~~NOTOC~~ ====== Szenario 12.1: PEM Export/Import ====== **Kategorie:** [[.:start|Import/Export]] \\ **Komplexität:** ⭐⭐ (Niedrig) \\ **Voraussetzungen:** Zertifikat oder Schlüssel \\ **Geschätzte Zeit:** 10-15 Minuten ---- ===== Beschreibung ===== Dieses Szenario beschreibt den **Export und Import im PEM-Format** (Privacy-Enhanced Mail). PEM ist das gängigste Format für Zertifikate und Schlüssel auf Linux/Unix-Systemen und wird von OpenSSL nativ unterstützt. **PEM-Eigenschaften:** * **Encoding:** Base64 mit Header/Footer * **Header:** ''-----BEGIN CERTIFICATE-----'' etc. * **Lesbarkeit:** Textdatei, leicht zu inspizieren * **Verkettung:** Mehrere Objekte in einer Datei möglich ---- ===== PEM-Typen ===== ^ Typ ^ Header ^ Inhalt ^ | Zertifikat | ''BEGIN CERTIFICATE'' | X.509 Zertifikat | | Private Key | ''BEGIN PRIVATE KEY'' | PKCS#8 unverschlüsselt | | Encrypted Key | ''BEGIN ENCRYPTED PRIVATE KEY'' | PKCS#8 verschlüsselt | | RSA Key | ''BEGIN RSA PRIVATE KEY'' | PKCS#1 (legacy) | | CSR | ''BEGIN CERTIFICATE REQUEST'' | PKCS#10 CSR | | CRL | ''BEGIN X509 CRL'' | Certificate Revocation List | ---- ===== Code-Beispiel: Zertifikat als PEM exportieren ===== using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ; using System.Security.Cryptography.X509Certificates; using var ctx = PqCryptoContext.Initialize(); // Zertifikat laden var cert = new X509Certificate2("certificate.pfx", "password"); // Als PEM exportieren ctx.ToPemFile(cert, "certificate.pem"); // Oder als String string pemString = ctx.ToPem(cert); Console.WriteLine(pemString); // Ausgabe: // -----BEGIN CERTIFICATE----- // MIIBkTCB+wIJAK... (Base64) // -----END CERTIFICATE----- ---- ===== Code-Beispiel: Private Key als PEM ===== using var ctx = PqCryptoContext.Initialize(); // Schlüssel generieren using var keyPair = ctx.GenerateKeyPair(PqAlgorithm.MlDsa65); // Unverschlüsseltes PEM (NUR für Tests!) keyPair.ToPemFile("private-key.pem"); // Verschlüsseltes PEM (EMPFOHLEN) keyPair.ToEncryptedPemFile( path: "private-key-encrypted.pem", password: "StrongPassword123!", pbeAlgorithm: PbeAlgorithm.Aes256Cbc, iterations: 100000 ); // Public Key separat keyPair.PublicKey.ToPemFile("public-key.pem"); ---- ===== Code-Beispiel: PEM importieren ===== using var ctx = PqCryptoContext.Initialize(); // Zertifikat aus PEM laden var cert = ctx.LoadCertificate("certificate.pem"); Console.WriteLine($"Subject: {cert.Subject}"); Console.WriteLine($"Gültig bis: {cert.NotAfter:d}"); // Verschlüsselten Private Key laden var privateKey = ctx.LoadPrivateKey( path: "private-key-encrypted.pem", password: "StrongPassword123!" ); // Zertifikat mit Private Key kombinieren var certWithKey = ctx.LoadCertificateWithPrivateKey( certPath: "certificate.pem", keyPath: "private-key-encrypted.pem", keyPassword: "StrongPassword123!" ); Console.WriteLine($"Hat Private Key: {certWithKey.HasPrivateKey}"); ---- ===== Code-Beispiel: Zertifikatskette als PEM ===== public class PemChainExporter { public void ExportChainAsPem( X509Certificate2 endEntity, X509Certificate2Collection chain, string outputPath) { using var ctx = PqCryptoContext.Initialize(); var sb = new StringBuilder(); // End-Entity Zertifikat zuerst sb.AppendLine("# End-Entity Certificate"); sb.AppendLine(ctx.ToPem(endEntity)); // Dann Intermediate CAs foreach (var cert in chain.OrderBy(c => c.NotAfter)) { if (cert.Thumbprint != endEntity.Thumbprint) { sb.AppendLine($"# Intermediate: {cert.Subject}"); sb.AppendLine(ctx.ToPem(cert)); } } File.WriteAllText(outputPath, sb.ToString()); Console.WriteLine($"Chain exportiert: {outputPath}"); } public X509Certificate2Collection ImportChainFromPem(string pemPath) { using var ctx = PqCryptoContext.Initialize(); var pemContent = File.ReadAllText(pemPath); var collection = new X509Certificate2Collection(); // PEM-Blöcke extrahieren var certPattern = @"-----BEGIN CERTIFICATE-----(.*?)-----END CERTIFICATE-----"; var matches = Regex.Matches(pemContent, certPattern, RegexOptions.Singleline); foreach (Match match in matches) { var base64 = match.Groups[1].Value.Trim(); var certBytes = Convert.FromBase64String(base64); collection.Add(new X509Certificate2(certBytes)); } Console.WriteLine($"{collection.Count} Zertifikate importiert"); return collection; } } ---- ===== Code-Beispiel: CSR als PEM ===== using var ctx = PqCryptoContext.Initialize(); // Schlüssel und CSR erstellen using var keyPair = ctx.GenerateKeyPair(PqAlgorithm.MlDsa65); var csr = ctx.CreateCertificateRequest( keyPair, new DnBuilder() .AddCN("www.example.com") .AddO("Example GmbH") .Build() ); // CSR als PEM exportieren string csrPem = ctx.ToPem(csr); File.WriteAllText("request.csr", csrPem); // Ausgabe: // -----BEGIN CERTIFICATE REQUEST----- // MIIBkTCB+wIJAK... (Base64) // -----END CERTIFICATE REQUEST----- ---- ===== Code-Beispiel: CRL als PEM ===== using var ctx = PqCryptoContext.Initialize(); // CRL erstellen var crlBuilder = new CertificateRevocationListBuilder(); // ... Zertifikate hinzufügen ... var crlBytes = crlBuilder.Build(caCert, caKey, crlNumber, nextUpdate); // CRL als PEM exportieren var crlPem = new StringBuilder(); crlPem.AppendLine("-----BEGIN X509 CRL-----"); crlPem.AppendLine(Convert.ToBase64String(crlBytes, Base64FormattingOptions.InsertLineBreaks)); crlPem.AppendLine("-----END X509 CRL-----"); File.WriteAllText("revoked.crl.pem", crlPem.ToString()); // CRL aus PEM laden var crlContent = File.ReadAllText("revoked.crl.pem"); var base64 = Regex.Match(crlContent, @"-----BEGIN X509 CRL-----(.*?)-----END X509 CRL-----", RegexOptions.Singleline).Groups[1].Value.Trim(); var crlData = Convert.FromBase64String(base64); ---- ===== PEM-Konvertierung mit OpenSSL ===== # DER zu PEM konvertieren openssl x509 -in cert.der -inform DER -out cert.pem -outform PEM # PEM zu DER konvertieren openssl x509 -in cert.pem -inform PEM -out cert.der -outform DER # PEM-Zertifikat inspizieren openssl x509 -in cert.pem -text -noout # Private Key verschlüsseln openssl pkcs8 -topk8 -in key.pem -out key-encrypted.pem -aes256 # Private Key entschlüsseln openssl pkcs8 -in key-encrypted.pem -out key.pem ---- ===== Branchenspezifische PEM-Verwendung ===== ^ System ^ PEM-Format ^ Besonderheit ^ | **Apache** | Separate .crt und .key | SSLCertificateFile, SSLCertificateKeyFile | | **Nginx** | Chain in einer .pem | ssl_certificate (fullchain) | | **HAProxy** | Cert + Key in einer Datei | bind ... ssl crt combined.pem | | **OpenSSL** | Alle Formate | Standard-Tool | | **Kubernetes** | Base64-kodiert in Secrets | kubectl create secret tls | ---- ===== Verwandte Szenarien ===== ^ Beziehung ^ Szenario ^ Beschreibung ^ | **Alternative** | [[.:pfx_export|12.2 PFX Export]] | Windows-Format | | **Verwandt** | [[.:pkcs7_chain|12.3 PKCS#7 Chain]] | Nur Zertifikate | | **Verwandt** | [[de:int:pqcrypt:szenarien:schluessel:speicherung|11.2 Schlüsselspeicherung]] | Sichere Aufbewahrung | ---- << [[.:start|← Import/Export-Übersicht]] | [[.:start|↑ Import/Export]] | [[.:pfx_export|12.2 PFX Export →]] >> {{tag>szenario import export pem base64 openssl}} ---- //Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//