# Convert PFX / PKCS#12 to PEM

To extract everything from a PFX into one PEM file, run `openssl pkcs12 -in certificate.pfx -out certificate.pem -nodes`. Most of the time you want the pieces separately instead: `-nocerts -nodes` writes just the private key, `-clcerts -nokeys` writes just the server certificate, and `-cacerts -nokeys` writes just the CA chain. If OpenSSL 3 refuses the file with a "unsupported" or MAC error, add `-legacy`, because archives produced by older tools use RC2 or 3DES ciphers that OpenSSL 3 moved into its legacy provider.

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

---

## Extract everything at once

*Certificate, chain and key into one PEM file*

```bash
openssl pkcs12 -in certificate.pfx -out certificate.pem -nodes
```

OpenSSL asks for the archive's import password. The result contains every object concatenated, which
is fine for HAProxy but wrong for nginx and Apache, both of which want the key in a separate file.

## Extract the pieces separately

This is what you usually want. Three commands, one per output file:

*Private key only*

```bash
openssl pkcs12 -in certificate.pfx -nocerts -nodes -out private.key
```

*Server certificate only*

```bash
openssl pkcs12 -in certificate.pfx -clcerts -nokeys -out certificate.crt
```

*CA chain only*

```bash
openssl pkcs12 -in certificate.pfx -cacerts -nokeys -out chain.crt
```

| Placeholder | What to put there |
| --- | --- |
| `-nocerts` | Suppress certificates, leaving only the private key. |
| `-nokeys` | Suppress the private key, leaving only certificates. |
| `-clcerts` | Client/end-entity certificate only — the one for your hostname. |
| `-cacerts` | CA certificates only — the intermediate chain. |
| `-nodes` | Write the key unencrypted. Spelled `-noenc` in OpenSSL 3. |

> **An unencrypted key on disk**
>
> `-nodes` writes a key that anyone who can read the file can use. Restrict it immediately —
>   `chmod 600 private.key` — and do not leave a copy in a shared or backed-up directory.

## If OpenSSL 3 refuses the archive

Archives written by older Windows tooling, older Java, or OpenSSL 1.x use RC2 or 3DES. OpenSSL 3
moved those algorithms into a legacy provider that is not loaded by default, and the resulting error
usually looks like a MAC or password problem rather than an algorithm problem:

*Load the legacy provider for this one command*

```bash
openssl pkcs12 -legacy -in certificate.pfx -out certificate.pem -nodes
```

That specific failure is covered in full at
[unsupported MAC / PKCS#12 legacy errors](/errors/unsupported-mac-pkcs12-legacy/).

## Scripting it without a prompt

{/* Not verified: the password is a placeholder, so it cannot match a fixture. */}
*Non-interactive extraction*

```bash
openssl pkcs12 -in certificate.pfx -nocerts -nodes \
  -passin pass:MyImportPassword -out private.key
```

> **Keep the password out of the process list**
>
> `pass:` puts the secret in `ps` output and your shell history. Prefer
>   `-passin file:/run/secrets/pfx-password` or `-passin env:PFX_PASSWORD`.

## Check what is in the archive before extracting

Useful when you do not know whether the chain is even present:

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

One `Certificate bag` per certificate and one `Shrouded Keybag` for the key. If you see only a single
certificate bag, there is no chain in the archive and `-cacerts` will produce an empty file.

## Wiring the results into a web server

#### nginx

nginx wants the leaf and chain concatenated into one file:

    ```bash
cat certificate.crt chain.crt > fullchain.crt
```

    ```nginx
ssl_certificate     /etc/ssl/certs/fullchain.crt;
ssl_certificate_key /etc/ssl/private/private.key;
```

#### Apache

Apache 2.4.8 and later also read the chain from the certificate file:

    ```apache
SSLCertificateFile    /etc/ssl/certs/fullchain.crt
SSLCertificateKeyFile /etc/ssl/private/private.key
```

Before reloading, confirm the extracted key actually matches the extracted certificate — a mismatch
here is the usual cause of a service that refuses to start:

```bash
openssl x509 -in certificate.crt -noout -pubkey | openssl sha256
openssl pkey -in private.key -pubout | openssl sha256
```


## Frequently asked questions

### What does -nodes do?

It writes the private key unencrypted. Without it, OpenSSL prompts for a new passphrase and encrypts the extracted key. Web servers that must start unattended need the unencrypted form. In OpenSSL 3 the flag is also spelled `-noenc`, which is clearer about what it does.

### How do I split the output into separate files?

Use the selector flags rather than editing by hand. `-nocerts` gives you only the key, `-clcerts` only the end-entity certificate, and `-cacerts` only the chain. Running the command three times is cleaner and less error-prone than cutting one combined file apart.

### Why is there a block of "Bag Attributes" text in my PEM file?

OpenSSL writes PKCS#12 bag metadata such as the friendly name and local key ID above each object. It is harmless and every implementation ignores it, but you can suppress it with `-nomacver` is not the answer — use `openssl x509` or `openssl pkey` to re-emit just the object if you want a clean file.

### Can I extract without knowing the password?

No. The private key inside a PKCS#12 archive is encrypted with a key derived from that password. Without it the archive is not recoverable by any tool, which is the entire point of the format.


## References

- [openssl-pkcs12(1)](https://docs.openssl.org/3.5/man1/openssl-pkcs12/) — extracting certificates and keys from an archive
- [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/pem-to-pfx/
- https://certguru.io/formats/pkcs12-pfx-p12/
- https://certguru.io/errors/unsupported-mac-pkcs12-legacy/
- https://certguru.io/openssl/extract-key-from-pkcs12/
- https://certguru.io/platforms/nginx/
- https://certguru.io/openssl/extract-cert-from-pkcs12/

--
CertGuru — https://certguru.io
