How to Create a PFX from CRT and KEY with OpenSSL

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

bash
openssl pkcs12 -export \
  -in certificate.crt \
  -inkey private.key \
  -out certificate.pfx \
  -passout pass:YourExportPassword

OpenSSL writes a password-protected PFX. Use a non-empty password—Windows often rejects blank PFX passwords on import.

Verify the bundle:

bash
openssl pkcs12 -in certificate.pfx -passin pass:YourExportPassword -info -noout
text
Certificate bag
Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC, Iteration 2048

Files 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:

bash
openssl x509 -noout -modulus -in certificate.crt | openssl md5
openssl rsa  -noout -modulus -in private.key  | openssl md5

Matching 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:

bash
openssl pkcs12 -export \
  -in certificate.crt \
  -inkey private.key \
  -out certificate.pfx

Set password on the command line

bash
openssl pkcs12 -export \
  -in certificate.crt \
  -inkey private.key \
  -out certificate.pfx \
  -passout pass:ExportPass123

Avoid leaving passwords in shell history on shared systems—use env: or file: instead:

bash
export PFXPASS='ExportPass123'
openssl pkcs12 -export -in certificate.crt -inkey private.key \
  -out certificate.pfx -passout env:PFXPASS
unset PFXPASS

Friendly name (optional)

Some Windows tools display the -name field:

bash
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:

bash
openssl pkcs12 -export \
  -in certificate.crt \
  -inkey private.key \
  -certfile intermediate.crt \
  -out certificate.pfx \
  -passout pass:ChainPass456

Multiple intermediates + root — concatenate into one PEM first:

bash
cat intermediate.crt root.crt > chain.pem

openssl pkcs12 -export \
  -in certificate.crt \
  -inkey private.key \
  -certfile chain.pem \
  -out certificate.pfx \
  -passout pass:ChainPass456

After export, -info shows multiple certificate bags:

text
Certificate bag
Certificate bag
Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC, Iteration 2048

Order 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:

bash
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:

bash
openssl pkcs12 -export -legacy \
  -in certificate.crt \
  -inkey private.key \
  -certfile intermediate.crt \
  -out certificate.pfx \
  -passout pass:ExportPass123

If IIS still fails on older hosts, force TripleDES + SHA1 explicitly:

bash
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:ExportPass123

Import 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:

bash
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:

bash
openssl pkcs12 -in certificate.pfx -passin pass:ExportPass123 -info -noout

Extract leaf subject to confirm:

bash
openssl pkcs12 -in certificate.pfx -passin pass:ExportPass123 \
  -clcerts -nokeys -out leaf-check.crt
openssl x509 -in leaf-check.crt -noout -subject -dates
text
subject=CN=app.example.test
notBefore=Jul  2 04:28:11 2026 GMT
notAfter=Jul  2 04:28:11 2027 GMT

Round-trip test: import on Windows or extract back to PEM using Extract private key from PFX.


Import on Windows IIS (after export)

  1. Copy certificate.pfx to the Windows server.
  2. Open MMC → Certificates (Local Computer) or IIS → Server Certificates → Import.
  3. Enter the export password you set with -passout.
  4. 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 .key and .pfx files.
  • 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.

Frequently Asked Questions

1. What is the OpenSSL command to create a PFX from CRT and KEY?

Run openssl pkcs12 -export -in cert.crt -inkey private.key -out cert.pfx -passout pass:YOUR_PASSWORD. The -in file is the leaf certificate, -inkey is the matching private key, and -passout sets the PFX import password Windows will ask for.

2. How do I include intermediate certificates in the PFX?

Add -certfile chain.pem where chain.pem contains intermediate and root CAs concatenated after the leaf is passed via -in. Example: cat intermediate.crt root.crt > chain.pem then use -certfile chain.pem on the export command.

3. Why does Windows IIS reject my OpenSSL PFX password?

OpenSSL 3.x defaults to AES-256 PKCS#12 encryption that older Windows Server versions cannot read. Re-export with -legacy, or explicitly use -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -macalg SHA1 for IIS on Windows Server 2016.

4. Can I create a PFX from an encrypted private key?

Yes. Pass the key unlock password with -passin pass:KEY_PASSWORD alongside -inkey. Example: openssl pkcs12 -export -inkey encrypted.key -passin pass:KEY_PASSWORD -in cert.crt -out cert.pfx -passout pass:PFX_PASSWORD.

5. Does the private key have to match the certificate?

Yes. OpenSSL errors with No cert in -in file matches private key when the CRT and KEY are not a pair. Verify with openssl x509 -noout -modulus -in cert.crt | openssl md5 and the same for the key before exporting.

6. How do I verify a PFX after creating it?

Run openssl pkcs12 -in cert.pfx -passin pass:YOUR_PASSWORD -info -noout to list certificate bags and the shrouded keybag. Extract and inspect with pkcs12 -clcerts -nokeys or see the extract guide linked from this page.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)