Scenario 12.2: PFX/PKCS#12 Export

Category: Import/Export
Complexity: * (Medium)
Prerequisites: Certificate with Private Key
Estimated Time: 15-20 minutes </WRAP> —- ===== Description ===== This scenario describes export and import in PFX/PKCS#12 format. PFX (Personal Information Exchange) is the standard format for Windows and .NET to store certificates together with private keys and optionally the certificate chain in a password-protected file. PFX/PKCS#12 Properties: * Content: Certificate + Private Key + Chain * Encoding: Binary (ASN.1/DER) * Encryption: Password-protected * Extensions: .pfx, .p12 —- ===== Workflow ===== <mermaid> flowchart LR subgraph Input CERT[Certificate] KEY[Private Key] CHAIN[Chain] end subgraph PFX[„PFX File“] BAG1[Cert Bag] BAG2[Key Bag] BAG3[CA Bags] end CERT –> BAG1 KEY –> BAG2 CHAIN –> BAG3 PFX –> ENC[Encrypted] </mermaid> —- ===== Code Example: Create PFX ===== <code csharp> using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ; using System.Security.Cryptography.X509Certificates; using var ctx = PqCryptoContext.Initialize(); Load certificate and key var cert = ctx.LoadCertificate(„server.crt.pem“); var privateKey = ctx.LoadPrivateKey(„server.key.pem“, „KeyPassword!“); Combine certificate with key var certWithKey = ctx.CombineCertificateAndKey(cert, privateKey); Export PFX byte[] pfxBytes = certWithKey.Export(X509ContentType.Pfx, „PfxPassword123!“); File.WriteAllBytes(„server.pfx“, pfxBytes); Console.WriteLine(„PFX created: server.pfx“); </code> —- ===== Code Example: PFX with Chain ===== <code csharp> public class PfxExporter { public byte[] ExportWithChain( X509Certificate2 certificate, X509Certificate2Collection chain, string password, PfxExportOptions options = null) { options ??= PfxExportOptions.Default; using var ctx = PqCryptoContext.Initialize(); Create collection for export var exportCollection = new X509Certificate2Collection(); exportCollection.Add(certificate); Add chain (without root, if desired) foreach (var caCert in chain) { if (options.IncludeRoot || !IsSelfSigned(caCert)) { exportCollection.Add(caCert); } } Export PFX var pfxBytes = exportCollection.Export(X509ContentType.Pfx, password); Console.WriteLine($„PFX created with {exportCollection.Count} certificates“); return pfxBytes; } public void ExportToFile( X509Certificate2 certificate, X509Certificate2Collection chain, string outputPath, string password) { var pfxBytes = ExportWithChain(certificate, chain, password); File.WriteAllBytes(outputPath, pfxBytes); Set permissions (owner only) if (OperatingSystem.IsWindows()) { var fileInfo = new FileInfo(outputPath); var security = fileInfo.GetAccessControl(); security.SetAccessRuleProtection(true, false); fileInfo.SetAccessControl(security); } } private bool IsSelfSigned(X509Certificate2 cert) { return cert.Subject == cert.Issuer; } } public class PfxExportOptions { public bool IncludeRoot { get; set; } = false; public bool IncludeChain { get; set; } = true; public static PfxExportOptions Default ⇒ new PfxExportOptions(); } </code> —- ===== Code Example: Import PFX ===== <code csharp> using var ctx = PqCryptoContext.Initialize(); Load PFX var pfxBytes = File.ReadAllBytes(„server.pfx“); var cert = new X509Certificate2( pfxBytes, „PfxPassword123!“, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet ); Console.WriteLine($„Subject: {cert.Subject}“); Console.WriteLine($„Has Private Key: {cert.HasPrivateKey}“); Extract private key if (cert.HasPrivateKey) { var privateKey = cert.GetRSAPrivateKey() ?? cert.GetECDsaPrivateKey() ?? (AsymmetricAlgorithm)ctx.GetPqPrivateKey(cert); Console.WriteLine($„Key Type: {privateKey.GetType().Name}“); } Extract chain from PFX var collection = new X509Certificate2Collection(); collection.Import(pfxBytes, „PfxPassword123!“, X509KeyStorageFlags.DefaultKeySet); Console.WriteLine($„Certificates in PFX: {collection.Count}“); foreach (var c in collection) { Console.WriteLine($„ - {c.Subject}“); } </code> —- ===== Code Example: Secure PFX with AES-256 ===== <code csharp> public class SecurePfxExporter { public byte[] ExportSecure( X509Certificate2 certificate, string password) { .NET 5+ supports modern PFX encryption var exportParams = new PbeParameters( PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, iterations: 100000 ); return certificate.Export(X509ContentType.Pfx, password); } public byte[] ExportWithOpenSsl( X509Certificate2 certificate, AsymmetricAlgorithm privateKey, X509Certificate2Collection chain, string password) { using var ctx = PqCryptoContext.Initialize(); OpenSSL-based export for maximum compatibility var pfxBuilder = new Pkcs12Builder(); Add Key Bag var keyBag = new Pkcs12KeyBag( privateKey.ExportPkcs8PrivateKey(), skipCopy: false ); Add Cert Bag var certBag = new Pkcs12CertBag(certificate); Create Safe Contents var safeContents = new Pkcs12SafeContents(); safeContents.AddBag(keyBag); safeContents.AddBag(certBag); foreach (var caCert in chain) { safeContents.AddBag(new Pkcs12CertBag(caCert)); } Encrypt with password pfxBuilder.AddSafeContentsEncrypted( safeContents, password, new PbeParameters( PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, 100000 ) ); pfxBuilder.SealWithMac(password, HashAlgorithmName.SHA256, 100000); return pfxBuilder.Encode(); } } </code> —- ===== Code Example: PFX for Windows Certificate Store ===== <code csharp> public class WindowsCertificateInstaller { public void InstallPfxToStore( string pfxPath, string password, StoreName storeName = StoreName.My, StoreLocation location = StoreLocation.LocalMachine) { var pfxBytes = File.ReadAllBytes(pfxPath); var cert = new X509Certificate2( pfxBytes, password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable ); using var store = new X509Store(storeName, location); store.Open(OpenFlags.ReadWrite); Check if already present var existing = store.Certificates.Find( X509FindType.FindByThumbprint, cert.Thumbprint, validOnly: false ); if (existing.Count > 0) { Console.WriteLine(„Certificate already exists in store“); return; } store.Add(cert); store.Close(); Console.WriteLine($„Certificate installed: {cert.Subject}“); Console.WriteLine($„Store: {storeName} ({location})“); Console.WriteLine($„Thumbprint: {cert.Thumbprint}“); } public void ExportFromStore( string thumbprint, string outputPath, string password, StoreName storeName = StoreName.My, StoreLocation location = StoreLocation.LocalMachine) { using var store = new X509Store(storeName, location); store.Open(OpenFlags.ReadOnly); var certs = store.Certificates.Find( X509FindType.FindByThumbprint, thumbprint, validOnly: false ); if (certs.Count == 0) { throw new Exception($„Certificate not found: {thumbprint}“); } var cert = certs[0]; if (!cert.HasPrivateKey) { throw new Exception(„Certificate has no private key“); } var pfxBytes = cert.Export(X509ContentType.Pfx, password); File.WriteAllBytes(outputPath, pfxBytes); Console.WriteLine($„PFX exported: {outputPath}“); } } </code> —- ===== Create PFX with OpenSSL ===== <code bash> # Create PFX from PEM files openssl pkcs12 -export \ -out server.pfx \ -inkey server.key \ -in server.crt \ -certfile chain.pem \ -passout pass:MyPassword # PFX with modern algorithm (AES-256) openssl pkcs12 -export \ -out server.pfx \ -inkey server.key \ -in server.crt \ -certfile chain.pem \ -aes256 \ -passout pass:MyPassword # Inspect PFX openssl pkcs12 -info -in server.pfx -passin pass:MyPassword # Unpack PFX openssl pkcs12 -in server.pfx \ -out combined.pem \ -nodes \ -passin pass:MyPassword </code> —- ===== Industry-Specific PFX Requirements ===== ^ Industry ^ Key Storage ^ Export ^ Specifics ^ | Windows Server | MachineKeySet | Exportable | IIS SSL Binding | | Azure | UserKeySet | Non-Exportable | App Service | | Code Signing | MachineKeySet | Non-Exportable | Authenticode | | Smart Card | Hardware | Non-Exportable | PIV Certificates | —- ===== Related Scenarios ===== ^ Relationship ^ Scenario ^ Description ^ | Alternative | 12.1 PEM Export | Linux format | | Related | 12.3 PKCS#7 Chain | Certificates only | | Prerequisite | 3.1 Server Certificate | Create certificate | —- « <- 12.1 PEM Export | ^ Import/Export | 12.3 PKCS#7 Chain -> »

—- Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional

Zuletzt geändert: on 2026/01/30 at 12:28 AM

Powered by DokuWiki