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