# Convert PEM to PFX / PKCS#12

To convert PEM to PFX, run `openssl pkcs12 -export -out certificate.pfx -inkey private.key -in certificate.crt -certfile chain.crt`. This bundles the certificate, its private key and any intermediate CA certificates into one password-protected PKCS#12 file. If the resulting file is rejected by Windows, IIS or a Java keystore, re-export it with the `-legacy` flag, because OpenSSL 3.x encrypts PKCS#12 files with AES-256-CBC by default and older implementations only understand the RC2 and 3DES ciphers.

Source: https://certguru.io/convert/pem-to-pfx/
Last updated: 2026-08-19
Commands verified against OpenSSL 3.5.7.

---

## The command

*Bundle certificate, key and chain into one PFX*

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

OpenSSL prompts twice for an export password. That password protects the private key inside the archive, and whoever imports the file will need it.

| Placeholder | What to put there |
| --- | --- |
| `certificate.pfx` | The PKCS#12 file to create. `.p12` is the same format. |
| `private.key` | PEM private key that matches the certificate. |
| `certificate.crt` | The end-entity (server) certificate, PEM-encoded. |
| `chain.crt` | Intermediate CA certificates, concatenated. Omit `-certfile` if you have none. |

## Doing it non-interactively

In a script or CI job you cannot answer a password prompt. Pass the password on the command line instead:

*Scripted export with an explicit password*

```bash
openssl pkcs12 -export \
  -out certificate.pfx \
  -inkey private.key \
  -in certificate.crt \
  -certfile chain.crt \
  -passout pass:MyExportPassword
```

> **Passwords on the command line**
>
> Anything after `pass:` is visible to every other user on the machine via `ps`, and it lands in your
>   shell history. Prefer `-passout file:/path/to/secret` or `-passout env:PFX_PASSWORD`, both of which
>   keep the secret out of the process list.

## If the PFX is rejected by Windows, IIS or Java

OpenSSL 3.0 changed the default PKCS#12 encryption to **AES-256-CBC with PBKDF2** and the MAC to SHA-256. That is the correct modern choice, but implementations written against the original PKCS#12 spec cannot read it, and they usually report the failure as a wrong password rather than an unsupported cipher.

*Export using the legacy algorithms older importers understand*

```bash
openssl pkcs12 -export -legacy \
  -out certificate.pfx \
  -inkey private.key \
  -in certificate.crt \
  -certfile chain.crt
```

`-legacy` is shorthand for the older RC2/3DES ciphers plus a SHA-1 MAC. If your OpenSSL build does not accept `-legacy`, spell the algorithms out:

```bash
openssl pkcs12 -export \
  -certpbe PBE-SHA1-3DES \
  -keypbe PBE-SHA1-3DES \
  -macalg sha1 \
  -out certificate.pfx \
  -inkey private.key \
  -in certificate.crt \
  -certfile chain.crt
```

> **These are weak algorithms**
>
> RC2, 3DES and SHA-1 are all deprecated. Use `-legacy` only when the consuming system genuinely
>   cannot read a modern archive, treat the file as short-lived transport, and re-protect the key
>   properly at the destination.

## Setting a friendly name

Windows certificate stores and Java keystores display the archive's *friendly name*, and an unnamed entry is painful to pick out of a list later:

```bash
openssl pkcs12 -export \
  -out certificate.pfx \
  -inkey private.key \
  -in certificate.crt \
  -certfile chain.crt \
  -name "example.com production"
```

## Verify the result

*List what actually ended up in the archive*

```bash
openssl pkcs12 -info -in certificate.pfx -noout
```

Expected output:

```
MAC: sha256, Iteration 2048
MAC length: 32, salt length: 8
PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC, Iteration 2048, PRF hmacWithSHA256
Certificate bag
Certificate bag
PKCS7 Data
Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC, Iteration 2048, PRF hmacWithSHA256
```

Read the output as a checklist. One `Certificate bag` per certificate means the chain went in — if you passed a two-certificate `chain.crt` you should see three bags in total. Exactly one `Shrouded Keybag` means the private key is present and encrypted. The `PBES2, PBKDF2, AES-256-CBC` line tells you this is a modern archive, so if you were aiming for `-legacy` output and see this instead, the flag did not take effect.

## Common failures

| Symptom | Cause | Fix |
| --- | --- | --- |
| `unable to load private key` | The key is encrypted and you were not prompted, or it is not PEM | Add `-passin pass:...`, or convert the key to PEM first |
| `No certificate matches private key` | The `.crt` and `.key` are from different key pairs | [Check whether the key and certificate match](/openssl/check-key-matches-certificate/) |
| Windows: "The password you entered is incorrect" | OpenSSL 3.x AES-256 archive | Re-export with `-legacy` |
| `Error outputting keys and certificates` with a PEM chain | `chain.crt` contains something that is not a certificate | Strip any private key or text preamble from the chain file |

## Going the other way

To unpack a PFX back into PEM files, see [convert PFX to PEM](/convert/pfx-to-pem/).


## Frequently asked questions

### What is the difference between .pfx and .p12?

Nothing. Both extensions denote a PKCS#12 archive with an identical binary format. Microsoft tooling historically wrote `.pfx` and most other software writes `.p12`, but the two are interchangeable and OpenSSL reads either.

### Can I create a PFX without a private key?

Yes, use `openssl pkcs12 -export -nokeys -in certificate.crt -certfile chain.crt -out bundle.pfx`. The result is a certificate-only archive, which is what you want when you are shipping a trust bundle rather than an identity.

### Can I create a PFX with no password?

Yes, pass `-passout pass:` with nothing after the colon. Be aware that many import tools refuse a blank password, and the private key inside the file is then entirely unprotected on disk.

### Why does Windows say the PFX password is incorrect when it is not?

This is almost always the OpenSSL 3.x cipher change rather than a wrong password. Re-export with `-legacy` so the archive uses RC2/3DES, which the older Windows CryptoAPI importer can decrypt.


## References

- [openssl-pkcs12(1)](https://docs.openssl.org/3.5/man1/openssl-pkcs12/) — -export and the -legacy flag
- [RFC 7292: PKCS #12](https://www.rfc-editor.org/rfc/rfc7292) — the archive format, including the MAC OpenSSL 3 rejects on legacy files

## Related pages

- https://certguru.io/convert/pfx-to-pem/
- https://certguru.io/formats/pkcs12-pfx-p12/
- https://certguru.io/formats/pem/
- https://certguru.io/errors/unsupported-mac-pkcs12-legacy/
- https://certguru.io/platforms/iis/

--
CertGuru — https://certguru.io
