~~NOTOC~~ ====== Scenarij 12.2: PFX/PKCS#12 izvoz ====== **Kategorija:** [[.:start|Uvoz/Izvoz]] \\ **Kompleksnost:** ⭐⭐⭐ (Srednja) \\ **Predpogoji:** Certifikat z zasebnim ključem \\ **Predviden čas:** 15-20 minut ---- ===== Opis ===== Ta scenarij opisuje **izvoz in uvoz v PFX/PKCS#12 formatu**. PFX (Personal Information Exchange) je standardni format za Windows in .NET za shranjevanje certifikatov skupaj z zasebnimi ključi in opcijsko certifikatno verigo v z geslom zaščiteni datoteki. **Lastnosti PFX/PKCS#12:** * **Vsebina:** Certifikat + zasebni ključ + veriga * **Kodiranje:** Binarno (ASN.1/DER) * **Šifriranje:** Zaščiteno z geslom * **Končnice:** .pfx, .p12 ---- ===== Potek dela ===== flowchart LR subgraph Vhod CERT[Certifikat] KEY[Zasebni ključ] CHAIN[Veriga] end subgraph PFX["PFX datoteka"] BAG1[Cert Bag] BAG2[Key Bag] BAG3[CA Bags] end CERT --> BAG1 KEY --> BAG2 CHAIN --> BAG3 PFX --> ENC[Šifrirano] ---- ===== Primer kode: Ustvarjanje PFX ===== using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ; using System.Security.Cryptography.X509Certificates; using var ctx = PqCryptoContext.Initialize(); // Nalaganje certifikata in ključa var cert = ctx.LoadCertificate("server.crt.pem"); var privateKey = ctx.LoadPrivateKey("server.key.pem", "KeyPassword!"); // Kombinacija certifikata s ključem var certWithKey = ctx.CombineCertificateAndKey(cert, privateKey); // Izvoz PFX byte[] pfxBytes = certWithKey.Export(X509ContentType.Pfx, "PfxPassword123!"); File.WriteAllBytes("server.pfx", pfxBytes); Console.WriteLine("PFX ustvarjen: server.pfx"); ---- ===== Primer kode: PFX z verigo ===== public class PfxExporter { public byte[] ExportWithChain( X509Certificate2 certificate, X509Certificate2Collection chain, string password, PfxExportOptions options = null) { options ??= PfxExportOptions.Default; using var ctx = PqCryptoContext.Initialize(); // Ustvarjanje kolekcije za izvoz var exportCollection = new X509Certificate2Collection(); exportCollection.Add(certificate); // Dodajanje verige (brez Root, če je želeno) foreach (var caCert in chain) { if (options.IncludeRoot || !IsSelfSigned(caCert)) { exportCollection.Add(caCert); } } // Izvoz PFX var pfxBytes = exportCollection.Export(X509ContentType.Pfx, password); Console.WriteLine($"PFX ustvarjen z {exportCollection.Count} certifikati"); return pfxBytes; } public void ExportToFile( X509Certificate2 certificate, X509Certificate2Collection chain, string outputPath, string password) { var pfxBytes = ExportWithChain(certificate, chain, password); File.WriteAllBytes(outputPath, pfxBytes); // Nastavitev dovoljenj (samo lastnik) 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(); } ---- ===== Primer kode: Uvoz PFX ===== using var ctx = PqCryptoContext.Initialize(); // Nalaganje PFX var pfxBytes = File.ReadAllBytes("server.pfx"); var cert = new X509Certificate2( pfxBytes, "PfxPassword123!", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet ); Console.WriteLine($"Subject: {cert.Subject}"); Console.WriteLine($"Ima zasebni ključ: {cert.HasPrivateKey}"); // Ekstrakcija zasebnega ključa if (cert.HasPrivateKey) { var privateKey = cert.GetRSAPrivateKey() ?? cert.GetECDsaPrivateKey() ?? (AsymmetricAlgorithm)ctx.GetPqPrivateKey(cert); Console.WriteLine($"Tip ključa: {privateKey.GetType().Name}"); } // Ekstrakcija verige iz PFX var collection = new X509Certificate2Collection(); collection.Import(pfxBytes, "PfxPassword123!", X509KeyStorageFlags.DefaultKeySet); Console.WriteLine($"Certifikati v PFX: {collection.Count}"); foreach (var c in collection) { Console.WriteLine($" - {c.Subject}"); } ---- ===== Primer kode: Varen PFX z AES-256 ===== public class SecurePfxExporter { public byte[] ExportSecure( X509Certificate2 certificate, string password) { // .NET 5+ podpira moderno PFX šifriranje 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(); // Izvoz temelječ na OpenSSL za maksimalno združljivost var pfxBuilder = new Pkcs12Builder(); // Dodajanje Key Bag var keyBag = new Pkcs12KeyBag( privateKey.ExportPkcs8PrivateKey(), skipCopy: false ); // Dodajanje Cert Bag var certBag = new Pkcs12CertBag(certificate); // Ustvarjanje Safe Contents var safeContents = new Pkcs12SafeContents(); safeContents.AddBag(keyBag); safeContents.AddBag(certBag); foreach (var caCert in chain) { safeContents.AddBag(new Pkcs12CertBag(caCert)); } // Šifriranje z geslom pfxBuilder.AddSafeContentsEncrypted( safeContents, password, new PbeParameters( PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, 100000 ) ); pfxBuilder.SealWithMac(password, HashAlgorithmName.SHA256, 100000); return pfxBuilder.Encode(); } } ---- ===== Primer kode: PFX za 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); // Preverjanje ali že obstaja var existing = store.Certificates.Find( X509FindType.FindByThumbprint, cert.Thumbprint, validOnly: false ); if (existing.Count > 0) { Console.WriteLine("Certifikat že obstaja v shrambi"); return; } store.Add(cert); store.Close(); Console.WriteLine($"Certifikat nameščen: {cert.Subject}"); Console.WriteLine($"Shramba: {storeName} ({location})"); Console.WriteLine($"Prstni odtis: {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($"Certifikat ni najden: {thumbprint}"); } var cert = certs[0]; if (!cert.HasPrivateKey) { throw new Exception("Certifikat nima zasebnega ključa"); } var pfxBytes = cert.Export(X509ContentType.Pfx, password); File.WriteAllBytes(outputPath, pfxBytes); Console.WriteLine($"PFX izvožen: {outputPath}"); } } ---- ===== Ustvarjanje PFX z OpenSSL ===== # Ustvarjanje PFX iz PEM datotek openssl pkcs12 -export \ -out server.pfx \ -inkey server.key \ -in server.crt \ -certfile chain.pem \ -passout pass:MyPassword # PFX z modernim algoritmom (AES-256) openssl pkcs12 -export \ -out server.pfx \ -inkey server.key \ -in server.crt \ -certfile chain.pem \ -aes256 \ -passout pass:MyPassword # Pregled PFX openssl pkcs12 -info -in server.pfx -passin pass:MyPassword # Razpakiranje PFX openssl pkcs12 -in server.pfx \ -out combined.pem \ -nodes \ -passin pass:MyPassword ---- ===== Panožne zahteve za PFX ===== ^ Panoga ^ Hramba ključev ^ Izvoz ^ Posebnost ^ | **Windows Server** | MachineKeySet | Exportable | IIS SSL vezava | | **Azure** | UserKeySet | Non-Exportable | App Service | | **Podpisovanje kode** | MachineKeySet | Non-Exportable | Authenticode | | **Pametna kartica** | Strojna oprema | Non-Exportable | PIV certifikati | ---- ===== Povezani scenariji ===== ^ Povezava ^ Scenarij ^ Opis ^ | **Alternativa** | [[.:pem_export|12.1 PEM izvoz]] | Linux format | | **Povezano** | [[.:pkcs7_chain|12.3 PKCS#7 veriga]] | Samo certifikati | | **Predpogoj** | [[sl:int:pqcrypt:szenarien:zertifikate:server_cert|3.1 Strežniški certifikat]] | Ustvarjanje certifikata | ---- << [[.:pem_export|← 12.1 PEM izvoz]] | [[.:start|↑ Uvoz/Izvoz]] | [[.:pkcs7_chain|12.3 PKCS#7 veriga →]] >> {{tag>scenarij uvoz izvoz pfx pkcs12 windows}} ---- //Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//