/** проверить цепочку сертификатов для объекта Х509
*/
package kz.gamma;

import kz.gamma.tumarcsp.LibraryWrapper;
import kz.gamma.tumarcsp.ProfileParams;
import kz.gamma.tumarcsp.TumarCspFunctions;
import kz.gamma.tumarcsp.profile.ProfileInfo;
import kz.gamma.util.encoders.Base64;
import kz.gamma.x509.X509InstanceGetter;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class CertChainVerify {
    /**
     * Проверка цепочки сертификатов, состоящей из двух звеньев
     *
     * @param profile       Имя профайла или URL на ключ
     * @param keySpec       Тип ключа. Параметр игнорируется, если в параметре profile передан URL на ключ.
     *                      Возможные варианты:
     *                      <ul>
     *                      <li>LibraryWrapper.AT_KEYEXCHANGE (1) - ключ на шифрование;
     *                      <li>LibraryWrapper.AT_SIGNATURE (2) - ключ на подпись.
     *                      </ul>
     * @param caCertificate Сертификат ЦС
     * @return true, если все ок.
     */
    public boolean verifyCertificateChain(String profile, int keySpec, String caCertificate) throws NoSuchAlgorithmException, CertificateException, NoSuchProviderException, InvalidKeyException, SignatureException {
        return verifyCertificateChain(profile, keySpec, null, caCertificate);
    }

    /**
     * Проверка цепочки сертификатов, состоящей из трех звеньев
     *
     * @param profile          Имя профайла или URL на ключ
     * @param keySpec          Тип ключа. Параметр игнорируется, если в параметре profile передан URL на ключ.
     *                         Возможные варианты:
     *                         <ul>
     *                         <li>LibraryWrapper.AT_KEYEXCHANGE (1) - ключ на шифрование;
     *                         <li>LibraryWrapper.AT_SIGNATURE (2) - ключ на подпись.
     *                         </ul>
     * @param subCaCertificate Сертификат подчиненного ЦС
     * @param caCertificate    Сертификат ЦС
     * @return true, если все ок.
     */
    public boolean verifyCertificateChain(String profile, int keySpec, String subCaCertificate, String caCertificate) throws NoSuchProviderException, CertificateException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {
        Number handleProv = 0;
        Number handleKey = 0;
        try {
            // Извлечение сертификата пользователя
            boolean profileChecking = ProfileParams.isProfile(profile);
            if (profileChecking) {
                profile = ProfileParams.getProfileName(profile, true);
            }
            handleProv = TumarCspFunctions.cpAcquireContext(profile, LibraryWrapper.CRYPT_SILENT, LibraryWrapper.PV_TABLE);
            if (profileChecking) {
                handleKey = TumarCspFunctions.cpGetUserKey(handleProv, keySpec);
            } else {
                ProfileInfo profileInfo = new ProfileInfo();
                int profileKeySpec = profileInfo.getKeySpec(profile, LibraryWrapper.CRYPT_SILENT);
                handleKey = TumarCspFunctions.cpGetUserKey(handleProv, profileKeySpec);
            }
            byte[] userCertificateBytes = TumarCspFunctions.cpGetKeyParamData(handleProv, handleKey, LibraryWrapper.KP_CERTIFICATE, 0);
            X509InstanceGetter instanceGetter = new X509InstanceGetter();
            X509Certificate x509userCertificate = instanceGetter.getX509CertificateInstance(userCertificateBytes);
            X509Certificate x509caCert = instanceGetter.getX509CertificateInstance(Base64.decode(caCertificate));
            if (subCaCertificate == null) {
                x509userCertificate.verify(x509caCert.getPublicKey());
                x509caCert.verify(x509caCert.getPublicKey());
            } else {
                X509Certificate x509subCaCert = instanceGetter.getX509CertificateInstance(Base64.decode(subCaCertificate));
                x509userCertificate.verify(x509subCaCert.getPublicKey());
                x509subCaCert.verify(x509caCert.getPublicKey());
                x509caCert.verify(x509caCert.getPublicKey());
            }
            return true;
        } finally {
            if (handleKey.longValue() != 0) {
                TumarCspFunctions.cpDestroyKey(handleProv, handleKey);
            }
            if (handleProv.longValue() != 0) {
                TumarCspFunctions.cpReleaseContext(handleProv, LibraryWrapper.ZERO);
            }
        }
    }
}
