How to convert a PFX file to PEM using OpenSSL

PKCS#12 archives, usually saved as .pfx or .p12 files, bundle a certificate, its private key, and sometimes the issuing certificate chain into one password-protected file. Converting that archive to PEM is needed when a Linux service, reverse proxy, client tool, or certificate handoff expects separate certificate, key, and chain files instead of a Windows or appliance export.

OpenSSL parses the archive with pkcs12 and can write only the leaf certificate with -clcerts -nokeys, only CA certificates with -cacerts -nokeys, and only the private key with -nocerts. Use -noenc only when the target service cannot unlock an encrypted key at startup; OpenSSL 3.x deprecates the older -nodes spelling for this job.

The command examples keep the PFX import password in a protected file so it does not appear in shell history, process listings, or saved evidence. Omit -passin file:pfx-password.txt to let OpenSSL prompt interactively, and remove the temporary password file after the PEM files have been written and checked.

Steps to convert a PFX file to PEM using OpenSSL:

  1. Stage the PFX archive and its password in a private working directory.
    $ install -d -m 700 "$HOME/pfx-export"
    $ install -m 600 "$HOME/Downloads/www.example.net.pfx" "$HOME/pfx-export/www.example.net.pfx"
    $ install -m 600 /run/secrets/pfx-password "$HOME/pfx-export/pfx-password.txt"
    $ cd "$HOME/pfx-export"
    $ ls -l www.example.net.pfx pfx-password.txt
    -rw------- 1 deploy deploy   20 Jun  5 20:25 pfx-password.txt
    -rw------- 1 deploy deploy 3698 Jun  5 20:25 www.example.net.pfx

    Replace /run/secrets/pfx-password with the protected source that holds the PFX import password. For a one-time manual conversion, omit -passin file:pfx-password.txt in the later commands and type the password at the OpenSSL prompt instead.

  2. Inspect the PFX archive before writing any credential files.
    $ openssl pkcs12 -in www.example.net.pfx -passin file:pfx-password.txt -info -noout
    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

    -info -noout confirms that the password opens the archive and shows the bag types without writing the certificate or private key to the terminal.

    If an older export fails because of legacy algorithms such as RC2-40-CBC, rerun the same command with -legacy for that archive only.

  3. Extract the leaf certificate to its own PEM file.
    $ openssl pkcs12 -in www.example.net.pfx -passin file:pfx-password.txt -clcerts -nokeys -out www.example.net.crt.pem

    -clcerts -nokeys writes the end-entity certificate and skips private keys and CA certificates.

  4. Extract the CA certificates from the archive into a separate chain file.
    $ openssl pkcs12 -in www.example.net.pfx -passin file:pfx-password.txt -cacerts -nokeys -out www.example.net.chain.pem

    Some PFX exports do not include the issuing chain. If the chain file is empty or does not verify the leaf later, get the current intermediate or CA bundle from the certificate issuer or internal PKI source.

  5. Extract the private key as an unencrypted PEM key only when the target service needs a key file it can read at startup.
    $ openssl pkcs12 -in www.example.net.pfx -passin file:pfx-password.txt -nocerts -noenc -out www.example.net.key.pem

    -noenc writes the private key without passphrase protection. Keep the file readable only by the service account or administrator that needs it, and omit -noenc when the consuming software supports encrypted keys.

  6. Restrict the extracted private key and review the output files.
    $ chmod 600 www.example.net.key.pem
    $ ls -l www.example.net.chain.pem www.example.net.crt.pem www.example.net.key.pem
    -rw------- 1 deploy deploy 1384 Jun  5 20:25 www.example.net.chain.pem
    -rw------- 1 deploy deploy 1523 Jun  5 20:25 www.example.net.crt.pem
    -rw------- 1 deploy deploy 1862 Jun  5 20:25 www.example.net.key.pem

    Do not attach the private key, PFX archive, or password file to tickets, chat messages, screenshots, or saved article evidence.

  7. Check that the extracted certificate has the expected subject, issuer, and expiry date.
    $ openssl x509 -in www.example.net.crt.pem -noout -subject -issuer -enddate
    subject=CN=www.example.net, O=Example Web
    issuer=CN=Example Issuing CA, O=Example Internal PKI
    notAfter=Sep  7 20:25:56 2028 GMT

    Fix a wrong subject, unexpected issuer, or expired certificate before installing the extracted files into a service.

  8. Compare the public key from the certificate with the public key derived from the private key.
    $ openssl x509 -in www.example.net.crt.pem -pubkey -noout -out www.example.net.crt.pub.pem
    $ openssl pkey -in www.example.net.key.pem -pubout -out www.example.net.key.pub.pem
    $ openssl dgst -sha256 www.example.net.crt.pub.pem www.example.net.key.pub.pem
    SHA2-256(www.example.net.crt.pub.pem)= 8dcdee07eb14074581d5811a1ba463c7349e3e1c89108ca99b0dd1b686808971
    SHA2-256(www.example.net.key.pub.pem)= 8dcdee07eb14074581d5811a1ba463c7349e3e1c89108ca99b0dd1b686808971

    Matching digests show that the certificate and private key belong to the same key pair.

  9. Verify the certificate against the extracted chain when the chain file contains the issuing CA material needed for the check.
    $ openssl verify -CAfile www.example.net.chain.pem www.example.net.crt.pem
    www.example.net.crt.pem: OK

    If the extracted chain contains only intermediates, verify against the system trust store or the organization CA bundle instead of treating a local openssl verify failure as proof that the extraction failed.

  10. Remove the temporary password file after the extracted PEM files have passed the checks.
    $ rm -f pfx-password.txt

    Keep the original PFX archive and the extracted private key in approved secret storage only. Delete local working copies when the target service no longer needs them.