M. A. Tanaka
M. A. Tanaka

Reputation: 185

adding private key to a keystore

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.

  1. extracted all certificates from the jks keystore using the keytool.
  2. created a PKCS#12 keystore using the openssl
  3. rename the alias in the created PKCS12 using keytool
  4. create another PKCS#12 keystore using the openssl
  5. rename the alias in the other created PKCS#12 using keytool
  6. merge the two keystore into one using the keytool
  7. importing the non private keyed certificates

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

Answers (1)

dave_thompson_085
dave_thompson_085

Reputation: 38771

  1. You can eliminate the -changealias steps by using -name long and -name short on the pkcs12 -export steps

  2. 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?

  3. 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.

  4. 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

Related Questions