~~NOTOC~~ ====== Scenarij 12.3: PKCS#7 izvoz verige ====== **Kategorija:** [[.:start|Uvoz/Izvoz]] \\ **Kompleksnost:** ⭐⭐ (Nizka) \\ **Predpogoji:** Certifikatna veriga \\ **Predviden čas:** 10-15 minut ---- ===== Opis ===== Ta scenarij opisuje **izvoz in uvoz certifikatnih verig v PKCS#7 formatu**. PKCS#7 (tudi CMS - Cryptographic Message Syntax) je idealen za distribucijo certifikatnih verig brez zasebnih ključev. **Lastnosti PKCS#7:** * **Vsebina:** Samo certifikati (brez zasebnih ključev!) * **Uporaba:** Distribucija verig, S/MIME * **Končnice:** .p7b, .p7c * **Kodiranje:** DER (binarno) ali PEM (Base64) ---- ===== Potek dela ===== flowchart TD subgraph Vhod ROOT[Korenski CA] INT[Vmesni CA] EE[Končna entiteta] end subgraph PKCS7["PKCS#7 vsebnik"] CERTS[SignedData.Certificates] end ROOT --> CERTS INT --> CERTS EE --> CERTS PKCS7 --> DER[.p7b binarno] PKCS7 --> PEM[.p7b PEM] ---- ===== Primer kode: Izvoz verige kot PKCS#7 ===== using System.Security.Cryptography.Pkcs; using System.Security.Cryptography.X509Certificates; public class Pkcs7ChainExporter { public byte[] ExportChain(X509Certificate2Collection certificates) { // SignedCms brez podpisa (samo certifikati) var content = new ContentInfo(Array.Empty()); var signedCms = new SignedCms(content, detached: true); // Dodajanje certifikatov foreach (var cert in certificates) { signedCms.Certificates.Add(cert); } // Izvoz kot PKCS#7 (DER) return signedCms.Encode(); } public void ExportToFile( X509Certificate2Collection certificates, string outputPath, bool asPem = false) { var p7bBytes = ExportChain(certificates); if (asPem) { // PEM format var pem = new StringBuilder(); pem.AppendLine("-----BEGIN PKCS7-----"); pem.AppendLine(Convert.ToBase64String(p7bBytes, Base64FormattingOptions.InsertLineBreaks)); pem.AppendLine("-----END PKCS7-----"); File.WriteAllText(outputPath, pem.ToString()); } else { // Binarno (DER) File.WriteAllBytes(outputPath, p7bBytes); } Console.WriteLine($"PKCS#7 izvožen: {outputPath} ({certificates.Count} certifikatov)"); } } ---- ===== Primer kode: Ustvarjanje in izvoz popolne verige ===== using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ; public class FullChainExporter { public void ExportFullChain( X509Certificate2 endEntity, string outputPath) { using var ctx = PqCryptoContext.Initialize(); // Gradnja verige using var chain = new X509Chain(); chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags; chain.Build(endEntity); // Zbiranje vseh certifikatov var collection = new X509Certificate2Collection(); collection.Add(endEntity); foreach (var element in chain.ChainElements) { if (element.Certificate.Thumbprint != endEntity.Thumbprint) { collection.Add(element.Certificate); } } // Izvoz kot PKCS#7 var exporter = new Pkcs7ChainExporter(); exporter.ExportToFile(collection, outputPath); // Izpis podrobnosti Console.WriteLine("Veriga izvožena:"); foreach (var cert in collection) { Console.WriteLine($" [{cert.Thumbprint.Substring(0, 8)}] {cert.Subject}"); } } } ---- ===== Primer kode: Uvoz PKCS#7 ===== public class Pkcs7ChainImporter { public X509Certificate2Collection ImportChain(byte[] p7bBytes) { var collection = new X509Certificate2Collection(); collection.Import(p7bBytes); Console.WriteLine($"{collection.Count} certifikatov uvoženih"); return collection; } public X509Certificate2Collection ImportFromFile(string filePath) { byte[] data; var content = File.ReadAllText(filePath); if (content.Contains("-----BEGIN PKCS7-----")) { // PEM format var base64 = Regex.Match( content, @"-----BEGIN PKCS7-----(.*?)-----END PKCS7-----", RegexOptions.Singleline ).Groups[1].Value.Trim(); data = Convert.FromBase64String(base64); } else { // Binarno (DER) data = File.ReadAllBytes(filePath); } return ImportChain(data); } public void InstallChainToStore( string p7bPath, StoreName storeName = StoreName.CertificateAuthority, StoreLocation location = StoreLocation.LocalMachine) { var certs = ImportFromFile(p7bPath); using var store = new X509Store(storeName, location); store.Open(OpenFlags.ReadWrite); foreach (var cert in certs) { // Preverjanje ali je samopodpisan (Root) var targetStore = cert.Subject == cert.Issuer ? new X509Store(StoreName.Root, location) : store; if (targetStore.Name != store.Name) { targetStore.Open(OpenFlags.ReadWrite); } // Preverjanje ali že obstaja var existing = targetStore.Certificates.Find( X509FindType.FindByThumbprint, cert.Thumbprint, validOnly: false ); if (existing.Count == 0) { targetStore.Add(cert); Console.WriteLine($"Nameščeno: {cert.Subject}"); } if (targetStore.Name != store.Name) { targetStore.Close(); } } store.Close(); } } ---- ===== Primer kode: CA Bundle za spletni strežnik ===== public class CaBundleCreator { public void CreateCaBundle( X509Certificate2 rootCa, X509Certificate2Collection intermediateCas, string outputPath) { var collection = new X509Certificate2Collection(); // Najprej vmesni (najbližji strežniku) foreach (var intermediate in intermediateCas.OrderByDescending(c => c.NotAfter)) { collection.Add(intermediate); } // Korenski na koncu collection.Add(rootCa); var exporter = new Pkcs7ChainExporter(); exporter.ExportToFile(collection, outputPath); Console.WriteLine("CA Bundle ustvarjen:"); Console.WriteLine($" Vmesni: {intermediateCas.Count}"); Console.WriteLine($" Korenski: {rootCa.Subject}"); } public void CreateNginxCaBundle( X509Certificate2 serverCert, X509Certificate2Collection chain, string outputPath) { // Nginx pričakuje PEM verigo (najprej strežnik, nato vmesni) var sb = new StringBuilder(); // Strežniški certifikat sb.AppendLine(ToPem(serverCert)); // Vmesni (ne korenski!) foreach (var cert in chain.Where(c => c.Subject != c.Issuer)) { sb.AppendLine(ToPem(cert)); } File.WriteAllText(outputPath, sb.ToString()); Console.WriteLine($"Nginx CA Bundle: {outputPath}"); } private string ToPem(X509Certificate2 cert) { var sb = new StringBuilder(); sb.AppendLine("-----BEGIN CERTIFICATE-----"); sb.AppendLine(Convert.ToBase64String(cert.RawData, Base64FormattingOptions.InsertLineBreaks)); sb.AppendLine("-----END CERTIFICATE-----"); return sb.ToString(); } } ---- ===== PKCS#7 z OpenSSL ===== # Ustvarjanje PKCS#7 iz več certifikatov openssl crl2pkcs7 -nocrl \ -certfile root-ca.pem \ -certfile intermediate-ca.pem \ -certfile server.pem \ -out chain.p7b \ -outform DER # PKCS#7 kot PEM openssl crl2pkcs7 -nocrl \ -certfile chain.pem \ -out chain.p7b \ -outform PEM # Pregled PKCS#7 openssl pkcs7 -in chain.p7b -print_certs -noout # Ekstrakcija certifikatov iz PKCS#7 openssl pkcs7 -in chain.p7b -print_certs -out extracted.pem # Informacije o PKCS#7 openssl pkcs7 -in chain.p7b -inform DER -text ---- ===== Uporaba v različnih sistemih ===== ^ Sistem ^ Uporaba PKCS#7 ^ Format ^ | **Windows** | Shramba vmesnih CA | .p7b (DER) | | **IIS** | SSL certifikatna veriga | .p7b | | **Java** | Uvoz v Trust Store | .p7b (DER) | | **S/MIME** | E-poštno šifriranje | Del sporočila | | **Podpisovanje kode** | Časovni žig + veriga | Vdelano | ---- ===== Povezani scenariji ===== ^ Povezava ^ Scenarij ^ Opis ^ | **Alternativa** | [[.:pem_export|12.1 PEM izvoz]] | Veriga kot PEM | | **Povezano** | [[.:pfx_export|12.2 PFX izvoz]] | Z zasebnim ključem | | **Predpogoj** | [[sl:int:pqcrypt:szenarien:pki:ca_hierarchie|1.3 CA hierarhija]] | Gradnja verige | | **Povezano** | [[sl:int:pqcrypt:szenarien:validierung:chain_building|5.1 Gradnja verige]] | Validacija verige | ---- << [[.:pfx_export|← 12.2 PFX izvoz]] | [[.:start|↑ Uvoz/Izvoz]] | [[.:interop|12.4 Interoperabilnost →]] >> {{tag>scenarij uvoz izvoz pkcs7 veriga p7b}} ---- //Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//