Ошибка при проверке подписи: свойство SigningCertificate содержит один или несколько сертификатов, не входящих в путь сертификации.

Я использую xades4j и получаю это исключение при попытке проверить подпись:

xades4j.verification.SigningCertificateCertsNotInCertPathException: Verification failed for property 'SigningCertificate': SigningCertificate property contains one or more certificates that are not part of the certification path.

Вот мой код для подписи:

public File sign(final X509Certificate x509, final PrivateKey priv, final Element elemToSign, final Document doc, final String fileName, final com.softexpert.crypto.document.Document document, List<X509Certificate> chain) throws Exception {
    final KeyingDataProvider kp = new SEDirectKeyingDataProvider(x509, priv, chain);
    XadesSigningProfile profile = new XadesBesSigningProfile(kp);
    final SESignaturePropertiesProvider propProv = this.getPropertiesProvider(document);

    profile = profile.withSignaturePropertiesProvider(propProv);
    profile = profile.withAlgorithmsProvider(AlgorithmsProvider.class);
    profile = profile.withTimeStampTokenProvider(TimeStampTokenProvider.class);

    final SignerBES signer = (SignerBES) profile.newSigner();
    final IndividualDataObjsTimeStampProperty dataObjsTimeStamp = new IndividualDataObjsTimeStampProperty();
    final DataObjectDesc obj = new EnvelopedXmlObject(elemToSign.getFirstChild()).withDataObjectTimeStamp(dataObjsTimeStamp);

    AllDataObjsCommitmentTypeProperty commitment = null;
    if (document.isProofOfOrigin() != null && document.isProofOfOrigin()) {
        commitment = AllDataObjsCommitmentTypeProperty.proofOfOrigin();
    } else {
        commitment = AllDataObjsCommitmentTypeProperty.proofOfReceipt();
    }

    SignedDataObjects dataObjs = new SignedDataObjects(obj).withCommitmentType(commitment);
    dataObjs = dataObjs.withDataObjectsTimeStamp();

    signer.sign(dataObjs, elemToSign);
    return this.outputDocument(doc, fileName);
}

private SESignaturePropertiesProvider getPropertiesProvider(com.softexpert.crypto.document.Document document) {
    SESignaturePropertiesProvider propertiesProvider = new SESignaturePropertiesProvider();

    if (document.getRole() != null) {
        final SignerRoleProperty signerRole = new SignerRoleProperty().withClaimedRole(document.getRole());
        propertiesProvider.setSignerRole(signerRole);
    }
    final SigningTimeProperty signingTime = new SigningTimeProperty();
    propertiesProvider.setSigningTime(signingTime);

    if (document.getLocalityName() != null && document.getCountry() != null) {
        final SignatureProductionPlaceProperty signatureProductionPlaceProperty = new SignatureProductionPlaceProperty(document.getLocalityName(), document.getCountry());
        propertiesProvider.setSignatureProductionPlaceProperty(signatureProductionPlaceProperty);
    }

    return propertiesProvider;
}

private File outputDocument(final Document doc, String fileName) throws Exception {
    if (!fileName.endsWith(".dsg")) {
        fileName += ".dsg";
    }

    FileOutputStream out = null;
    File f = null;
    try {
        final TransformerFactory tf = TransformerFactory.newInstance();
        f = new File(fileName);
        if (!f.exists()) {
            new File(f.getParent()).mkdirs();
            f.createNewFile();
        }
        out = new FileOutputStream(f);
        tf.newTransformer().transform(new DOMSource(doc), new StreamResult(out));
    } finally {
        if(out != null) {
            try {
                out.close();
            } catch(IOException e) {}
        }
    }

    return f;
}

И вот мой код для проверки:

try {
    final org.w3c.dom.Document doc = this.getDomDocument();
    doc.getDocumentElement().normalize();

    // Find Signature element
    final NodeList nl = doc.getElementsByTagNameNS(javax.xml.crypto.dsig.XMLSignature.XMLNS, "Signature");
    final CertStore crls = ... // get CRLS
    final CertStore certs = ... // get intermediate certs                
    final KeyStore ks = ... // get KS from Windows-ROOT
    final PKIXCertificateValidationProvider cvp = new PKIXCertificateValidationProvider(ks, false, certs, crls);
    final XadesVerificationProfile p = new XadesVerificationProfile(cvp);
    p.withTimeStampTokenVerifier(SETimeStampTokenProvider.class);
    final Element signatureElemntNode = (Element) nl.item(0);
    final XadesVerifier verifier = p.newVerifier();
    XAdESVerificationResult verificationResult = verifier.verify(signatureElemntNode, null); // exception is thrown here
}

Я искал эту ошибку, но не смог найти ничего, что могло бы мне помочь. Как я могу решить эту ошибку?

Заранее спасибо.


person lucasdc    schedule 29.11.2016    source источник


Ответы (2)


Как указано в сообщениях об ошибках, ваше свойство SigningCertificate, вероятно, имеет сертификаты, которые не являются частью цепочки сертификатов. Это правило определено в спецификации XAdES.

Что касается операции подписания:

  • Какие сертификаты вы возвращаете из метода getSigningCertificateChain вашего пользовательского SEDirectKeyingDataProvider?
  • Каковы элементы сертификата в окончательном XML свойства SigningCertificate?

Все возвращенные сертификаты должны быть частью цепочки сертификата пения, но вам не нужно возвращать всю цепочку. Вы даже можете вернуть список, содержащий только сертификат подписи, если вы сделаете все промежуточные сертификаты доступными для проверки (что вы, похоже, и делаете). Если вы сделаете это, проверка свойства SigningCertificate должна пройти успешно.

person lgoncalves    schedule 29.11.2016
comment
getSigningCertificateChain возвращает: CN=AC CAIXA v2, OU=Autoridade Certificadora Raiz Brasileira v2, O=ICP-Brasil, C=BR CN=Autoridade Certificadora Raiz Brasileira v2, OU=Instituto Nacional de Tecnologia da Informacao - ITI, O=ICP-Brasil , C=BR CN=AC CAIXA PF v2, OU=Caixa Economica Federal, O=ICP-Brasil, C=BR CN=Autoridade Certificadora Raiz Brasileira v2, OU=Instituto Nacional de Tecnologia da Informacao - ITI, O=ICP-Brasil , C=BR И свойство SigningCertificate показывает эти 4 сертификата. Я не могу вставить его из-за ограничения символов - person lucasdc; 30.11.2016
comment
certs (переменная, содержащая промежуточные сертификаты) также показывает эти 4 сертификата. Я заметил, что C=BR CN=Autoridade Certificadora Raiz Brasileira v2, OU=Instituto Nacional de Tecnologia da Informacao - ITI, O=ICP-Brasil, C=BR появляется дважды. Вы думаете, что это может быть проблемой? - person lucasdc; 30.11.2016
comment
Похоже, у вас есть повторный сертификат. Из-за этого проверка не будет выполнена (см. здесь). Обратите внимание, что возвращать дубликаты на getSigningCertificateChain неправильно (и библиотека этого не проверяет). Возможно, проверка могла бы быть немного умнее, но я думаю, что иметь дубликаты не очень правильно. Надеюсь это поможет - person lgoncalves; 01.12.2016

Основываясь на ответе lgoncalve, я немного изменил свой код:

Подписание: вместо подписания всей цепочкой сертификатов я использовал только сертификат подписи, так что SEDirectKeyingDataProvider.getSigningCertificateChain() возвращает только сертификат подписи). При таком подходе мой xml теперь имеет только одно свойство <SigningCertificate>, а не всю цепочку.

Проверка. Используя подход, который я прокомментировал выше, у меня возникла проблема при проверке сертификатов: в моем xml в свойстве <ds:X509Certificate> упоминался только сертификат подписи, поэтому я не мог проверить всю цепочку. . Чтобы решить эту проблему, мне пришлось использовать этот код после вызова XAdESVerificationResult result = verifier.verify(signatureElemntNode, null);:

for(X509Certificate cert : chain) {         
   result.getSignature().addKeyInfo(cert);
}

Используя этот код, на каждый сертификат цепочки ссылается свойство <ds:X509Certificate>, и я могу получить всю цепочку, чтобы проверить, заслуживает ли она доверия или нет.

person lucasdc    schedule 05.12.2016