La cuestión de PKCS#12 frente a PEM surge siempre que una clave y un certificado se mueven entre servidores Unix y plataformas con sus propios almacenes de claves. Los archivos PEM son bloques separados y legibles que el software basado en OpenSSL carga directamente; un archivo PKCS#12 (.p12 o .pfx) es un único contenedor cifrado que los sistemas operativos y Java importan en un solo paso. Son las mismas claves y los mismos certificados con distinto empaquetado, y los algoritmos del empaquetado deciden si una importación funciona.
De un vistazo
| PEM | PKCS#12 (PFX) | |
|---|---|---|
| Especificación | RFC 7468 (codificación de texto de DER) | RFC 7292 (PKCS #12 v1.1), RFC 9579 (PBMAC1) |
| Formato | Texto, uno o más bloques BEGIN … END | Contenedor binario en DER de bolsas («safe bags») |
| Contenido | Lo que pongas en el archivo: clave, certificados, CRL | Claves privadas, certificados, CRL, secretos, con nombres descriptivos e ID de clave |
| Protección | Opcional para cada clave (PKCS#8 cifrado) | Cifrado de las bolsas basado en contraseña más un MAC de integridad |
| Protección por defecto en OpenSSL 3.6 | PBES2 con AES-256-CBC para las claves cifradas | PBES2, PBKDF2-HMAC-SHA256, AES-256-CBC, 2048 iteraciones; MAC HMAC-SHA256 |
-legacy de OpenSSL | No aplicable | RC2-40 para los certificados, 3DES para las claves, MAC HMAC-SHA1 |
| Extensiones habituales | .pem, .crt, .key | .p12, .pfx |
| Lo usan | OpenSSL, servidores web, proxies, Go, Python, Node.js | Almacén de certificados de Windows, llavero de macOS, KeyStore de Java, navegadores, signtool |
Qué contiene un .pfx
Un archivo PKCS#12 es una estructura PFX: un contenedor autenticado (authenticated safe) formado por bloques de contenido, cada uno con sus bolsas. Las claves privadas están en entradas pkcs8ShroudedKeyBag (PKCS#8 cifrado), los certificados en entradas certBag (a menudo también dentro de un bloque cifrado), y las bolsas llevan atributos como friendlyName y localKeyId que vinculan una clave con su certificado. Un MAC derivado de la contraseña protege la integridad de todo el archivo; el RFC 9579 (2024) añade PBMAC1, que deriva la clave del MAC con PBKDF2 en lugar de la KDF heredada de PKCS#12.
PEM no tiene contenedor: un servidor se configura con un archivo de clave y un archivo de certificado (o de cadena), o con un solo archivo con varios bloques. La protección es la que tenga el archivo de la clave, normalmente ninguna en los servidores, porque el proceso tiene que leer la clave sin que nadie escriba una contraseña.
Conversión
El script siguiente, ejecutado con OpenSSL 3.6.5, empaqueta una clave y un certificado desechables en un archivo PKCS#12 y después vuelve a desempaquetarlo.
#!/bin/sh
dir=$(mktemp -d)
cd "$dir" || exit 1
openssl req -new -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -keyout key.pem \
-subj "/CN=example.com" -days 30 -out cert.pem 2>/dev/null
openssl pkcs12 -export -inkey key.pem -in cert.pem -name demo -passout pass:demo -out bundle.p12
openssl pkcs12 -in bundle.p12 -passin pass:demo -info -noout 2>&1 | grep -E "MAC:|Shrouded|PKCS7 Encrypted"
openssl pkcs12 -in bundle.p12 -passin pass:demo -nodes -out extracted.pem 2>/dev/null
grep -E "^-----BEGIN" extracted.pem
cd / && rm -rf "$dir"
MAC: sha256, Iteration 2048
PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC, Iteration 2048, PRF hmacWithSHA256
Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC, Iteration 2048, PRF hmacWithSHA256
-----BEGIN CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
Para incluir los intermedios, pásalos con -certfile chain.pem; para extraer solo los certificados, usa -nokeys, y solo la clave, -nocerts. La opción -nodes (llamada -noenc en las versiones más recientes) escribe la clave sin cifrar, así que trata la salida con el cuidado que corresponde.
Compatibilidad: algoritmos modernos frente a heredados
OpenSSL 3.0 cambió los valores por defecto de exportación: de RC2-40 y 3DES con un MAC HMAC-SHA1 pasó a AES-256 con un MAC HMAC-SHA256. Muchos consumidores se pusieron al día más tarde:
- macOS: el framework Security de Apple importa archivos PKCS#12 modernos a partir de macOS 15; macOS 14 y anteriores fallan con «MAC verification failed during PKCS12 import (wrong password?)», incluso con la contraseña correcta.
- Java: JDK 9 convirtió PKCS#12 en el tipo de almacén de claves por defecto; JDK 16 (y las actualizaciones de 2021 de 8 y 11) cambió el valor por defecto propio de Java a PBES2 con AES-256 y un MAC HMAC-SHA256, y las versiones actuales leen los archivos de OpenSSL 3.
- Windows: las versiones actuales importan archivos PFX con AES-256; las versiones muy antiguas de Windows Server pueden necesitar la forma heredada.
- OpenSSL 3 con archivos antiguos: los archivos cuyos certificados están cifrados con RC2-40 (el valor por defecto de OpenSSL 1.1, y lo que usan las exportaciones con
-legacycuando RC2 está incluido en la compilación) solo se cargan con-legacy, que carga el proveedor heredado (legacy). Sin él, OpenSSL 3.6.5 muestraerror:0308010C:digital envelope routines:inner_evp_generic_fetch:unsupportedparaRC2-40-CBC, y Node.js 26 rechaza el archivo conUnsupported PKCS12 PFX data. Los archivos que solo usan 3DES y un MAC HMAC-SHA1 se cargan sin el proveedor heredado.
Cuando un archivo moderno falla en un destino que sabes que es antiguo, exporta con openssl pkcs12 -export -legacy … o elige los algoritmos de forma explícita (-keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -macalg SHA1), y considera que ese archivo viaja con una protección débil.
Aquí los mensajes de error engañan: «MAC verification failed» o «wrong password» suelen significar que el lector no admite el algoritmo del MAC o del cifrado, no que la contraseña sea incorrecta. Antes de probar contraseñas, inspecciona el archivo con openssl pkcs12 -info -noout (añade -legacy para los archivos antiguos) para ver qué algoritmos se usaron.
PKCS#12 como almacén de claves
Java trata un archivo PKCS#12 como un almacén de claves: keytool -list -keystore bundle.p12 -storetype PKCS12 muestra sus entradas, y el friendlyName se convierte en el alias. Un almacén de claves puede contener varias entradas de clave y certificados de confianza, algo que un archivo PEM no puede expresar sin convenciones de nombres. Los almacenes de confianza son un caso especial: un almacén de confianza PKCS#12 que solo contiene certificados necesita atributos propios de Java para marcarlos como de confianza, así que keytool -importcert es la forma fiable de crear uno. La mayoría de las demás plataformas ignoran esos atributos de Java e importan las claves y los certificados emparejándolos por localKeyId.
Cuándo elegir cada uno
- TLS en servidores Linux, proxies inversos, ingress de Kubernetes: clave PEM y certificado con la cadena completa.
- Importación de certificados en IIS de Windows, Azure App Service y Key Vault: PKCS#12.
- TLS en Java y Spring Boot: un almacén de claves PKCS#12 (o PEM, que las versiones recientes de Spring Boot aceptan directamente).
- Certificados de cliente para navegadores y dispositivos móviles: PKCS#12 con una contraseña robusta; el archivo y la contraseña se entregan por separado.
- Firma de código con signtool o jarsigner: PKCS#12, si es que la clave está en un archivo; desde 2023, las claves de firma de código de confianza pública deben residir en hardware.
- Inspección y depuración: PEM, o el inspector de PFX, que enumera en local las bolsas y los algoritmos sin revelar la clave.
Notas de migración
- Incluye la cadena completa al crear un PKCS#12 para servidores o clientes, empezando por el certificado hoja; la falta de intermedios es el fallo más habitual después de la importación.
- Comprueba que la clave y el certificado se corresponden antes de empaquetarlos: el comprobador de clave y certificado compara sus claves públicas.
- Elige los algoritmos para el consumidor más antiguo y después actualiza: vuelve a exportar con los valores por defecto modernos cuando desaparezcan las plataformas antiguas.
- Usa contraseñas robustas y aleatorias en los archivos PKCS#12 que viajan, porque el archivo se puede atacar sin conexión; las 2048 iteraciones de PBKDF2 que OpenSSL usa por defecto son pocas para los estándares de almacenamiento de contraseñas.
- No dejes claves extraídas por ahí: después de convertir un
.pfxa PEM para un servidor, restringe los permisos del archivo y borra las copias temporales.
Referencias
- RFC 7292, PKCS #12 v1.1
- RFC 9579, PBMAC1 en PKCS #12
- RFC 7468, codificaciones PEM
- RFC 5958, paquetes de claves asimétricas PKCS #8
- Manual de openssl-pkcs12 de OpenSSL
- JDK-8228481, algoritmos PKCS #12 por defecto más robustos en Java
- Apple Developer Forums: compatibilidad con PKCS #12 moderno en macOS 15