将证书添加到 CMS 签名数据

Adding Certificates to CMS Signed Data

我目前正在使用 java Bouncy Castle 库来创建 CMS 签名数据(或 PKCS7 签名数据)。然而,我似乎坚持添加证书(即使正确添加了证书签名者)。

我检查了 this question 关于正确签署数据的信息,但它没有响应我的 SCEP 服务器的需求。我使用的代码来自 EJBCA,但似乎没有向 PKCS7 签名数据添加证书。

当我用openssl cms工具解析签名数据时,我看到"certificates"字段是"EMPTY"。此外,当我尝试使用 openssl pkcs7 [...] -print_certs 打印证书时,我什么也没得到。

以下是我如何使用 Bouncy Castle 对我的数据进行签名(代码很多,但足以重现该问题):

CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
CMSTypedData msg;
List<X509Certificate> certList = new ArrayList<>();
// Make sure the certificate is not null
if (this.certificate != null) {
    certList.add((X509Certificate) this.certificate);
}

/**
* Create the signed CMS message to be contained inside the envelope
* this message does not contain any message, and no signerInfo
**/
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
Collection<JcaX509CertificateHolder> x509CertificateHolder = new ArrayList<>();
try {
    for (X509Certificate certificate : certList) {
        x509CertificateHolder.add(new JcaX509CertificateHolder(certificate));
    }
    CollectionStore<JcaX509CertificateHolder> store = new CollectionStore<>(x509CertificateHolder);
    gen.addCertificates(store);
} catch (Handle all exceptions) {}

上面这段代码通常应该添加证书。这是我从 EJBCA 拿来的。

这是我完成签名数据的方式:

CMSSignedDataGenerator gen1 = new CMSSignedDataGenerator();
// I add ALL of my attributes here
// Once they're added...
Certificate caCert = this.caCertificate;
try {
    String provider = BouncyCastleProvider.PROVIDER_NAME;
    ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithmName).
            setProvider(provider).
            build(signerKey);
    JcaDigestCalculatorProviderBuilder calculatorProviderBuilder = new JcaDigestCalculatorProviderBuilder().
            setProvider(provider);
    JcaSignerInfoGeneratorBuilder builder = new JcaSignerInfoGeneratorBuilder(calculatorProviderBuilder.build());
    builder.setSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(new AttributeTable(attributes)));
    gen1.addSignerInfoGenerator(builder.build(contentSigner, (X509Certificate) ca));
} catch (Handle all exceptions) {}

// Create the signed data
CMSSignedData sd = gen1.generate(msg, true);
byte[] results = sd.getEncoded();

字节数组结果是 DER 格式的 PKCS7 签名数据...但未添加证书。

我错过了什么吗?感谢您的帮助!

CMSSignedDataGenerator gen1 必须明确添加我不知道的证书。

可以简单地通过以下方式完成:

  • 将证书添加到 X509CertificatesList
  • List 转换为 JcaX509CertificateHolderCollection
  • 正在将此合集添加到 JcaX509CertificateHolderCollectionStore 中;
  • 正在添加商店 CMSSignedDataGenerator

代码示例:

 CMSSignedDataGenerator gen1 = new CMSSignedDataGenerator();
 List<X509Certificate> certificates = new ArrayList<>();

 // I chose to add the CA certificate
 certificates.add((X509Certificate) this.caCertificate);

 // In this case, this is a certificate that I need to add
 if (this.certificate != null)
     certificates.add((X509Certificate) this.certificate);

 // This is the recipient certificate
 if (this.recipientCert != null)
     certificates.add((X509Certificate) this.recipientCert);
 Collection<JcaX509CertificateHolder> x509CertificateHolder = new ArrayList<>();

 // Of course, we need to handle the exceptions...
 for (X509Certificate certificate : certificates) {
     x509CertificateHolder.add(new JcaX509CertificateHolder(certificate));
 }
 CollectionStore<JcaX509CertificateHolder> store = new CollectionStore<>(x509CertificateHolder);

// The final stage.
 gen1.addCertificates(store);

希望这对以后的任何人都有帮助。