Convert JKS to PKCS#12 – and back

Since Java 9, PKCS#12 is the default keystore format, and keytool urges you to migrate every time it touches a JKS file. The conversion is one command; the pitfalls are passwords and old versions.

Why PKCS#12?

JKS is a format only Java understands. PKCS#12 (extension .p12 or .pfx) is a standard that OpenSSL, Windows, web server tooling and browsers read too. Since Java 9 keytool therefore creates PKCS#12 by default. For JKS files you get this warning:

Warning: The JKS keystore uses a proprietary format. It is recommended to migrate
to PKCS12 which is an industry standard format using "keytool -importkeystore ..."

The command

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

keytool asks for the source password and the new password. All entries are copied: keys with their certificate chain and trusted certificates. Then adjust file name and type in the application, for example in Spring Boot:

server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-type=PKCS12

The password trap

In JKS each key can have its own password that differs from the keystore password. keytool does not support that for PKCS#12: key and store password are the same. keytool then says:

Warning: Different store and key passwords not supported for PKCS12 KeyStores.
Ignoring user-specified -destkeypass value.

If the key had a different password, pass it with -srckeypass. In the result only the store password applies. Remove a separate key-password setting in the application or set it to the same value.

Back to JKS

Some old applications or appliances insist on JKS. The way back is the same command with the types swapped:

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

PKCS#12 to PEM for nginx or Apache

If the certificate goes onto a web server or load balancer, you usually need PEM. Use OpenSSL or the certificate converter:

openssl pkcs12 -in keystore.p12 -clcerts -nokeys -out server.crt
openssl pkcs12 -in keystore.p12 -cacerts -nokeys -out chain.crt
openssl pkcs12 -in keystore.p12 -nocerts -nodes -out server.key

Old Java versions and OpenSSL 3

The encryption inside PKCS#12 has changed. Java 12 and later (as well as Java 8u301 and 11.0.12) write PKCS#12 with AES-256 and SHA-256. Older Java versions used RC2 and 3DES. That causes two problems:

The Java keystore helper reads both variants and lets you choose “modern” (AES-256) or “compatible” (3DES) when saving.

FAQ

Do I lose anything in the conversion?

Keys, chains and trusted certificates are copied. Only different passwords per key are lost, because PKCS#12 in Java uses a single password.

Can I simply rename the .p12 to .pfx?

Yes. Both are the same format; Windows usually expects the .pfx extension.

What about JCEKS?

JCEKS can also store symmetric keys. keytool copies them to PKCS#12 as well if you specify -srcstoretype JCEKS.

Do I have to convert truststores too?

Not necessarily; Java still reads JKS. The JDK’s cacerts has itself been PKCS#12 since Java 9, but it is read regardless of type.