| Tested on | Ubuntu 25.04 (Plucky Puffin) |
|---|---|
| Package | openssl 3.2.2 |
| Applies to | Ubuntu, Debian, RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora |
| Privilege | sudo or root |
| Scope | Bundle a certificate and private key into a PFX file, including intermediate chain, export password, and legacy compatibility for older Windows. |
| Related guides | OpenSSL Tutorial How to Install OpenSSL on Ubuntu Generate duplicate certificates with the same key How to Verify a Certificate Matches a Private Key wi... How to Create PKCS12 from CRT and KEY with OpenSSL |
You have a .crt (or .pem) certificate and a .key private key from Let’s Encrypt, a commercial CA, or an internal signer—and Windows IIS, Azure, or Java wants a single .pfx / .p12 file instead. OpenSSL’s pkcs12 -export bundles the leaf certificate, private key, optional intermediate chain, and an export password into PKCS#12 format.
This guide covers every common export scenario: basic CRT + KEY, password-protected output, intermediate chain via -certfile, encrypted input keys, legacy PFX for older Windows, and verification after export. I ran the commands on Ubuntu 25.04 with OpenSSL 3.4.1. For JVM apps, confirm the alias with keytool after export; to unpack a PFX later on Linux, see Extract private key from PFX.
Quick answer: create PFX from CRT and KEY
openssl pkcs12 -export \
-in certificate.crt \
-inkey private.key \
-out certificate.pfx \
-passout pass:YourExportPasswordOpenSSL writes a password-protected PFX. Use a non-empty password—Windows often rejects blank PFX passwords on import.
Verify the bundle:
openssl pkcs12 -in certificate.pfx -passin pass:YourExportPassword -info -nooutCertificate bag
Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC, Iteration 2048Files you need before exporting
| File | Role | Common extensions |
|---|---|---|
| Leaf certificate | Your server/app cert | .crt, .cer, .pem |
| Private key | Matching key pair | .key, .pem |
| Intermediate(s) | CA between leaf and root | intermediate.crt, gd_bundle.crt |
| Root (optional) | Often omitted in PFX; include if required | root.crt |
The leaf certificate in -in must match -inkey. Check before export:
openssl x509 -noout -modulus -in certificate.crt | openssl md5
openssl rsa -noout -modulus -in private.key | openssl md5Matching MD5(stdin)= lines mean the pair is valid. See View certificate with OpenSSL for more inspection commands.
Create PFX with export password
Prompt for password interactively
Omit -passout; OpenSSL asks twice for the PFX import password:
openssl pkcs12 -export \
-in certificate.crt \
-inkey private.key \
-out certificate.pfxSet password on the command line
openssl pkcs12 -export \
-in certificate.crt \
-inkey private.key \
-out certificate.pfx \
-passout pass:ExportPass123Avoid leaving passwords in shell history on shared systems—use env: or file: instead:
export PFXPASS='ExportPass123'
openssl pkcs12 -export -in certificate.crt -inkey private.key \
-out certificate.pfx -passout env:PFXPASS
unset PFXPASSFriendly name (optional)
Some Windows tools display the -name field:
openssl pkcs12 -export \
-in certificate.crt \
-inkey private.key \
-out certificate.pfx \
-passout pass:ExportPass123 \
-name "www.example.com"Create PFX with intermediate chain
When your CA sent a separate intermediate (or bundle file), attach it with -certfile. The leaf stays in -in; chain certificates go in -certfile.
Single intermediate:
openssl pkcs12 -export \
-in certificate.crt \
-inkey private.key \
-certfile intermediate.crt \
-out certificate.pfx \
-passout pass:ChainPass456Multiple intermediates + root — concatenate into one PEM first:
cat intermediate.crt root.crt > chain.pem
openssl pkcs12 -export \
-in certificate.crt \
-inkey private.key \
-certfile chain.pem \
-out certificate.pfx \
-passout pass:ChainPass456After export, -info shows multiple certificate bags:
Certificate bag
Certificate bag
Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC, Iteration 2048Order in -certfile should follow CA guidance—typically intermediate(s) first, root last. Many vendors ship a ready-made bundle (for example gd_bundle-g2-g1.crt) you pass directly to -certfile.
Export when the private key is encrypted
If private.key was created with a passphrase (BEGIN ENCRYPTED PRIVATE KEY), unlock it during export:
openssl pkcs12 -export \
-in certificate.crt \
-inkey encrypted.key \
-passin pass:KeyPass99 \
-out certificate.pfx \
-passout pass:ExportPass123-passin unlocks the key file; -passout sets the new PFX password. If you see No cert in -in file matches private key, the CRT and KEY are not a pair—fix that before retrying.
To remove the key passphrase first (nginx-style unencrypted key), see the workflow in Generate self-signed certificate or decrypt with openssl rsa -in encrypted.key -passin pass:KEYPASS -out plain.key.
Legacy PFX for Windows IIS and older imports
OpenSSL 3.x defaults to AES-256 PKCS#12 encryption. Windows Server 2016 and some IIS versions reject that with “password incorrect” even when the password is right—the algorithms differ, not your typing.
Try -legacy first:
openssl pkcs12 -export -legacy \
-in certificate.crt \
-inkey private.key \
-certfile intermediate.crt \
-out certificate.pfx \
-passout pass:ExportPass123If IIS still fails on older hosts, force TripleDES + SHA1 explicitly:
openssl pkcs12 -export \
-legacy \
-macalg SHA1 \
-keypbe PBE-SHA1-3DES \
-certpbe PBE-SHA1-3DES \
-in certificate.crt \
-inkey private.key \
-certfile intermediate.crt \
-out certificate.pfx \
-passout pass:ExportPass123Import the resulting PFX on Windows with the same -passout password you set during export.
PEM, CRT, and CER inputs
OpenSSL -in and -inkey expect PEM text (Base64 with BEGIN/END lines). If your .crt is binary DER:
openssl x509 -in cert.cer -inform DER -out cert.pem
openssl pkcs12 -export -in cert.pem -inkey private.key -out cert.pfx -passout pass:ExportPass123.pem, .crt, and .cer (when PEM-encoded) are interchangeable as long as the content is PEM.
Verify and test the PFX
List contents:
openssl pkcs12 -in certificate.pfx -passin pass:ExportPass123 -info -nooutExtract leaf subject to confirm:
openssl pkcs12 -in certificate.pfx -passin pass:ExportPass123 \
-clcerts -nokeys -out leaf-check.crt
openssl x509 -in leaf-check.crt -noout -subject -datessubject=CN=app.example.test
notBefore=Jul 2 04:28:11 2026 GMT
notAfter=Jul 2 04:28:11 2027 GMTRound-trip test: import on Windows or extract back to PEM using Extract private key from PFX.
Import on Windows IIS (after export)
- Copy
certificate.pfxto the Windows server. - Open MMC → Certificates (Local Computer) or IIS → Server Certificates → Import.
- Enter the export password you set with
-passout. - Bind the certificate in IIS site → Edit Bindings → HTTPS.
If import fails, re-export with -legacy or the TripleDES command above.
Troubleshooting
| Problem | Cause | Fix |
|---|---|---|
No cert in -in file matches private key |
CRT/KEY mismatch | Compare modulus MD5; re-download or re-issue cert |
| Windows “password incorrect” on import | OpenSSL 3 modern ciphers | Add -legacy or -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -macalg SHA1 |
| Empty PFX password rejected | Windows policy | Use -passout pass:NonEmptyPassword |
| Missing intermediate in IIS chain | Chain not in PFX | Re-export with -certfile intermediate.crt |
unable to load private key |
Encrypted key, no -passin |
Add -passin pass:KEY_PASSWORD |
Only one cert bag in -info |
No -certfile used |
Concatenate intermediates and re-export |
Security notes
- The PFX password protects the bundle; anyone with the file and password has your private key.
- Prefer restrictive file permissions (
chmod 600) on.keyand.pfxfiles. - Do not commit PFX files or passwords to git.
- Use CA-issued certificates for production HTTPS; PFX is a transport format, not a substitute for proper issuance.
References
Summary
Run openssl pkcs12 -export -in leaf.crt -inkey private.key -out bundle.pfx -passout pass:YOUR_PASSWORD to create a PFX from CRT and KEY. Add -certfile chain.pem when intermediates or root CAs must ship inside the bundle for IIS or Java. Use -passin when the input key is encrypted, and -legacy (or explicit -keypbe PBE-SHA1-3DES) when older Windows rejects OpenSSL 3 defaults. Confirm the CRT matches the key with modulus MD5 before export, then verify with openssl pkcs12 -info -noout. To split the PFX back into PEM files on Linux, use Extract private key from PFX.

