PKCS#12 — .pfx and .p12
PKCS#12 is a password-protected binary archive that bundles a certificate, its private key and the intermediate chain into a single file. `.pfx` and `.p12` are the same format under different extensions — Microsoft tooling writes `.pfx` and most other software writes `.p12`. It is the standard way to move a complete TLS identity between systems, and the format most likely to cause trouble across OpenSSL versions, because OpenSSL 3 changed the default encryption to AES-256-CBC and older importers cannot read it.
What is inside #
A PKCS#12 archive is a set of “bags”, each holding one object:
| Bag type | Contents |
|---|---|
| Certificate bag | One certificate. A typical archive has one per chain member. |
| Shrouded key bag | The private key, encrypted with a key derived from the password. |
| Bag attributes | The friendly name and local key ID that associate a key with its certificate. |
The whole file is then MAC-protected using the same password, so tampering is detectable.
openssl pkcs12 -in certificate.pfx -info -noout Expected output
MAC: sha256, Iteration 2048 PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC Certificate bag Certificate bag PKCS7 Data Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC
Two certificate bags plus one shrouded key bag is the shape of a normal server identity with one intermediate. No shrouded key bag means there is no private key in the file.
The OpenSSL 3 problem #
This is the single most common thing to go wrong with PKCS#12 files, and it is worth understanding rather than just memorising the flag.
OpenSSL 3.0 changed the default PKCS#12 encryption from RC2/3DES with a SHA-1 MAC to AES-256-CBC with PBKDF2 and a SHA-256 MAC. That is unambiguously the right default. But implementations written against the original specification — older Windows CryptoAPI, older JDKs, various appliances — do not implement those algorithms, and when decryption fails they report it as an incorrect password rather than an unsupported cipher. So the symptom points at the wrong cause.
openssl pkcs12 -export -legacy \
-out certificate.pfx -inkey private.key -in certificate.crt openssl pkcs12 -legacy -in certificate.pfx -info -noout Creating and unpacking #
openssl pkcs12 -export \
-out certificate.pfx \
-inkey private.key \
-in certificate.crt \
-certfile chain.crt \
-name "example.com" openssl pkcs12 -in certificate.pfx -nocerts -nodes -out private.key
openssl pkcs12 -in certificate.pfx -clcerts -nokeys -out certificate.crt
openssl pkcs12 -in certificate.pfx -cacerts -nokeys -out chain.crt Full detail at PEM to PFX and PFX to PEM.
Where you will meet it #
- IIS and Windows use PKCS#12 as the native import and export format for TLS identities.
- Java 9 and later default to PKCS#12 for keystores, replacing JKS.
- Azure, AWS and most managed platforms accept a PFX upload as the way to supply a certificate with its key.
- Moving a certificate between machines — it is the one file format that carries the complete identity, which is exactly why it needs a password.
Handling it safely #
Setting a blank password with -passout pass: produces a file with no protection at all. Some
import tools require it, most refuse it, and it should never touch a shared filesystem.
Frequently asked questions
- What is the difference between .pfx and .p12?
- Nothing. The binary format is identical and every tool reads either.
.pfxcame from Microsoft's earlier PFX specification, which PKCS#12 superseded, and the name stuck in the Windows ecosystem. - Does a PFX always contain the private key?
- Almost always, and that is the point of the format — but not necessarily. An archive exported with
-nokeysholds certificates only. Runopenssl pkcs12 -info -nooutand look for a Shrouded Keybag to find out. - Why does Windows say my password is wrong when it is not?
- Because OpenSSL 3 encrypted the archive with AES-256-CBC and the older Windows importer cannot decrypt it, reporting the failure as a bad password. Re-export with
-legacy. See the full explanation. - Can a PFX hold more than one certificate and key?
- Yes. The format is a general bag structure and can hold several identities, each distinguished by a friendly name. In practice almost every PFX holds exactly one identity plus its chain.
References
- RFC 7292: PKCS #12 — the archive format, including the MAC OpenSSL 3 rejects on legacy files