Java 结合验证PKCS#7签名所需的所有任务

Java 结合验证PKCS#7签名所需的所有任务,java,cryptography,digital-signature,bouncycastle,Java,Cryptography,Digital Signature,Bouncycastle,我已经为这个问题绞尽脑汁20个小时了,我可能错过了一些简单的事情。然而,我已经到了需要帮助的地步。我已经阅读了几十篇关于如何处理问题不同部分的解释,但我不知道如何将它们结合在一起 我有一个DER编码的PKCS#7数字签名。签名符合RFC 3852(加密消息语法)。对于我的项目,我需要一步一步地完成验证签名所需的每一个步骤,并能够判断验证失败的步骤。我正在Java中使用BouncyCastle 据我所知,验证数字签名需要六个基本步骤 验证根证书是否为受信任的证书 验证从根证书到签名证书的证书链 验

我已经为这个问题绞尽脑汁20个小时了,我可能错过了一些简单的事情。然而,我已经到了需要帮助的地步。我已经阅读了几十篇关于如何处理问题不同部分的解释,但我不知道如何将它们结合在一起

我有一个DER编码的PKCS#7数字签名。签名符合RFC 3852(加密消息语法)。对于我的项目,我需要一步一步地完成验证签名所需的每一个步骤,并能够判断验证失败的步骤。我正在Java中使用BouncyCastle

据我所知,验证数字签名需要六个基本步骤

  • 验证根证书是否为受信任的证书
  • 验证从根证书到签名证书的证书链
  • 验证签名者的姓名是否为您期望的姓名
  • 验证证书是否未过期
  • 验证证书是否未出现在CRL上(为简单起见,假设CRL已在本地下载)
  • 验证签名中的摘要是否与文档摘要匹配
  • 编辑:请求在列表中添加OSCP检查的几个注释

    在BouncyCastle测试代码中,我能够找到以下示例。它似乎完成了2/6,但不清楚它是否完成了任何任务。如果有人能为我指出其余任务的正确方向,我将不胜感激

    CMSSignedData s = ...
    byte[] contentDigest = ...
    
    Store certStore = s.getCertificates();
    Store crlStore = s.getCRLs();
    SignerInformationStore  signers = s.getSignerInfos();
    
    Collection c = signers.getSigners();
    Iterator it = c.iterator();
    
    while (it.hasNext())
    {
        SignerInformation   signer = (SignerInformation)it.next();
        Collection certCollection = certStore.getMatches(signer.getSID());
    
        Iterator certIt = certCollection.iterator();
        X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
    
        assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
    
        if (contentDigest != null)
        {
            assertTrue(MessageDigest.isEqual(contentDigest, signer.getContentDigest()));
        }
    }
    
    Collection certColl = certStore.getMatches(null);
    Collection crlColl = crlStore.getMatches(null);
    
    assertEquals(certColl.size(), s.getCertificates().getMatches(null).size());
    assertEquals(crlColl.size(), s.getCRLs().getMatches(null).size());
    

    CMS签名数据验证中最复杂的部分是X.509验证部分。对于签名数据中的每个签名者,步骤如下:

    1。查找签名者证书

    SignerInformation signerInfo = (SignerInformation)it.next();
    Collection certCollection = certStore.getMatches(signerInfo.getSID());
    Iterator certIt = certCollection.iterator();
    X509CertificateHolder signerCertificateHolder = (X509CertificateHolder)certIt.next();
    
    我假设这里只有一个匹配的证书

    2。查找从签名者证书到受信任根证书的证书链

    SignerInformation signerInfo = (SignerInformation)it.next();
    Collection certCollection = certStore.getMatches(signerInfo.getSID());
    Iterator certIt = certCollection.iterator();
    X509CertificateHolder signerCertificateHolder = (X509CertificateHolder)certIt.next();
    
    在这里,您要检查
    存储中的证书
    ,以查找证书链。使用主题DN/颁发者DN和主题密钥标识符/权限密钥标识符匹配项来构建该链

    3。验证链

    这一步是对链中的每个证书进行递归验证。对于每个证书,从根证书正下方的证书开始,您需要检查:

  • 具有颁发者公钥的证书签名
  • 证书的有效日期
  • 证书的吊销状态
  • 希望在步骤2和步骤3中,您可以使用内置的PKIX证书路径生成器和验证机制:

    KeyStore trustAnchors = getTrustAnchors();
    X509CertSelector target = new X509CertSelector();
    target.setCertificate(signerCertificate);
    PKIXBuilderParameters params = new PKIXBuilderParameters(anchors, target);
    CertStoreParameters additionalCerts = new CollectionCertStoreParameters(allOtherCerts)
    params.addCertStore(CertStore.getInstance("Collection", additionalCerts));
    CertStoreParameters revocationObjects = new CollectionCertStoreParameters(allCRLs);
    params.addCertStore(CertStore.getInstance("Collection", revocationObjects));
    CertPathBuilder builder = CertPathBuilder.getInstance("PKIX");
    PKIXCertPathBuilderResult r = (PKIXCertPathBuilderResult) builder.build(params);
    /* if the build method returns without exception, the certificate chain is valid */
    
    为了可读性,我省略了对象在
    java(x).crypto
    和Bouncycastle类型之间的转换

    4。使用公钥验证SignerInfo签名

    JcaSimpleSignerInfoVerifierBuilder builder = new JcaSimpleSignerInfoVerifierBuilder();
    SignerInformationVerifier verifier = builder.build(signerCertificateHolder);
    assertTrue(signerInfo.verify(verifier));
    
    5。验证文档摘要是否与签名摘要匹配

    byte[] contentDigest = computeDigest(originalDoc, signerInfo.getDigestAlgOID());
    assertArrayEquals(contentDigest, signer.getContentDigest());
    

    将OCSP检查添加到列表中。如果要彻底检查,请将crl和OCSP响应签名的检查也添加到列表中。