~~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//