Scenarij 8.2: Podpisovanje kode

Kategorija: Digitalni podpisi
Kompleksnost: ⭐⭐⭐⭐ (Visoka)
Predpogoji: Certifikat za podpisovanje kode
Predviden čas: 20-30 minut


Opis

Ta scenarij opisuje podpisovanje kode in izvršljivih datotek s postkvantno varnimi algoritmi. Podpisovanje kode omogoča:

Podprti formati:


Potek dela

flowchart LR CODE[Izvršljiva datoteka/DLL] --> HASH[Authenticode zgoščena vrednost] HASH --> SIGN[ML-DSA + RSA podpis] KEY[Ključ za podpisovanje kode] --> SIGN SIGN --> TS[Dodajanje časovnega žiga] TSA[TSA strežnik] --> TS TS --> OUTPUT[Podpisana datoteka] style SIGN fill:#e8f5e9 style TS fill:#fff3e0


Primer kode: Authenticode podpisovanje

using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
using System.Security.Cryptography;
 
using var ctx = PqCryptoContext.Initialize();
 
// Nalaganje certifikata in ključa za podpisovanje kode
var codeSignCert = ctx.LoadCertificate("codesign.crt.pem");
var codeSignKey = ctx.LoadPrivateKey("codesign.key.pem", "KeyPassword!");
 
// Ustvarjanje Authenticode podpisa
var signatureOptions = new AuthenticodeSignatureOptions
{
    Certificate = codeSignCert,
    PrivateKey = codeSignKey,
    HashAlgorithm = HashAlgorithmName.SHA256,
    TimestampUrl = "http://timestamp.digicert.com",
    TimestampHashAlgorithm = HashAlgorithmName.SHA256,
    Mode = CryptoMode.Hybrid,
    Description = "MyApp - Varna aplikacija",
    DescriptionUrl = "https://myapp.example.com"
};
 
// Podpisovanje EXE
var inputPath = "MyApp.exe";
var outputPath = "MyApp-signed.exe";
 
ctx.SignAuthenticode(inputPath, outputPath, signatureOptions);
 
Console.WriteLine($"Koda podpisana: {outputPath}");
Console.WriteLine($"  Podpisnik: {codeSignCert.Subject}");
Console.WriteLine($"  Časovni žig: {signatureOptions.TimestampUrl}");

Integracija Windows SignTool

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($"Podpisano: {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;
    }
}

Podpisovanje PowerShell skript

public class PowerShellSigner
{
    public void SignScript(string scriptPath, X509Certificate2 cert)
    {
        // Dodajanje PowerShell CMS podpisa
        var scriptContent = File.ReadAllText(scriptPath);
 
        // Ustvarjanje bloka podpisa
        var signatureBlock = CreatePowerShellSignature(scriptContent, cert);
 
        // Pripenjanje podpisa na skripto
        var signedContent = scriptContent + Environment.NewLine + signatureBlock;
        File.WriteAllText(scriptPath, signedContent);
 
        Console.WriteLine($"PowerShell skripta podpisana: {scriptPath}");
    }
 
    private string CreatePowerShellSignature(string content, X509Certificate2 cert)
    {
        using var ctx = PqCryptoContext.Initialize();
 
        // Zgoščena vrednost skripte
        var hash = SHA256.HashData(Encoding.UTF8.GetBytes(content));
 
        // CMS podpis
        var contentInfo = new ContentInfo(hash);
        var signedCms = new SignedCms(contentInfo, true);
        var signer = new CmsSigner(cert);
        signedCms.ComputeSignature(signer);
 
        // Base64-kodiran blok podpisa
        var signatureBase64 = Convert.ToBase64String(signedCms.Encode());
 
        return $@"
# SIG # Begin signature block
# {signatureBase64}
# SIG # End signature block";
    }
}

Podpisovanje NuGet paketa

public class NuGetSigner
{
    public async Task SignPackage(
        string packagePath,
        X509Certificate2 cert,
        AsymmetricAlgorithm privateKey,
        string timestampUrl)
    {
        using var ctx = PqCryptoContext.Initialize();
 
        // Odpiranje NuGet paketa
        using var package = new ZipArchive(File.Open(packagePath, FileMode.Open), ZipArchiveMode.Update);
 
        // Ustvarjanje .signature.p7s
        var signatureEntry = package.CreateEntry(".signature.p7s");
 
        // Izračun zgoščene vrednosti paketa (brez vnosa podpisa)
        var packageHash = ComputePackageHash(package);
 
        // CMS podpis
        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);
 
        // Dodajanje časovnega žiga
        await AddTimestamp(signedCms, timestampUrl);
 
        // Zapisovanje podpisa
        using var signatureStream = signatureEntry.Open();
        signatureStream.Write(signedCms.Encode());
 
        Console.WriteLine($"NuGet paket podpisan: {packagePath}");
    }
}

Dvojni podpis (Legacy + PQ)

Za prehodno obdobje: Oba podpisa vzporedno

public class DualSignature
{
    public void SignWithDualSignature(string exePath, SigningCredentials credentials)
    {
        using var ctx = PqCryptoContext.Initialize();
 
        // 1. Prvi podpis: SHA-1 (za združljivost z Windows XP/Vista)
        ctx.SignAuthenticode(exePath, exePath, new AuthenticodeSignatureOptions
        {
            Certificate = credentials.LegacyCert,
            PrivateKey = credentials.LegacyKey,
            HashAlgorithm = HashAlgorithmName.SHA1,
            TimestampUrl = credentials.TimestampUrl,
            AppendSignature = false  // Prvi podpis
        });
 
        // 2. Drugi podpis: SHA-256 + PQ (za moderne sisteme)
        ctx.SignAuthenticode(exePath, exePath, new AuthenticodeSignatureOptions
        {
            Certificate = credentials.PqCert,
            PrivateKey = credentials.PqKey,
            HashAlgorithm = HashAlgorithmName.SHA256,
            Mode = CryptoMode.Hybrid,
            TimestampUrl = credentials.TimestampUrl,
            AppendSignature = true  // Pripenjanje drugega podpisa
        });
 
        Console.WriteLine("Dvojni podpis ustvarjen (SHA-1 + SHA-256/PQ)");
    }
}

Strežniki za časovne žige

Ponudnik URL Protokol
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

POMEMBNO: Brez časovnega žiga je podpis po poteku certifikata neveljaven!


Panožne zahteve

Panoga Standard Zahteve
Windows Authenticode EV certifikat za SmartScreen
Avtomobilska industrija UNECE R156 Podpisovanje strojne programske opreme, HSM
Zdravstvo DiGAV Kvalificiran podpis
Industrija IEC 62443 PLC strojna programska oprema

Povezani scenariji

Povezava Scenarij Opis
Predpogoj 3.3 Certifikat za podpisovanje kode Ustvarjanje certifikata
Pomembno 8.3 Časovni žig Dolgoročna veljavnost
Povezano 8.4 Verifikacija podpisa Preverjanje

« ← 8.1 Podpisovanje dokumentov | ↑ Pregled podpisov | 8.3 Časovni žig → »


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