【问题标题】:Bouncy Castle: Signed Certificate with an existing CABouncy Castle:与现有 CA 签署的证书
【发布时间】:2018-08-08 15:24:08
【问题描述】:

我正在尝试创建一个证书 (A),该证书 (A) 为存储在 p12 密钥库中的其他证书 (B) 签名。此存储的证书 (B) 已添加到我的本地计算机的受信任证书存储中。

证书A用于使用bouncy castle 1.52库对pdf文档进行签名,但我在签名文档中获得的数字签名无效。

如果有人可以帮助我,我将解释完成的步骤。

首先,我从 p12 密钥库(B)创建一个 CSR:

    private static PKCS10CertificationRequest generateCSR() {
    PKCS10CertificationRequest csr = null;
    try {
        initCACert();
        PKCS10CertificationRequestBuilder p10Builder = new JcaPKCS10CertificationRequestBuilder(
                new X500Principal("CN=Requested Test Certificate"), CAcert.getPublicKey());
        JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder("SHA256withRSA");
        ContentSigner signer = csBuilder.build(CApk);
        csr = p10Builder.build(signer);
    } catch (Exception e) {
        log.error(e);
    }
    return csr;
}

然后,使用此 CSR 生成证书 (A)。

    private static Certificate signCSR() throws Exception { 
    PKCS10CertificationRequest csr = generateCSR();

    AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA256withRSA");
    AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);

    X500Name issuer = X500Name.getInstance(CAcert.getSubjectX500Principal().getEncoded());

    BigInteger serial = new BigInteger(32, new SecureRandom());
    Calendar c = Calendar.getInstance();
    c.add(Calendar.SECOND, -1);
    Date from = c.getTime();
    c.add(Calendar.YEAR, 5);
    Date to = c.getTime();

    X509v1CertificateBuilder certBuilder = new X509v1CertificateBuilder(issuer, serial, from, to, csr.getSubject(),
            csr.getSubjectPublicKeyInfo());

    ContentSigner signer = new BcRSAContentSignerBuilder(sigAlgId, digAlgId)
            .build(PrivateKeyFactory.createKey(CApk.getEncoded()));
    X509CertificateHolder holder = certBuilder.build(signer);

    CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
    InputStream in = new ByteArrayInputStream(holder.getEncoded());
    Certificate cert = certFactory.generateCertificate(in);

    return cert;
}

最后,我使用这个生成的证书 (A) 来签署我的 pdf。

        Certificate cert = signCSR();

        SignerInfoGeneratorBuilder signerInfoBuilder = new SignerInfoGeneratorBuilder(
                    new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()
                    );
        signerInfoBuilder.setSignedAttributeGenerator( signedAttributeGenerator );

        JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder( "SHA1WITHRSA" );
        contentSignerBuilder.setProvider("BC");


        X509CertificateHolder certificateHolder = new X509CertificateHolder( cert.getEncoded( ) );

        generator.addSignerInfoGenerator(
                signerInfoBuilder.build( contentSignerBuilder.build( CApk ),
                        certificateHolder ) 
                );

        ArrayList<X509CertificateHolder> signingChainHolder = new ArrayList<X509CertificateHolder>( );
        certificateHolder = new X509CertificateHolder( cert.getEncoded() );
        certificateHolder = new X509CertificateHolder( CAcert.getEncoded() );

        signingChainHolder.add( certificateHolder );

        Store certs = new JcaCertStore( signingChainHolder );
        generator.addCertificates( certs );

        CMSTypedData content = new CMSProcessableByteArray(datos);

        CMSSignedData signedData = generator.generate( content, true );
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        new DEROutputStream(baos).writeObject(signedData.toASN1Structure());
        result = baos.toByteArray();

所有过程显然都执行正确,但是当我打开pdf时签名无效:

编辑:我已导出生成的证书。这是得到的结果。

我将不胜感激任何可以帮助我解决此问题的评论或信息。

提前致谢。

【问题讨论】:

  • 将签名者证书添加到您正在查看已签名文档的 PC 中的受信任存储区。
  • 是的,我使用 Windows 的加密 shell 实用程序将 P12 添加到受信任的商店中

标签: java bouncycastle signature ca


【解决方案1】:
    generator.addSignerInfoGenerator(
            signerInfoBuilder.build( contentSignerBuilder.build( CApk ),
                    certificateHolder ) 
            );

如果我没看错,您就是在使用 CA 的私钥对数据进行签名。应该是证书的。所以私钥和公钥不匹配,因此签名验证检查失败。

【讨论】:

  • SignerInfoGeneratorBuilder 的方法构建需要一个私钥作为参数
  • @MarMillán 是的,它必须是您用于签名的证书的私钥。
【解决方案2】:

我发现了问题:我以与应有的相反顺序构建证书链。

我有这个订单:

 certificateHolder = new X509CertificateHolder( cert.getEncoded() );
 certificateHolder = new X509CertificateHolder( CAcert.getEncoded() );

正确的顺序是这样的:

certificateHolder = new X509CertificateHolder( CAcert.getEncoded() );
certificateHolder = new X509CertificateHolder( cert.getEncoded() );

我希望有人能发现这些信息有用!

【讨论】:

  • 每个块中的第一个语句是多余的,因为它被以下语句覆盖。如果它有效,那只是因为certificateHolder 应该是new X509CertificateHolder( cert.getEncoded() )。
猜你喜欢
  • 2015-10-15
  • 2018-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-03
  • 2018-03-20
  • 1970-01-01
  • 2017-08-14
相关资源
最近更新 更多