Convert CA-signed JKS keystore to PEM

35,741

Solution 1

You can easily convert a JKS file into a PKCS12 file:

keytool -importkeystore -srckeystore keystore.jks -srcstoretype JKS -deststoretype PKCS12 -destkeystore keystore.p12

You can then extract the private key and any certs with:

openssl pkcs12 -in keystore.p12

Solution 2

A rather large problem that I frequently encounter is that, when generating the CSR to get our certificate, the keystore (Sun formatted jks keystore) does not output the .key or provide any facility for obtaining the .key. So I always had ended up with a .pem/.crt with no way of using it with Apache2, which cannot read a JKS keystore like Tomcat can, but instead requires a unpackaged .key + .pem/.crt pair.

To start, get a “copy” of your existing keystore and skip to the 5th command below, or create your own like this:

C:\Temp>keytool -genkey -alias tomcat -keyalg RSA -keystore
 keystore.jks -keysize 2048 -validity 730 -storepass changeit

Then, optionally, create a 2-year CSR and then import the CSR response, in the next 3 step process:

C:\Temp>keytool -certreq -alias mydomain -keystore keystore.jks
 -file mydomain.csr
C:\Temp>keytool -import -trustcacerts -alias root -file
 RootPack.crt -keystore keystore.jks -storepass changeit
C:\Temp>keytool -import -trustcacerts -alias tomcat -file mydomain.response.crt
 -keystore keystore.jks -storepass changeit

To get this working, and if you already have your JKS keystore file that you use for a Tomcat application server, follow the following steps:

First, get the DER (binary) formatted certificate into a file called “exported-der.crt”:

C:\Temp>keytool -export -alias tomcat -keystore keystore.jks -file
 exported-der.crt

Then, view & verify it:

C:\Temp>openssl x509 -noout -text -in exported-der.crt -inform der

Now you will want to convert it to PEM format, which is more widely used in applications such as Apache and by OpenSSL to do the PKCS12 conversion:

C:\Temp>openssl x509 -in exported-der.crt -out exported-pem.crt 
-outform pem -inform der

Then, download and use ExportPriv to get the unencrypted private key from your keystore:

C:\Temp>java ExportPriv <keystore> <alias> <password> > exported-pkcs8.key

By now you probably realize, the private key is being exported as PKCS#8 PEM format. To get it into the RSA format that works with Apache (PKCS#12??) you can issue the following command:

C:\Temp>openssl pkcs8 -inform PEM -nocrypt -in exported-pkcs8.key
 -out exported-pem.key
Share:
35,741
Konrad Garus
Author by

Konrad Garus

Quality nut. So disappointed with "good enough" and "I don't care I'm too busy chasing my tail".

Updated on August 02, 2020

Comments

  • Konrad Garus
    Konrad Garus almost 4 years

    I have a JKS keystore with certicate signed by CA. I need to export it in PEM format in order to use it with nginx. I need to do it in such a way that it includes the whole chain, so that my client can verify the signature.

    If I do something like:

    keytool -exportcert -keystore mykestore.jks -file mycert.crt -alias myalias
    openssl x509 -out mycert.crt.pem -outform pem -in mycert.crt -inform der
    

    It only includes the lowest level certificate. The verification fails:

    $ openssl s_client -connect localhost:443
    CONNECTED(00000003)
    depth=0 /O=*.mydomain.com/OU=Domain Control Validated/CN=*.mydomain.com
    verify error:num=20:unable to get local issuer certificate
    verify return:1
    depth=0 /O=*.mydomain.com/OU=Domain Control Validated/CN=*.mydomain.com
    verify error:num=27:certificate not trusted
    verify return:1
    depth=0 /O=*.mydomain.com/OU=Domain Control Validated/CN=*.mydomain.com
    verify error:num=21:unable to verify the first certificate
    verify return:1
    ---
    Certificate chain
     0 s:/O=*.mydomain.com/OU=Domain Control Validated/CN=*.mydomain.com
       i:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certificates.godaddy.com/repository/CN=Go Daddy Secure Certification Authority/serialNumber=123123
    ... (only one certificate!)
    ...
    SSL-Session:
        ...
        Verify return code: 21 (unable to verify the first certificate)
    

    From Java:

    sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    

    Whereas Jetty with the same JKS keystore prints the following:

    $ openssl s_client -connect localhost:8084
    CONNECTED(00000003)
    depth=2 /C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority
    verify error:num=19:self signed certificate in certificate chain
    verify return:0
    ---
    Certificate chain
     0 s:/O=*.mydomain.com/OU=Domain Control Validated/CN=*.mydomain.com
       i:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certificates.godaddy.com/repository/CN=Go Daddy Secure Certification Authority/serialNumber=1234
     1 s:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certificates.godaddy.com/repository/CN=Go Daddy Secure Certification Authority/serialNumber=1234
       i:/C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority
     2 s:/C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority
       i:/C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority
    ...
    SSL-Session:
        Verify return code: 19 (self signed certificate in certificate chain)
    

    Although openssl returns that 19 error, it no longer is an issue for Java HttpsURLConnection and that is all I care about.

    So, how can I export the whole chain from JKS in a format (e.g. PEM) which works with both nginx server and Java client? What am I missing?

  • simbro
    simbro about 5 years
    This is a great answer - how does it not have more upvotes?
  • John Humphreys
    John Humphreys almost 5 years
    Agreed, I actually can't believe how well this worked.