Szenario 8.2: Code signieren

Kategorie: Digitale Signaturen
Komplexität: ⭐⭐⭐⭐ (Hoch)
Voraussetzungen: Code-Signing-Zertifikat
Geschätzte Zeit: 20-30 Minuten


Beschreibung

Dieses Szenario beschreibt das Signieren von Code und Executables mit Post-Quantum-sicheren Algorithmen. Code Signing ermöglicht:

Unterstützte Formate:


Workflow

flowchart LR CODE[Executable/DLL] --> HASH[Authenticode Hash] HASH --> SIGN[ML-DSA + RSA Signatur] KEY[Code-Signing Key] --> SIGN SIGN --> TS[Timestamp hinzufügen] TSA[TSA Server] --> TS TS --> OUTPUT[Signierte Datei] style SIGN fill:#e8f5e9 style TS fill:#fff3e0


Code-Beispiel: Authenticode Signierung

using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
using System.Security.Cryptography;
 
using var ctx = PqCryptoContext.Initialize();
 
// Code-Signing-Zertifikat und Schlüssel laden
var codeSignCert = ctx.LoadCertificate("codesign.crt.pem");
var codeSignKey = ctx.LoadPrivateKey("codesign.key.pem", "KeyPassword!");
 
// Authenticode-Signatur erstellen
var signatureOptions = new AuthenticodeSignatureOptions
{
    Certificate = codeSignCert,
    PrivateKey = codeSignKey,
    HashAlgorithm = HashAlgorithmName.SHA256,
    TimestampUrl = "http://timestamp.digicert.com",
    TimestampHashAlgorithm = HashAlgorithmName.SHA256,
    Mode = CryptoMode.Hybrid,
    Description = "MyApp - Sichere Anwendung",
    DescriptionUrl = "https://myapp.example.com"
};
 
// EXE signieren
var inputPath = "MyApp.exe";
var outputPath = "MyApp-signed.exe";
 
ctx.SignAuthenticode(inputPath, outputPath, signatureOptions);
 
Console.WriteLine($"Code signiert: {outputPath}");
Console.WriteLine($"  Signer: {codeSignCert.Subject}");
Console.WriteLine($"  Timestamp: {signatureOptions.TimestampUrl}");

Windows SignTool Integration

public class SignToolWrapper
{
    public void Sign(string filePath, string pfxPath, string password, string timestampUrl)
    {
        var process = new Process
        {
            StartInfo = new ProcessStartInfo
            {
                FileName = "signtool.exe",
                Arguments = $"sign " +
                    $"/fd SHA256 " +
                    $"/f \"{pfxPath}\" " +
                    $"/p \"{password}\" " +
                    $"/tr \"{timestampUrl}\" " +
                    $"/td SHA256 " +
                    $"/d \"Signed with PQ-Crypto\" " +
                    $"\"{filePath}\"",
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false
            }
        };
 
        process.Start();
        process.WaitForExit();
 
        if (process.ExitCode != 0)
        {
            var error = process.StandardError.ReadToEnd();
            throw new InvalidOperationException($"SignTool failed: {error}");
        }
 
        Console.WriteLine($"Signiert: {filePath}");
    }
 
    public bool Verify(string filePath)
    {
        var process = new Process
        {
            StartInfo = new ProcessStartInfo
            {
                FileName = "signtool.exe",
                Arguments = $"verify /pa /v \"{filePath}\"",
                RedirectStandardOutput = true,
                UseShellExecute = false
            }
        };
 
        process.Start();
        process.WaitForExit();
 
        return process.ExitCode == 0;
    }
}

PowerShell Script signieren

public class PowerShellSigner
{
    public void SignScript(string scriptPath, X509Certificate2 cert)
    {
        // PowerShell CMS Signatur hinzufügen
        var scriptContent = File.ReadAllText(scriptPath);
 
        // Signatur-Block erstellen
        var signatureBlock = CreatePowerShellSignature(scriptContent, cert);
 
        // Signatur an Script anhängen
        var signedContent = scriptContent + Environment.NewLine + signatureBlock;
        File.WriteAllText(scriptPath, signedContent);
 
        Console.WriteLine($"PowerShell Script signiert: {scriptPath}");
    }
 
    private string CreatePowerShellSignature(string content, X509Certificate2 cert)
    {
        using var ctx = PqCryptoContext.Initialize();
 
        // Hash des Scripts
        var hash = SHA256.HashData(Encoding.UTF8.GetBytes(content));
 
        // CMS Signatur
        var contentInfo = new ContentInfo(hash);
        var signedCms = new SignedCms(contentInfo, true);
        var signer = new CmsSigner(cert);
        signedCms.ComputeSignature(signer);
 
        // Base64-codierter Signatur-Block
        var signatureBase64 = Convert.ToBase64String(signedCms.Encode());
 
        return $@"
# SIG # Begin signature block
# {signatureBase64}
# SIG # End signature block";
    }
}

NuGet Package signieren

public class NuGetSigner
{
    public async Task SignPackage(
        string packagePath,
        X509Certificate2 cert,
        AsymmetricAlgorithm privateKey,
        string timestampUrl)
    {
        using var ctx = PqCryptoContext.Initialize();
 
        // NuGet Package öffnen
        using var package = new ZipArchive(File.Open(packagePath, FileMode.Open), ZipArchiveMode.Update);
 
        // .signature.p7s erstellen
        var signatureEntry = package.CreateEntry(".signature.p7s");
 
        // Package-Hash berechnen (ohne Signatur-Entry)
        var packageHash = ComputePackageHash(package);
 
        // CMS Signatur
        var contentInfo = new ContentInfo(packageHash);
        var signedCms = new SignedCms(contentInfo, true);
        var signer = new CmsSigner(cert)
        {
            DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1"),
            IncludeOption = X509IncludeOption.WholeChain
        };
 
        signedCms.ComputeSignature(signer, mode: CryptoMode.Hybrid);
 
        // Timestamp hinzufügen
        await AddTimestamp(signedCms, timestampUrl);
 
        // Signatur schreiben
        using var signatureStream = signatureEntry.Open();
        signatureStream.Write(signedCms.Encode());
 
        Console.WriteLine($"NuGet Package signiert: {packagePath}");
    }
}

Dual-Signatur (Legacy + PQ)

Für Übergangszeit: Beide Signaturen parallel

public class DualSignature
{
    public void SignWithDualSignature(string exePath, SigningCredentials credentials)
    {
        using var ctx = PqCryptoContext.Initialize();
 
        // 1. Erste Signatur: SHA-1 (für Windows XP/Vista Kompatibilität)
        ctx.SignAuthenticode(exePath, exePath, new AuthenticodeSignatureOptions
        {
            Certificate = credentials.LegacyCert,
            PrivateKey = credentials.LegacyKey,
            HashAlgorithm = HashAlgorithmName.SHA1,
            TimestampUrl = credentials.TimestampUrl,
            AppendSignature = false  // Erste Signatur
        });
 
        // 2. Zweite Signatur: SHA-256 + PQ (für moderne Systeme)
        ctx.SignAuthenticode(exePath, exePath, new AuthenticodeSignatureOptions
        {
            Certificate = credentials.PqCert,
            PrivateKey = credentials.PqKey,
            HashAlgorithm = HashAlgorithmName.SHA256,
            Mode = CryptoMode.Hybrid,
            TimestampUrl = credentials.TimestampUrl,
            AppendSignature = true  // Zweite Signatur anhängen
        });
 
        Console.WriteLine("Dual-Signatur erstellt (SHA-1 + SHA-256/PQ)");
    }
}

Timestamp-Server

Anbieter URL Protokoll
DigiCert http://timestamp.digicert.com RFC 3161
Sectigo http://timestamp.sectigo.com RFC 3161
GlobalSign http://timestamp.globalsign.com RFC 3161
SSL.com http://ts.ssl.com RFC 3161

WICHTIG: Ohne Timestamp ist die Signatur nach Zertifikatsablauf ungültig!


Branchenspezifische Anforderungen

Branche Standard Anforderungen
Windows Authenticode EV-Zertifikat für SmartScreen
Automotive UNECE R156 Firmware-Signierung, HSM
Healthcare DiGAV Qualifizierte Signatur
Industrie IEC 62443 SPS-Firmware

Verwandte Szenarien

Beziehung Szenario Beschreibung
Voraussetzung 3.3 Code-Signing Cert Zertifikat erstellen
Wichtig 8.3 Zeitstempel Langzeit-Gültigkeit
Verwandt 8.4 Signatur verifizieren Prüfung

« ← 8.1 Dokument signieren | ↑ Signaturen-Übersicht | 8.3 Zeitstempel → »


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