AxelRUS
9/19/2017 - 12:10 PM

Java - проверка ЭЦП

Java - проверка ЭЦП

Пример проверки подписи

Для проверки ЭЦП необходимо сначало ее получить из XML файла или из файла (CMS).

Получение подписи из XML и из файла (отсоединенная, CMS)

Получение из CMS файла:

CMSSignedData cmsSignedData = new CMSSignedData(Base64.decode(readFile(signaturePath)));
CMSProcessableByteArray signers = new CMSProcessableByteArray(readFile(documentPath).getBytes("UTF-8"));
cmsSignedData = new CMSSignedData(signers, cmsSignedData.getEncoded());

SignerInformationStore signerInformationStore = cmsSignedData.getSignerInfos();
CertStore clientCerts = cmsSignedData.getCertificatesAndCRLs("Collection", mProviderName);

Iterator it = signers.getSigners().iterator();

boolean overAllResult = true;

while (it.hasNext()) {
    SignerInformation signer = (SignerInformation) it.next();
    X509CertSelector signerConstraints = signer.getSID();

    Collection certCollection = clientCerts.getCertificates(signerConstraints);
    Iterator certIt = certCollection.iterator();
    int indexOfSigner = 0;

    while (certIt.hasNext()) {
        indexOfSigner++;
        X509Certificate cert = (X509Certificate) certIt.next();
        
        /* other code */
        
    }
}

Получение из XML файла:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder documentBuilder = dbf.newDocumentBuilder();
Document doc = documentBuilder.parse(new ByteArrayInputStream(xmlString.getBytes("UTF-8")));

Element sigElement = null;
Element rootEl = (Element) doc.getFirstChild();

NodeList list = rootEl.getElementsByTagName("ds:Signature");
int length = list.getLength();

for (int i = 0; i < length; i++) {
    Node sigNode = list.item(length - 1);
    sigElement = (Element) sigNode;
    
    if (sigElement == null) {
        System.out.print(VERIFICATION_FAILED);
    }
    
    XMLSignature signature = new XMLSignature(sigElement, "");
    KeyInfo ki = signature.getKeyInfo();
    X509Certificate cert = ki.getX509Certificate();

    /* other code */

}

Есть три способа проверки валидности сертификата:

  1. статический заранее полученный CRL. В этом случае при инициализации CertPathBuilder и CertPathValidator надо поместить crl в list
  2. CertPathBuilder и CertPathValidator сами берут crl с crldp корневого сертификата. Необходимо использовать свойство enableCRLDP. crl при этом хранить не нужно.
  3. через OCSP протокол

Проверки

CertificateFactory cf = CertificateFactory.getInstance("X.509");
List<X509Certificate> certList = new ArrayList<X509Certificate>();
certList.add(cert);
CertPath cp = cf.generateCertPath(certList);
CertPathValidator certPathValidator = CertPathValidator.getInstance("PKIX");

PKIXParameters params = new PKIXParameters(getTrustedCertsFromResources(rootCAList));
List<X509CRL> crlList = getCrlFromFile(mCrlFiles);

for (X509CRL crl : crlList) {
    params.addCertStore(CertStore.getInstance("Collection",
            new CollectionCertStoreParameters(Collections.singletonList(crl))));
}

PKIXCertPathValidatorResult validationResult = (PKIXCertPathValidatorResult) certPathValidator.validate(cp, params);
result = signature.checkSignatureValue(cert);

Короткое описание алгоритма:

  1. Получаем инстант CertificateFactory
  2. Создаем `List`` и добавляем туда наш сертификат
  3. Получаем CertPath у CertificateFactory используя метод generateCertPath с параметров из п. 2
  4. Получаем инстанс CertPathValidator
  5. Создаем PKIXParameters на основе корневых сертификатов (корневые - самодподписанные)
  6. Создаем список из файлов списков отзыва crl
  7. Добавляем CertStore к PKIXParameters из п.5 с crl файлами
  8. Вызываем у CertPathValidator из п.4 метод validate с CertPath из п.3 и PKIXParameters из п.5