OpenSSL 3 cannot read my PFX

If OpenSSL 3 fails to open a `.pfx` or `.p12` with a MAC error, an "unsupported" decoder message, or an apparent wrong-password error, the cause is almost always the algorithm rather than the password. OpenSSL 3 moved RC2, 3DES and other legacy ciphers into a provider that is not loaded by default, and older Windows and Java tools wrote archives using exactly those. Add `-legacy` to the command — `openssl pkcs12 -legacy -in certificate.pfx -out certificate.pem -nodes`. The same flag on export produces archives those older tools can read.

Updated August 19, 2026 Verified against OpenSSL 3.5.7

What actually changed #

OpenSSL 3.0 reorganised algorithms into providers. Ciphers considered obsolete — RC2, RC4, 3DES-in-PKCS#12, MD2, and others — moved into a legacy provider that is not loaded by default.

At the same time, the default PKCS#12 export encryption became AES-256-CBC with PBKDF2 and a SHA-256 MAC.

The result is a two-way incompatibility:

Archive written by Read by OpenSSL 3 Read by older tools
OpenSSL 1.x, older Windows, older Java Fails without -legacy Fine
OpenSSL 3 defaults Fine Fails, usually reported as a bad password

Reading an old archive #

Load the legacy provider for this command only
openssl pkcs12 -legacy -in certificate.pfx -info -noout

If that works where the command without -legacy failed, you have confirmed the diagnosis. Then extract as normal:

openssl pkcs12 -legacy -in certificate.pfx -nocerts -nodes -out private.key
openssl pkcs12 -legacy -in certificate.pfx -clcerts -nokeys -out certificate.crt

Writing an archive an old tool can read #

Export using legacy algorithms
openssl pkcs12 -export -legacy \
-out certificate.pfx \
-inkey private.key -in certificate.crt -certfile chain.crt

If your build does not accept -legacy, name the algorithms explicitly:

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

Telling which encryption an archive uses #

openssl pkcs12 -in certificate.pfx -info -noout 2>&1 | head -n 5
Expected output
MAC: sha256, Iteration 2048
PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC, Iteration 2048, PRF hmacWithSHA256

AES-256-CBC and a sha256 MAC mean a modern archive. RC2-40-CBC or 3DES with a sha1 MAC mean a legacy one.

The better long-term fix #

-legacy is a compatibility shim, not a resting place. Where you can:

  1. Upgrade the consuming system. Windows Server 2019 and later, and JDK 8u301 and later, read AES-256 PKCS#12 archives without complaint.
  2. Avoid PKCS#12 for transport. If both ends are Unix, moving separate PEM files sidesteps the entire problem.
  3. Re-protect at the destination. If you must use -legacy to move a key, do not leave it in that archive afterwards.

Loading the provider globally (usually a mistake) #

It can be done through openssl.cnf:

[provider_sect]
default = default_sect
legacy  = legacy_sect

[default_sect]
activate = 1

[legacy_sect]
activate = 1

Frequently asked questions

Does -legacy weaken the file?
Yes. It selects RC2 or 3DES with a SHA-1 MAC, all of which are deprecated. Use it only when the system on the other end cannot read a modern archive, treat the file as short-lived transport, and protect the key properly at the destination.
Why does Windows say the password is wrong when it is correct?
Because the older Windows importer cannot decrypt an AES-256-CBC archive, and it reports every decryption failure as a bad password. The symptom points at the wrong cause, which is why this wastes so much time.
Which OpenSSL versions are affected?
OpenSSL 3.0 and later. OpenSSL 1.1.1 and earlier used RC2/3DES by default and had no separate legacy provider, so they read and write the old format without any flag.
Can I load the legacy provider permanently?
Yes, by adding a legacy provider section to openssl.cnf, but it is better not to. A per-command -legacy flag keeps the weak algorithms opt-in rather than making every operation on the machine quietly accept them.

References