Reputation: 185
In connection to renewal of some certificates I had to convert a jks keystore to a PKCS#12 keystore and include the private key during the conversion as well. We received the keystore as a JKS keystore, however our webservers uses PKCS#12 keystores, and the keystores we received only contained the certificates and not the private key.
I tried to google around and readthrough several entries at SO, and I have only come up with a solution, which seems more like a workaround than a good approach, so I was wondering if someone out there has a better approach how to inject private keys and convert from a jks keystore to a PKCS#12 keystore in a simpler manner.
It seems like JKS keystores can only be manipulated by the keytool, however the keytool utility does not support injecting private keys into trustedCertEntries AFAIK, so the approach I used was as follows:
assuming I have the private key as a pem file.
So the whole flow is as follows (In case also needs it):
openssl pkcs12 -in orig.alias.p12 -nodes -nocerts -out key.pem -passin pass:PASSWORD
keytool -keystore keystore1 -storepass PASSWORD -list
keytool -keystore keystore1 -storepass PASSWORD -rfc -file alias.root.pem -alias "root" -exportcert
keytool -keystore keystore1 -storepass PASSWORD -rfc -file alias.ca3.pem -alias "ca3" -exportcert
keytool -keystore keystore1 -storepass PASSWORD -rfc -file alias.long.pem -alias "long" -exportcert
keytool -keystore keystore1 -storepass PASSWORD -rfc -file alias.short.pem -alias "short" -exportcert
openssl pkcs12 -export -out keystore.p12 -inkey key.pem -in alias.short.pem -passout pass:PASSWORD
keytool -changealias -alias "1" -destalias "short" -keypass PASSWORD -keystore keystore.p12 -storepass PASSWORD
openssl pkcs12 -export -out keystore2.p12 -inkey key.pem -in alias.long.pem -passout pass:PASSWORD
keytool -changealias -alias "1" -destalias "long" -keypass PASSWORD -keystore keystore2.p12 -storepass PASSWORD
keytool -importkeystore -srckeystore keystore2.p12 -srcstoretype pkcs12 -srcstorepass PASSWORD -destkeystore keystore.p12 -deststoretype pkcs12 -deststorepass PASSWORD
keytool -keystore keystore.p12 -storepass PASSWORD -file alias.ca3.pem -alias "ca3" -importcert -noprompt
keytool -keystore keystore.p12 -storepass PASSWORD -file alias.root.pem -alias "root" -importcert -noprompt
keytool -keystore keystore.p12 -storepass PASSWORD -list
I imagined for instance if I could set the alias while importing a private keyed certificate then I would not need rename the alias' afterwards. Is that possible?
At any rate thanks in advance
Upvotes: 5
Views: 16736
Reputation: 38771
You can eliminate the -changealias
steps by using -name long
and -name short
on the pkcs12 -export
steps
For both keystore.p12
and keystore2.p12
your inputs are key.pem
and (cert) alias.short.pem
. Did you intend to use (cert) alias.long.pem
for one of them?
Among free Oracle Javas, only later versions of j8 (with keystore.compat set in java.security) can read both JKS and P12 keystores without specifying the type. By default j7 and lower only do JKS, j9 and higher only P12.
FWIW, if you convert the original JKS (with trustedCert's) to P12 (with j8+ only) then openssl pkcs12 -nokeys
will output all the trustedcerts in one operation -- but since you need to do differing things with them, you need to split that into separate files or else do on-demand like:
awk '/friendlyName: short/,/-END CERT/' allcerts.pem | \ openssl pkcs12 -export -inkey key.pem -name short -out file -passout pass:PW # similar for long -- or make loop # combine the p12s as before awk '/friendlyName: root/,/-END CERT/' allcerts.pem | \ keytool -keystore file -storepass PW -importcert -file root.pem -alias root -noprompt # similar for ca3 -- or make loop
... which I'm not sure is really an improvement
Alternatively, since this is SO, you could write a program that does this more directly:
char[] pw = "PASSWORD".toCharArray(); // or whatever as appropriate
KeyStore ks1 = KeyStore.getInstance("JKS"); ks1.load (new FileInputStream ("certs",pw));
KeyStore ks2 = KeyStore.getInstance("PKCS12");
try( InputStream is = new FileInputStream("oldp12") ){ ks2.load(is,pw); }
String alias = ks2.getAliases().nextElement(); // assume only one
PrivateKey key = (PrivateKey) ks2.getKey(alias,pw);
ks2.deleteAlias(alias);
ks2.setKeyEntry("short",key,pw,new Certificate[]{ ks1.getCertificate("short") });
ks2.setKeyEntry("long" ,key,pw,new Certificate[]{ ks1.getCertificate("long" ) });
// assuming those combinations are what you intended, see above
ks2.setCertificateEntry("root", ks1.getCertificate("root") );
ks2.setCertificateEntry("ca3" , ks1.getCertificate("ca3" ) );
try( OutputStream os = new FileOutputStream ("newp12") ){ ks2.store(os,pw); }
Upvotes: 4