I have a signature that is created by an external source and I need create a CMSSignedData instance for with this signature.
I thought perhaps, I could do this:
private ContentSigner contentSigner(AlgorithmIdentifier sigAlgId, byte[] signature) {
ContentSigner signer = new ContentSigner() {
@Override
public AlgorithmIdentifier getAlgorithmIdentifier() {
return sigAlgId;
}
@Override
public OutputStream getOutputStream() {
return new ByteArrayOutputStream();
}
@Override
public byte[] getSignature() {
return signature;
}
};
return signer;
}
but the signatures don't verify.
I could use, this libary, https://j4sign.sourceforge.io/index.html but I think there must be a way to do this using BC.
Any ideas?
Thanks
Update... I actually got this to work, but I'm not sure if my solution is correct or good. Perhaps, someone can confirm that this approach is ok and explain why it works?
These are the steps:
Signature creation (for test purposes)
byte[] data = "yeehaw".getBytes();
PrivateKey privateKey = (PrivateKey) getKeyStoreManager().getKey("mykey");
X509Certificate cert = (X509Certificate) getKeyStoreManager().getCertificate("mykey");
Signature sign = Signature.getInstance("SHA1withRSA", "BC");
sign.initSign(privateKey);
sign.update(data);
byte[] signature = sign.sign();
Create ConentSigner - using method above
AlgorithmIdentifier sigAlgId = (new DefaultSignatureAlgorithmIdentifierFinder()).find("SHA1withRSA");
ContentSigner contentSigner = contentSigner(sigAlgId, signature);
Create CMSSignedDataGenerator
CMSSignedDataGenerator cmsSignedDataGen = new CMSSignedDataGenerator();
cmsSignedDataGen.addCertificate(new X509CertificateHolder(cert.getEncoded()));
cmsSignedDataGen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()).setDirectSignature(true).build(contentSigner, cert));
Adding setDirectSignature(true) was what solved my problem (but I'm not sure this is correct)
Generate the CMSSignedData and verify - verify method is below
CMSSignedData sigData = cmsSignedDataGen.generate(msg);
verify((byte[]) sigData.getEncoded(), data);
The verify method
private void verify(byte[] data, byte[] signatureBytes) throws CMSException, CertificateException, OperatorCreationException {
CMSSignedData signedData = new CMSSignedData(new CMSProcessableByteArray(signatureBytes), data);
org.bouncycastle.util.Store store = signedData.getCertificates();
SignerInformationStore signers = signedData.getSignerInfos();
Collection c = signers.getSigners();
Iterator it = c.iterator();
while (it.hasNext()) {
SignerInformation signer = (SignerInformation)it.next();
Collection certCollection = store.getMatches(signer.getSID());
Iterator certIt = certCollection.iterator();
X509CertificateHolder certHolder = (X509CertificateHolder)certIt.next();
X509Certificate cert = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certHolder);
boolean verified = signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert));
System.out.println("Verified = " + verified);
}
}