The 28 day problem
The past five weeks have had some interesting learning code wise 🙂
Normally, smime messages are signed with the public key signature embedded in the message. It allows quick and simple verification of who has sent the message and whether that signature is valid against a root certificate. The root certificate is typically held in a certificate store, an encoded file indexed by certain attributes of the certificate.
This practice is commonly found throughout the internet. In fact the code I inherited on the 1st April which was tested and working, was doing exactly that same, cut and pasted, formula. The author may have been the one who initially posted – that has been lost in time. A reasonably clear example is given here: Explore a bouncy castle store object.
If the certificates are not held in a file based certstore and the public keys are not held in the sent message, these techniques fail. The case I am displaying here is against an Active Directory certificate service.
Instead, you end up with this: extract the signature from the message into a SignatureInformationStore, for each signature get the information regarding the certificate used, use that to query the active directory certificate store and then verify the signature against that relevant certificate. The certificates may be proven against the associated root certificates and any certificate revocation lists.
LDAPCertStore certStore = new LDAPCertStore (new LDAPCertStoreParameters (host, port));
SignerInformationStore signers = smimeSignedMessage.getSignerInfos();
Collection c = signers.getSigners();
Iterator it = c.iterator();
//in our case there is only one signature
SignerInformation signer = (SignerInformation)it.next();
X509CertSelector xcs = new LDAPCertSelector();
Collection <X509Certificates> certCollection = certStore.engineGetCertificates (xcs);
//as there is only one cert!
Iterator thisCert = certCollection.iterator();
boolean verified = (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(“BC”).build(thisCert.next())));
At this point you can then verify the certificates using standard methods.
The big thing here is the use of the X509CertSelector. You cannot use signer.getSID() as the LDAPCertStore is not an extension of CertStore which has the ability to select the certificate based on the getSID values from the signature.
Instead you need to understand what is available from the signature that you can use to select the unique certificate.
Here endeth the lesson.
Actually… This does not have any error handling and you are going to need that for the cases where it doesn’t work.