JKS (Java Keystore) is the default implementation for certificates and key management in Java applications like WebSphere and Tomcat. A common problem faced is the extraction of private key from JKS for use in an Apache web server which makes use of base64-encoded DER (aka PEM) standard or in the case of IBM HTTP Server, KDB.
If you use openssl to create your CSR then you wouldn't have a problem because the private key will be in hand. However this doesn't apply to CSR created using ikeyman (IHS) because the key management tool doesn't offer a private key export functionality for security reason. Unfortunately the same restriction applies to java-based Keytool so for reason I will soon explain you might run into difficulty updating a Java keystore.
Without the private key you won't be able to convert a signed DER (.crt/cer/der) certificate received from a CA to PKCS12 (.p12), which is the format understood by ikeyman for "import" into a KDB/CMS database. However, if you use ikeyman to generate the original CSR then you should be able to "receive" the signed certificate from a CA directly into CMS. There is an important distinction between "Receiving" as opposed to "Importing" a certificate: ikeyman will happily receive a certificate file in binary DER or base-64 encoded format, but will only import from one of the following formats: CMS, JKS, JCEKS or PKCS12.
In order to export the private key from JKS you'd require a java tool that probably needs to be compiled from source (see ExportPriv.java, available from M. Foster or its variant ExportPrivateKey.java, whose source code is published in Read more... of this page).
It is worth noting that although IBM HTTP Server uses CMS/KDB for certificate & key management, the ikeyman tool that comes with IHS provides a functionality to save a CMS database as JKS. So apart from this additional step of KDB to JKS conversion, private key extraction using the java tool is exactly the same for IHS as it is for applications that rely on native JKS.
Finally PEM keys and certificates can be exported easily to DER format and vice versa. The DER format is understood by Apache and used by the CAs for certificate distribution. Binary encoded DER file can also be opened in a text viewer although it would appear as random texts so to examine its content use openssl ("openssl x509 -noout -text -in CRT.der" for a certificate received from CA or "openssl rsa -noout -text -in rsa.key" for a RSA private key) or just execute the file in Windows.
Further reading:
- X.509 from Wikipedia
- Source code for ExportPrivateKey.java
$Path_to_java/java ExportPrivateKey mykeystore.jks JKS mysecretpassword "my alias" myprivate.keyIf you receive a NullPointer exception chances are the alias specified is incorrect. Make sure you enclose the alias in double quotes.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import sun.misc.BASE64Encoder;
public class ExportPrivateKey {
private File keystoreFile;
private String keyStoreType;
private char[] password;
private String alias;
private File exportedFile;
public static KeyPair getPrivateKey(KeyStore keystore, String alias, char[] password) {
try {
Key key=keystore.getKey(alias,password);
if(key instanceof PrivateKey) {
Certificate cert=keystore.getCertificate(alias);
PublicKey publicKey=cert.getPublicKey();
return new KeyPair(publicKey,(PrivateKey)key);
}
} catch (UnrecoverableKeyException e) {
} catch (NoSuchAlgorithmException e) {
} catch (KeyStoreException e) {
}
return null;
}
public void export() throws Exception{
KeyStore keystore=KeyStore.getInstance(keyStoreType);
BASE64Encoder encoder=new BASE64Encoder();
keystore.load(new FileInputStream(keystoreFile),password);
KeyPair keyPair=getPrivateKey(keystore,alias,password);
PrivateKey privateKey=keyPair.getPrivate();
String encoded=encoder.encode(privateKey.getEncoded());
FileWriter fw=new FileWriter(exportedFile);
fw.write("---BEGIN PRIVATE KEY---\n");
fw.write(encoded);
fw.write("\n");
fw.write("---END PRIVATE KEY---");
fw.close();
}
public static void main(String args[]) throws Exception{
ExportPrivateKey export=new ExportPrivateKey();
export.keystoreFile=new File(args[0]);
export.keyStoreType=args[1];
export.password=args[2].toCharArray();
export.alias=args[3];
export.exportedFile=new File(args[4]);
export.export();
}
}


5 comments:
I'm trying to extract the private key from a JKS file. I use the ExportPrivateKey java code, and I'm getting stuck on the alias - it can't be found. The java keytool lists the aliases for me, so I know my "foo bar" alias is in there, but the java code does not find it. Any recommendations?
Hi, have you tried enclosing your alias value in double quotes ""?
Thanks for the response. I got the authority to re-issue the certificate and this time they have another alias in there that I could use. Not sure what the problem was on their end, but this code works.
What if I am not sure about the alias name? Guy created jks has given "name1" when he is generating the request would it be the same name for private key also.
Please help
Keytool might come in handy in this situation.
E.g. keytool -list -v -keystore keystore_file
Post a Comment