Scenarij 12.3: PKCS#7 izvoz verige

Kategorija: 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<byte>());
        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 12.1 PEM izvoz Veriga kot PEM
Povezano 12.2 PFX izvoz Z zasebnim ključem
Predpogoj 1.3 CA hierarhija Gradnja verige
Povezano 5.1 Gradnja verige Validacija verige

« ← 12.2 PFX izvoz | ↑ Uvoz/Izvoz | 12.4 Interoperabilnost → »


Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional

Zuletzt geändert: dne 30.01.2026 ob 06:27