I've recently been put in charge of mocking up an Apple product (iPhone Configuration Utility) in Java. One of the sections I've been a bit stuck on is a part about Exchange ActiveSync. In there, it allows you to select a certificate from your Keychain to use as credentials for your EAS account. After some research, I found that it's actually creating a PKCS12 keystore, inserting the private key of the certificate I selected, and encoding that into XML. So far not a big deal. If I create a .p12 file with Keychain Access it uploads without a problem. But I run into a problem when I try to bring that over to Java.
Say I export one of those certs that I had used earlier with the .p12 file as a .cer file (this is what we are expecting to get in the environment). Now when I upload it into Java I get a Certificate object as follows...
KeyStore ks = java.security.KeyStore.getInstance("PKCS12");
ks.load(null, "somePassword".toCharArray());
CertificateFactory cf = CertificateFactory.getInstance("X.509", new BouncyCastleProvider());
java.security.cert.Certificate userCert = cf.generateCertificate(new FileInputStream("/Users/me/Desktop/RecentlyExportedCert.cer"));
But when I try...
ks.setCertificateEntry("SomeAlias", userCert);
I get the exception...
java.security.KeyStoreException: TrustedCertEntry not supported
So from certs I move onto keys. But with those Certificates (I got the CA Cert as well), I'm only able to access the public key, not the private. And if I attempt to add the public key like so...
java.security.cert.Certificate[] chain = {CACert};
ks.setKeyEntry("SomeAlias", userCert.getPublicKey().getEncoded(), chain);
I get...
java.security.KeyStoreException: Private key is not stored as PKCS#8 EncryptedPrivateKeyInfo: java.io.IOException: DerValue.getOctetString, not an Octet String: 3
So now I'm here. Does anyone have any idea how to get a private key from a .cer file into a PKCS12 keystore in Java? Am I even on the right track?
Thanks in advance!
A keystore contains personal certificates, plus the corresponding private keys that are used to identify the owner of the certificate. For TLS, a personal certificate represents the identity of a TLS endpoint.
The PKCS#12 format is intended for storing a private key associated with a certificate chain, and both are required (although you might not need the whole chain).
Although the PKCS12
keystore type does a good job for mapping this format to a Java KeyStore
, not everything is supported for this reason.
What you're trying to do in your first attempt is storing a certificate on its own, which won't work.
What you're trying to do in your second attempt (ks.setKeyEntry("SomeAlias", userCert.getPublicKey().getEncoded(), chain)
) is to for a public key in place of what should be a private key (see KeyStore#setKeyEntry
).
.cer
file tend to be just for certificates not private keys (although of course, the extension is ultimately just an indication). If you export your .cer
file from Keychain Access.app, you won't get the private key with it (that's what the .p12
export format is for).
EDIT about KeychainStore:
If the reason you're trying to do this conversion is ultimately to access private keys and certificates that are already in the keychain you could load them from the KeychainStore
directly:
KeyStore ks = KeyStore.getInstance("KeychainStore", "Apple");
ks.load(null, "-".toCharArray());
A couple of notes for this:
"-".toCharArray()
), as access will be prompted by the OS's security service (like it would in other applications).http://www.docjar.com/html/api/org/bouncycastle/jce/examples/PKCS12Example.java.html
This is how to add a certificate with a associating private key to a PKCS12 keystore. When you are using client authentication, the keystore needs to contain also the private key, in that case you use KeyStore.getInstance("PKCS12").
When youre not using client authentication but only server authentication(and private key will not be added to keystore, since it belongs to the server), its better to use KeyStore.getInstance("JKS"), than you can add multiple certificates with an alias to that one keystore.
When you are using PKCS12, as far as I know, you can only add 1 certificate(you have to add the whole certificate chain) associated with the private key, you want to use for that certificate.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With