簡體   English   中英

iText7 pdf 使用 GlobalSign DSS AATL 證書簽名顯示 Adobe Reader 中的信任鏈損壞

[英]iText7 pdf signing with GlobalSign DSS AATL certificate shows broken trustchain in Adobe Reader

我正在使用 iText7 和 GlobalSign DSS 對 PDF 進行數字簽名。 我在必要的 iText 類中實現了 GlobalSing DSS API 調用。 我得到了正確的服務器響應,並且能夠使用所有需要的 arguments 調用 pdfSigner.signDetached() 方法。 使用 pdfSigner 簽名也成功了,我得到了一個簽名的 PDF,乍一看還不錯。 但是,當我在 Adobe Reader 中打開簽名的 pdf 時,它告訴我簽名證書的信任鏈已損壞,並且無法將其追溯到 CA 根。 這很奇怪,因為它是一個 AATL 證書,並且 Adobe Reader 的 AATL 列表是最新的。
我不明白為什么會這樣。

這就是我所做的:

  • 為身份調用 DSS:返回 id 字符串、簽名證書和 ocsp 響應

  • 為信任鏈調用 DSS:返回用於
    簽署簽名證書,直到 GlobalSign 根,連同
    他們的 oscp 響應(除了根)

  • 我創建了一個包含簽名的 X509Certificate 對象數組
    證書、2 個中間證書和 GlobalSign 根證書(按此順序)

  • 我實現了一個 IOcspClient,它使用來自 DSS 調用的 ocsp 響應來獲取身份

  • 我實現了一個調用 DSS API /timestamp/{digest} 的 ITsaClient

  • 最后我執行: pdfSigner.signDetached(externalDigest, externalSignature, chain.toArray(new X509Certificate[]{}), null, dssOcspClient, dssTSAClient, 0, PdfSigner.CryptoStandard.CMS);

  • 其中 externalSignature(IExternalSignature 的實現)將調用 DSS 身份/{id}/sign/{digest} API

在調試 signDetached 方法並深入 pdfSigner 代碼時,我清楚地看到所有證書都以正確的順序在鏈中。 我看到它們正在 PdfPKCS7 class 中處理(但是我不知道/不了解那里到底發生了什么)。 我看到正在簽名,沒有拋出異常,最后生成的 PDF 看起來像是正確簽名的。 Adobe 說的不是。

我在這里想念什么?

來自 de DSS API 的信任鏈響應不僅返回簽名證書信任鏈中的證書,還返回簽名證書和 GlobalSign 根之間的兩個中間體的 ocsp 響應。 這些從未使用過。 事實上,我也不知道如何處理它們。
這些可能是 AdobeReader 重建到 GlobalSign 根的信任鏈所缺少的部分嗎?
如果是這樣:我如何將它們放入 PDF 中?
如果不是:那我做錯了什么破壞了信任鏈?

這些問題的答案將節省我的一天:-)

這是 PDF 的鏈接,它將顯示問題:
測試用 DSS 簽名的 pdf
(接受答案后,我根據客戶的要求刪除了示例 pdf)

下面是部分代碼。

收集 DSS 信息並調用 signDetached 方法的中心部分

    private InputStream sign(byte[] unsignedDocument) throws IOException, DssServiceException, GeneralSecurityException {

    SigningIdentity signingIdentity = signingIdentityService.getValidSigningIdentity();
    DssOcspClient dssOcspClient = new DssOcspClient(signingIdentity);

    TrustChainResponse trustChainResponse = digitalSigningService.getTrustChain();
    List<X509Certificate> chain = new ArrayList<>();
    chain.add(signingIdentity.getCertificate());
    chain.addAll(trustChainResponse.getTrustChain());

    IExternalDigest externalDigest = new ProviderDigest(BC_SECURITY_PROVIDER);
    IExternalSignature externalSignature = new DssExternalSignature(signingIdentity.getIdentity(), digitalSigningService);

    ByteArrayOutputStream signedPdfOut = new ByteArrayOutputStream();
    PdfSigner pdfSigner = createPdfSigner(new ByteArrayInputStream(unsignedDocument), signedPdfOut);
    pdfSigner.signDetached(externalDigest, externalSignature, chain.toArray(new X509Certificate[]{}), null, dssOcspClient, dssTSAClient, 0, PdfSigner.CryptoStandard.CADES);

    return new ByteArrayInputStream(signedPdfOut.toByteArray());
}


IExternalSignature 實現

    @Override
public byte[] sign(byte[] message) throws GeneralSecurityException {
    MessageDigest messageDigest = new BouncyCastleDigest().getMessageDigest(DEFAULT_DIGEST_ALGORITHM);
    byte[] documentHash = messageDigest.digest(message);
    try {
        return digitalSigningService.getSignature(signingIdentity, documentHash);
    }
    catch (DssServiceException e) {
        LOGGER.error("error getting signature", e);
        throw  new GeneralSecurityException(e);
    }
}


IOcspClient 實現

    @Override
public byte[] getEncoded(X509Certificate checkCert, X509Certificate issuerCert, String url) {
    try {
        if(Objects.equals(signingIdentity.getCertificate(), checkCert)) {
            OCSPResp response = new OCSPResp(signingIdentity.getOcsp());
            BasicOCSPResp basicResponse = (BasicOCSPResp)response.getResponseObject();
            return basicResponse.getEncoded();
        }
    }
    catch (CertificateException | IOException | OCSPException e) {
        LOGGER.warn("OCSP validatie gefaald!", e.getMessage());
    }
    return null;
}


ITSAClient 實施

    @Override
public byte[] getTimeStampToken(byte[] imprint) throws Exception {

    String digestAlgorithmOID = DigestAlgorithms.getAllowedDigest(DEFAULT_DIGEST_ALGORITHM);
    ASN1ObjectIdentifier digestAlgOID = new ASN1ObjectIdentifier(digestAlgorithmOID);
    AlgorithmIdentifier algID = new AlgorithmIdentifier(digestAlgOID, DERNull.INSTANCE);
    MessageImprint messageImprint = new MessageImprint(algID, imprint);

    byte[] hash = messageImprint.getHashedMessage();
    return digitalSigningService.getTimeStamp(hash);
}

簡而言之

您的簽名者證書無效。

詳細地

您的簽名者證書及其證書鏈(根據頒發者/主題匹配)嵌入簽名中,特別是您的帶有主題的證書

cn=Homologatie Voertuigen, ou=Departement Mobiliteit en Openbare Werken, ou=Vlaams Huis voor de Verkeersveiligheid, o=Ministeries van de Vlaamse Gemeenschap, l=Brussel, st=Brussel, c=BE

及其聲稱的發行人

cn=針對 AATL 的 GlobalSign CA 5,o=GlobalSign nv-sa,c=BE

因此,可以檢查您的證書所使用的簽名。 在這樣做的同時,您會看到簽名者證書的TBSCertificate部分(待簽名部分)具有此摘要值

C8751FDC7F679CB627F61028ACDD0D09613AFA782412ACFC7E189EA5DA625831

但簽名實際上簽署了這個摘要值

16090737B41E6E0466E7EB7A7EBD79F5494E438C11D0FB408BCA663A5923AD03

因此,您的簽名者證書未正確簽名。

這是什么意思

在你問的評論中

但我對它的確切含義有點困惑。 我們真的在簽名過程中做錯了什么,將錯誤的文檔 hash 發送到簽名服務器嗎? 還是您的意思是 GlobalSign 頒發的用於簽署該文檔 hash 的服務器端簽名證書有問題?

你在簽約的時候沒有做錯什么,至少我不這么認為。 損壞的簽名不是簽署文檔的簽名,而是您的 CA 簽署您的證書的簽名。

我基本上看到了三個可能的原因:

  • 證書簽名只是被破壞了,無論如何都與您的證書不匹配。

    這會讓我感到驚訝。

  • 證書簽名不是針對您要簽名的證書部分的 DER 編碼形式計算的,而是針對其他形式的。

    這並非聞所未聞,如果您的證書最初不是 DER 形式,但證書簽名過程假定它是,則可能已經簽署了非 DER 形式(即使根據規范必須簽署 DER 形式)。 如果某個驗證器隨后檢查了簽名,該簽名也不能確保 DER 形式,而是按原樣獲取 TBSCertificate,那么該驗證器甚至會表明該簽名是有效的。

    在嵌入在 PDF 簽名中的證書中,待簽名部分是 DER 編碼的,但這可能在初始證書生成后的某個步驟被強制執行。

  • 創建后,您的證書可能發生了一些微小的變化。

    這也是可能的。

您可以嘗試以盡可能原始的形式從您的 CA 接收您的證書副本,並與嵌入在您簽名中的證書進行比較。 如果您發現差異,那么分析差異最有可能將進一步闡明問題的原因。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM