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