using System.Security.Cryptography;using System.Security.Cryptography.X509Certificates; string password = Environment.GetEnvironmentVariable("P12_PASSWORD")!; // Certificate + its private key from PEM files in one callusing X509Certificate2 leaf = X509Certificate2.CreateFromPemFile("leaf.pem", "key.pem");using X509Certificate2 intermediate = X509CertificateLoader.LoadCertificateFromFile("intermediate.pem"); var bundle = new X509Certificate2Collection { leaf, intermediate };// .NET 9+: choose the protection explicitly; Export(X509ContentType.Pkcs12, ...) uses 3DES and SHA-1byte[] pfx = bundle.ExportPkcs12(Pkcs12ExportPbeParameters.Pbes2Aes256Sha256, password);File.WriteAllBytes("bundle.p12", pfx); using System.Security.Cryptography;using System.Security.Cryptography.X509Certificates; string password = Environment.GetEnvironmentVariable("P12_PASSWORD")!; // Every certificate of the file; the one with a private key is the leafX509Certificate2Collection all = X509CertificateLoader.LoadPkcs12CollectionFromFile("bundle.p12", password);foreach (X509Certificate2 cert in all){ Console.WriteLine($"{cert.Subject} | private key: {cert.HasPrivateKey}");}using ECDsa? key = all.First(c => c.HasPrivateKey).GetECDsaPrivateKey();Console.WriteLine($"key: ECDSA {key!.KeySize}-bit"); try{ X509CertificateLoader.LoadPkcs12FromFile("bundle.p12", "wrong-password");}catch (CryptographicException e){ Console.WriteLine($"wrong password: {e.Message}");} How it works
X509Certificate2.CreateFromPemFile("leaf.pem", "key.pem")pairs the certificate with its private key; the intermediate is loaded on its own.collection.ExportPkcs12(Pkcs12ExportPbeParameters.Pbes2Aes256Sha256, password)writes AES-256-CBC with PBKDF2-HMAC-SHA256 and an HMAC-SHA-256 MAC (2000 iterations in the run).X509CertificateLoader.LoadPkcs12CollectionFromFilereturns every certificate; the one withHasPrivateKeyis the leaf, andGetECDsaPrivateKey()gives its key.LoadPkcs12FromFile(singular) returns only the certificate that has the key —CN=api.example.comwithHasPrivateKeytrue in the run.
Gotchas
Export(X509ContentType.Pkcs12, password)— the classic method — protects the key with 3DES and SHA-1 (pbeWithSHA1And3-KeyTripleDES-CBCin the run). UseExportPkcs12withPbes2Aes256Sha256for new files.- Setting
FriendlyNameoutside Windows throwsPlatformNotSupportedException: The FriendlyName value cannot be set on Unix., so bundles made on Linux carry no friendly name (OpenSSL shows it empty). - A wrong password throws
CryptographicException: The certificate data cannot be read with the provided password, the password may be incorrect.
Related recipes
- How to create a PKCS#12 (.p12/.pfx) file from a key and certificate chain in Java
- How to create a PKCS#12 (.p12/.pfx) file from a key and certificate chain with OpenSSL
- How to create a PKCS#12 (.p12/.pfx) file from a key and certificate chain in Python
- How to convert a certificate and a private key between PEM and DER in C# (.NET)
- How to verify a certificate chain against your own trust store in C# (.NET)