I'm attempting to decrypt an S/MIME email (sent originally via Outlook), and to do that, I'm using the bouncycastle API. I'm running into a snag, though.
I have, in the Windows certificate store, the certificate for the recipient. I had previously used it to send a signed and encrypted email to the other party, and they in turn used it to send me an encrypted reply. I then exported the certificate (with private key) as a .pfx file, and I loaded this pfx file into a Java KeyStore. It doesn't work, however, and I suspect that's because the subject key identifiers don't match.
Here's the code I'm using to get the subject key id from the KeyStore:
KeyStore ks = KeyStore.getInstance("PKCS12");
char[] pw = "password".toCharArray();
ks.load(new FileInputStream("d:\\cert_priv_key.pfx"), pw);
Enumeration en = ks.aliases();
while( en.hasMoreElements() )
{
String alias = (String)en.nextElement();
System.out.println(alias);
if( ks.isKeyEntry(alias) )
{
Certificate[] chain = ks.getCertificateChain(alias);
X509Certificate cert = (X509Certificate)chain[0];
byte[] id = cert.getExtensionValue("2.5.29.14");
System.out.println(" " + toHex(id));
}
}
This prints out the following key identifier:
04 16 04 14 88 ed bb 7c 64 7b 41 63 48 0a 24 40 2b 3c d0 78 72 3c 30 b3
When I check the Windows certificate store, however, the key identifier is different:
88 ed bb 7c 64 7b 41 63 48 0a 24 40 2b 3c d0 78 72 3c 30 b3
The KeyStore returns an extra 4 bytes in the front (the subject key identifier should be the 160-bit SHA1 hash of the key, and therefore 20 bytes long, correct?).
Even more confusing is the fact that when I parse the S/MIME email using the bouncycastle API, and go through the recipients (SMIMEEnveloped.getRecipientInfos().getRecipients()
), the only recipient returned (there should be only one) has this subject key identifier:
04 14 88 ed bb 7c 64 7b 41 63 48 0a 24 40 2b 3c d0 78 72 3c 30 b3
... it has only two extra bytes, not four, and I assume this is why I'm unable to decrypt the email with the certificate.
Why do none of these subject key identifiers match up? What am I doing wrong?
Is the S/MIME message created by Outlook 2010?
if so see http://bouncy-castle.1462172.n4.nabble.com/Re-ReadEncryptedMail-sample-and-SubjectKeyIdentifier-instead-of-IssuerSerial-Outlook-2010-Hack-td3042968.html and https://bugzilla.mozilla.org/show_bug.cgi?id=559243 for more info
Martijn Brinkers
The accepted answer from GregS helped me alot.
The code that ended up working for me is:
All these answers are consistent if you understand all the specs, but of course that means they are confusing if you don't. The first place to look is in RFC 5280, section 4.2.1.2. In this case method (1) is used. Next, look at section A.2 at the definition of KeyIdentifier. It is defined as an OCTET STRING. Now look at how an ASN.1 OCTET STRING should be encoded. It should start out with hex 04 followed by the length in bytes (20 bytes, or 14 hex) followed by the actual octet string (the SHA1 hash). So the contents of the extension should be
Finally, look at the ASN.1 definition of Extension. It says that the extension value must be encoded as an OCTET STRING. In the case of this particular extension, the net effect is that is get encoded twice in a row as an OCTET STRING. At this level the OCTET STRING is the previous OCTET STRING which includes the two header bytes
04 14
, so the length is hex 16, and the encoding isThis is the value returned by the X509Extension.getExtensionValue() method. Now the interesting part of the key id is just the SHA1 hash which start with
88
, so this is what the Windows utility displays. Obviously the bouncycastle method you are using displays the extension without doing additional decoding.