~~NOTOC~~ ====== Szenario 12.2: PFX/PKCS#12 Export ====== **Kategorie:** [[.:start|Import/Export]] \\ **Komplexität:** ⭐⭐⭐ (Mittel) \\ **Voraussetzungen:** Zertifikat mit Private Key \\ **Geschätzte Zeit:** 15-20 Minuten ---- ===== Beschreibung ===== Dieses Szenario beschreibt den **Export und Import im PFX/PKCS#12-Format**. PFX (Personal Information Exchange) ist das Standardformat für Windows und .NET, um Zertifikate zusammen mit Private Keys und optional der Zertifikatskette in einer passwortgeschützten Datei zu speichern. **PFX/PKCS#12 Eigenschaften:** * **Inhalt:** Zertifikat + Private Key + Chain * **Encoding:** Binary (ASN.1/DER) * **Verschlüsselung:** Passwortgeschützt * **Erweiterungen:** .pfx, .p12 ---- ===== Workflow ===== flowchart LR subgraph Input CERT[Zertifikat] KEY[Private Key] CHAIN[Chain] end subgraph PFX["PFX-Datei"] BAG1[Cert Bag] BAG2[Key Bag] BAG3[CA Bags] end CERT --> BAG1 KEY --> BAG2 CHAIN --> BAG3 PFX --> ENC[Verschlüsselt] ---- ===== Code-Beispiel: PFX erstellen ===== using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ; using System.Security.Cryptography.X509Certificates; using var ctx = PqCryptoContext.Initialize(); // Zertifikat und Key laden var cert = ctx.LoadCertificate("server.crt.pem"); var privateKey = ctx.LoadPrivateKey("server.key.pem", "KeyPassword!"); // Zertifikat mit Key kombinieren var certWithKey = ctx.CombineCertificateAndKey(cert, privateKey); // PFX exportieren byte[] pfxBytes = certWithKey.Export(X509ContentType.Pfx, "PfxPassword123!"); File.WriteAllBytes("server.pfx", pfxBytes); Console.WriteLine("PFX erstellt: server.pfx"); ---- ===== Code-Beispiel: PFX mit Chain ===== public class PfxExporter { public byte[] ExportWithChain( X509Certificate2 certificate, X509Certificate2Collection chain, string password, PfxExportOptions options = null) { options ??= PfxExportOptions.Default; using var ctx = PqCryptoContext.Initialize(); // Collection für Export erstellen var exportCollection = new X509Certificate2Collection(); exportCollection.Add(certificate); // Chain hinzufügen (ohne Root, wenn gewünscht) foreach (var caCert in chain) { if (options.IncludeRoot || !IsSelfSigned(caCert)) { exportCollection.Add(caCert); } } // PFX exportieren var pfxBytes = exportCollection.Export(X509ContentType.Pfx, password); Console.WriteLine($"PFX erstellt mit {exportCollection.Count} Zertifikaten"); return pfxBytes; } public void ExportToFile( X509Certificate2 certificate, X509Certificate2Collection chain, string outputPath, string password) { var pfxBytes = ExportWithChain(certificate, chain, password); File.WriteAllBytes(outputPath, pfxBytes); // Berechtigungen setzen (nur Eigentümer) 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-Beispiel: PFX importieren ===== using var ctx = PqCryptoContext.Initialize(); // PFX laden var pfxBytes = File.ReadAllBytes("server.pfx"); var cert = new X509Certificate2( pfxBytes, "PfxPassword123!", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet ); Console.WriteLine($"Subject: {cert.Subject}"); Console.WriteLine($"Hat Private Key: {cert.HasPrivateKey}"); // Private Key extrahieren if (cert.HasPrivateKey) { var privateKey = cert.GetRSAPrivateKey() ?? cert.GetECDsaPrivateKey() ?? (AsymmetricAlgorithm)ctx.GetPqPrivateKey(cert); Console.WriteLine($"Key-Typ: {privateKey.GetType().Name}"); } // Chain aus PFX extrahieren var collection = new X509Certificate2Collection(); collection.Import(pfxBytes, "PfxPassword123!", X509KeyStorageFlags.DefaultKeySet); Console.WriteLine($"Zertifikate in PFX: {collection.Count}"); foreach (var c in collection) { Console.WriteLine($" - {c.Subject}"); } ---- ===== Code-Beispiel: Secure PFX mit AES-256 ===== public class SecurePfxExporter { public byte[] ExportSecure( X509Certificate2 certificate, string password) { // .NET 5+ unterstützt moderne PFX-Verschlüsselung 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-basierter Export für maximale Kompatibilität var pfxBuilder = new Pkcs12Builder(); // Key Bag hinzufügen var keyBag = new Pkcs12KeyBag( privateKey.ExportPkcs8PrivateKey(), skipCopy: false ); // Cert Bag hinzufügen var certBag = new Pkcs12CertBag(certificate); // Safe Contents erstellen var safeContents = new Pkcs12SafeContents(); safeContents.AddBag(keyBag); safeContents.AddBag(certBag); foreach (var caCert in chain) { safeContents.AddBag(new Pkcs12CertBag(caCert)); } // Mit Passwort verschlüsseln pfxBuilder.AddSafeContentsEncrypted( safeContents, password, new PbeParameters( PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, 100000 ) ); pfxBuilder.SealWithMac(password, HashAlgorithmName.SHA256, 100000); return pfxBuilder.Encode(); } } ---- ===== Code-Beispiel: PFX für Windows Certificate Store ===== 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); // Prüfen ob bereits vorhanden var existing = store.Certificates.Find( X509FindType.FindByThumbprint, cert.Thumbprint, validOnly: false ); if (existing.Count > 0) { Console.WriteLine("Zertifikat bereits im Store vorhanden"); return; } store.Add(cert); store.Close(); Console.WriteLine($"Zertifikat installiert: {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($"Zertifikat nicht gefunden: {thumbprint}"); } var cert = certs[0]; if (!cert.HasPrivateKey) { throw new Exception("Zertifikat hat keinen Private Key"); } var pfxBytes = cert.Export(X509ContentType.Pfx, password); File.WriteAllBytes(outputPath, pfxBytes); Console.WriteLine($"PFX exportiert: {outputPath}"); } } ---- ===== PFX mit OpenSSL erstellen ===== # PFX aus PEM-Dateien erstellen openssl pkcs12 -export \ -out server.pfx \ -inkey server.key \ -in server.crt \ -certfile chain.pem \ -passout pass:MyPassword # PFX mit modernem Algorithmus (AES-256) openssl pkcs12 -export \ -out server.pfx \ -inkey server.key \ -in server.crt \ -certfile chain.pem \ -aes256 \ -passout pass:MyPassword # PFX inspizieren openssl pkcs12 -info -in server.pfx -passin pass:MyPassword # PFX entpacken openssl pkcs12 -in server.pfx \ -out combined.pem \ -nodes \ -passin pass:MyPassword ---- ===== Branchenspezifische PFX-Anforderungen ===== ^ Branche ^ Key Storage ^ Export ^ Besonderheit ^ | **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-Zertifikate | ---- ===== Verwandte Szenarien ===== ^ Beziehung ^ Szenario ^ Beschreibung ^ | **Alternative** | [[.:pem_export|12.1 PEM Export]] | Linux-Format | | **Verwandt** | [[.:pkcs7_chain|12.3 PKCS#7 Chain]] | Nur Zertifikate | | **Voraussetzung** | [[de:int:pqcrypt:szenarien:zertifikate:server_cert|3.1 Server-Zertifikat]] | Zertifikat erstellen | ---- << [[.:pem_export|← 12.1 PEM Export]] | [[.:start|↑ Import/Export]] | [[.:pkcs7_chain|12.3 PKCS#7 Chain →]] >> {{tag>szenario import export pfx pkcs12 windows}} ---- //Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//