La question PKCS#12 vs PEM se pose chaque fois qu’une clé et un certificat circulent entre des serveurs Unix et des plateformes dotées de leurs propres magasins de clés. Les fichiers PEM sont des blocs séparés et lisibles que les logiciels fondés sur OpenSSL chargent directement ; un fichier PKCS#12 (.p12 ou .pfx) est un conteneur chiffré unique que les systèmes d’exploitation et Java importent en une seule étape. Mêmes clés et mêmes certificats, emballage différent, et ce sont les algorithmes de l’emballage qui décident si un import fonctionne.
Vue d’ensemble
| PEM | PKCS#12 (PFX) | |
|---|---|---|
| Spécification | RFC 7468 (encodage texte du DER) | RFC 7292 (PKCS #12 v1.1), RFC 9579 (PBMAC1) |
| Format | Texte, un ou plusieurs blocs BEGIN … END | Conteneur DER binaire de « safe bags » |
| Contenu | Tout ce que vous mettez dans le fichier : clé, certificats, CRL | Clés privées, certificats, CRL, secrets, avec noms conviviaux et identifiants de clé |
| Protection | Facultative, par clé (PKCS#8 chiffré) | Chiffrement des bags par mot de passe, plus un MAC d’intégrité |
| Protection par défaut d’OpenSSL 3.6 | PBES2 avec AES-256-CBC pour les clés chiffrées | PBES2, PBKDF2-HMAC-SHA256, AES-256-CBC, 2048 itérations ; MAC HMAC-SHA256 |
-legacy d’OpenSSL | Sans objet | RC2-40 pour les certificats, 3DES pour les clés, MAC HMAC-SHA1 |
| Extensions courantes | .pem, .crt, .key | .p12, .pfx |
| Utilisé par | OpenSSL, serveurs web, proxys, Go, Python, Node.js | Magasin de certificats Windows, trousseau macOS, KeyStore de Java, navigateurs, signtool |
Ce que contient un .pfx
Un fichier PKCS#12 est une structure PFX : un coffre authentifié (authenticated safe) composé de blocs de contenu, chacun contenant des bags. Les clés privées se trouvent dans des entrées pkcs8ShroudedKeyBag (PKCS#8 chiffré), les certificats dans des entrées certBag (souvent placées, elles aussi, dans un bloc chiffré), et les bags portent des attributs comme friendlyName et localKeyId qui relient une clé à son certificat. Un MAC dérivé du mot de passe protège l’intégrité de l’ensemble du fichier ; la RFC 9579 (2024) ajoute PBMAC1, qui dérive la clé du MAC avec PBKDF2 au lieu de l’ancienne KDF de PKCS#12.
PEM n’a pas de conteneur : un serveur est configuré avec un fichier de clé et un fichier de certificat (ou de chaîne), ou bien avec un seul fichier contenant plusieurs blocs. La protection est celle du fichier de clé, en général inexistante sur les serveurs, car le processus doit lire la clé sans que personne ne saisisse de mot de passe.
Conversion
Le script ci-dessous, exécuté avec OpenSSL 3.6.5, place une clé et un certificat jetables dans un fichier PKCS#12, puis les en extrait.
#!/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-----
Pour inclure les intermédiaires, passez-les avec -certfile chain.pem ; pour n’extraire que les certificats, utilisez -nokeys, et pour la clé seule, -nocerts. L’option -nodes (nommée -noenc dans les versions récentes) écrit la clé sans chiffrement : manipulez la sortie en conséquence.
Compatibilité : algorithmes modernes ou anciens
OpenSSL 3.0 a remplacé les valeurs d’export par défaut, RC2-40 et 3DES avec un MAC HMAC-SHA1, par AES-256 avec un MAC HMAC-SHA256. De nombreux consommateurs ne se sont adaptés que plus tard :
- macOS : le framework Security d’Apple importe les fichiers PKCS#12 modernes depuis macOS 15 ; macOS 14 et les versions antérieures échouent avec « MAC verification failed during PKCS12 import (wrong password?) », même avec le bon mot de passe.
- Java : le JDK 9 a fait de PKCS#12 le type de keystore par défaut ; le JDK 16 (et les mises à jour de 2021 des versions 8 et 11) a fait passer les valeurs par défaut propres à Java à PBES2 avec AES-256 et un MAC HMAC-SHA256, et les versions actuelles lisent les fichiers d’OpenSSL 3.
- Windows : les versions actuelles importent les fichiers PFX en AES-256 ; les très anciennes versions de Windows Server peuvent nécessiter l’ancienne forme.
- OpenSSL 3 face aux anciens fichiers : les fichiers dont les certificats sont chiffrés en RC2-40 (la valeur par défaut d’OpenSSL 1.1, et ce qu’utilisent les exports
-legacylorsque RC2 est compilé) ne se chargent qu’avec-legacy, qui charge le fournisseur legacy. Sans cette option, OpenSSL 3.6.5 afficheerror:0308010C:digital envelope routines:inner_evp_generic_fetch:unsupportedpourRC2-40-CBC, et Node.js 26 rejette le fichier avecUnsupported PKCS12 PFX data. Les fichiers qui n’utilisent que 3DES et un MAC HMAC-SHA1 se chargent sans le fournisseur legacy.
Lorsqu’un fichier moderne échoue sur une cible que l’on sait ancienne, exportez avec openssl pkcs12 -export -legacy …, ou choisissez explicitement les algorithmes (-keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -macalg SHA1), et considérez ce fichier comme faiblement protégé pendant son transport.
Les messages d’erreur sont trompeurs ici : « MAC verification failed » ou « wrong password » signifie généralement que le lecteur ne prend pas en charge l’algorithme de MAC ou de chiffrement, et non que le mot de passe est faux. Inspectez le fichier avec openssl pkcs12 -info -noout (ajoutez -legacy pour les anciens fichiers) afin de voir quels algorithmes ont été utilisés avant d’essayer de deviner des mots de passe.
PKCS#12 comme keystore
Java traite un fichier PKCS#12 comme un keystore : keytool -list -keystore bundle.p12 -storetype PKCS12 affiche ses entrées, et le friendlyName devient l’alias. Un keystore peut contenir plusieurs entrées de clé et des certificats de confiance, ce qu’un fichier PEM ne peut pas exprimer sans conventions de nommage. Les truststores sont un cas particulier : un truststore PKCS#12 ne contenant que des certificats a besoin d’attributs propres à Java pour les marquer comme approuvés, si bien que keytool -importcert est le moyen fiable d’en construire un. La plupart des autres plateformes ignorent ces attributs Java et importent clés et certificats en faisant correspondre localKeyId.
Quand choisir l’un ou l’autre
- TLS sur des serveurs Linux, proxys inverses, ingress Kubernetes : clé PEM et certificat avec la chaîne complète.
- Imports de certificats dans Windows IIS, Azure App Service et Key Vault : PKCS#12.
- TLS avec Java et Spring Boot : un keystore PKCS#12 (ou du PEM, que les versions récentes de Spring Boot acceptent directement).
- Certificats clients pour navigateurs et appareils mobiles : PKCS#12 avec un mot de passe robuste, le fichier étant transmis séparément du mot de passe.
- Signature de code avec signtool ou jarsigner : PKCS#12, si tant est que la clé se trouve dans un fichier ; depuis 2023, les clés de signature de code de confiance publique doivent résider dans du matériel dédié.
- Inspection et débogage : PEM, ou l’inspecteur PFX, qui liste localement les bags et les algorithmes sans révéler la clé.
Notes de migration
- Incluez la chaîne complète lorsque vous construisez un PKCS#12 pour des serveurs ou des clients, en commençant par le certificat feuille ; les intermédiaires manquants sont la cause d’échec la plus courante après un import.
- Vérifiez que la clé et le certificat correspondent avant de les empaqueter : le comparateur de clé et de certificat compare leurs clés publiques.
- Choisissez les algorithmes en fonction du consommateur le plus ancien, puis passez aux plus récents : réexportez avec les valeurs par défaut modernes une fois les anciennes plateformes disparues.
- Utilisez des mots de passe robustes et aléatoires pour les fichiers PKCS#12 qui circulent, car le fichier peut être attaqué hors ligne ; les 2048 itérations PBKDF2 par défaut d’OpenSSL sont peu nombreuses au regard des normes de stockage des mots de passe.
- Ne laissez pas traîner les clés extraites : après avoir converti un
.pfxen PEM pour un serveur, restreignez les permissions des fichiers et supprimez les copies temporaires.