I am currently using the java Bouncy Castle libraries in order to create CMS signed data (or PKCS7 signed data). I seem however to be stuck with adding certificates (even though the certificate signer is properly added).
I checked out this question about properly signing data, but it didn't respond the needs of my SCEP server. The code I used was from EJBCA but doesn't seem to add certificates to the PKCS7 signed data.
When I parse the signed data with the openssl cms
tool, I see that the "certificates" field is "EMPTY". Additionally, when I try to the print the certs with openssl pkcs7 [...] -print_certs
, I get nothing.
Here is how I sign my data with Bouncy Castle (it's a lot code but enough to reproduce the issue):
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) {}
This snippet of code above should normally add certificates. I took this from EJBCA.
Here is how I complete the signed data:
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();
The bytes array results is the DER formatted PKCS7 signed data... but no certificate is added.
Am I missing something? Thank you for your help!
The CMSSignedDataGenerator gen1
has to explicitly add the certificate, which I wasn't aware of.
It can simply be done by:
List
of X509Certificates
;List
into a Collection
of JcaX509CertificateHolder
;CollectionStore
of JcaX509CertificateHolder
;CMSSignedDataGenerator
.Code sample:
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);
Hope this helps anyone in the future.