Convertir JKS a PKCS#12 – y al revés

Desde Java 9, PKCS#12 es el formato de keystore por defecto y keytool insiste en migrar cada vez que toca un archivo JKS. La conversión es un comando; las trampas están en las contraseñas y las versiones antiguas.

¿Por qué PKCS#12?

JKS es un formato que solo entiende Java. PKCS#12 (extensión .p12 o .pfx) es un estándar que también leen OpenSSL, Windows, las herramientas de servidores web y los navegadores. Por eso keytool crea PKCS#12 por defecto desde Java 9. Con archivos JKS aparece el aviso:

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

El comando

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

keytool pide la contraseña del origen y la nueva contraseña. Se copian todas las entradas: claves con su cadena y certificados de confianza. Después ajusta nombre y tipo en la aplicación, por ejemplo en Spring Boot:

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

La trampa de las contraseñas

En JKS cada clave puede tener su propia contraseña, distinta de la del keystore. keytool no lo admite en PKCS#12: la contraseña de la clave y la del almacén son la misma. keytool muestra entonces:

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

Si la clave tenía otra contraseña, indícala con -srckeypass. En el resultado solo vale la contraseña del almacén. Quita en la aplicación un ajuste key-password separado o ponle el mismo valor.

Volver a JKS

Algunas aplicaciones o appliances antiguos exigen JKS. El camino de vuelta es el mismo comando con los tipos intercambiados:

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

PKCS#12 a PEM para nginx o Apache

Para un servidor web o un balanceador de carga normalmente necesitas PEM. Con OpenSSL o con el conversor de certificados:

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

Java antiguo y OpenSSL 3

El cifrado interno de PKCS#12 ha cambiado. Java 12 y posteriores (y también Java 8u301 y 11.0.12) escriben PKCS#12 con AES-256 y SHA-256. Las versiones anteriores usaban RC2 y 3DES. Eso causa dos problemas:

El asistente de keystores Java lee ambas variantes y al guardar te deja elegir «moderno» (AES-256) o «compatible» (3DES).

FAQ

¿Pierdo algo en la conversión?

Se copian claves, cadenas y certificados de confianza. Solo se pierden las contraseñas distintas por clave, porque PKCS#12 en Java usa una única contraseña.

¿Puedo renombrar sin más el .p12 a .pfx?

Sí. Es el mismo formato; Windows suele esperar la extensión .pfx.

¿Y JCEKS?

JCEKS también puede guardar claves simétricas. keytool las pasa igualmente a PKCS#12 si indicas -srcstoretype JCEKS.

¿Tengo que convertir también los truststores?

No necesariamente; Java sigue leyendo JKS. El cacerts del JDK es PKCS#12 desde Java 9, pero se lee sea cual sea su tipo.