~~NOTOC~~ ====== Scenarij 8.2: Podpisovanje kode ====== **Kategorija:** [[.:start|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: * **Avtentikacijo** izdajatelja programske opreme * **Zaščito celovitosti** pred manipulacijo * **Zaupanje** za končne uporabnike * **Skladnost** z varnostnimi smernicami **Podprti formati:** * Windows Authenticode (EXE, DLL, MSI) * PowerShell skripte (.ps1) * NuGet paketi (.nupkg) * Java JAR datoteke * macOS podpis kode ---- ===== 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** | [[sl:int:pqcrypt:szenarien:zertifikate:codesign_cert|3.3 Certifikat za podpisovanje kode]] | Ustvarjanje certifikata | | **Pomembno** | [[.:timestamp|8.3 Časovni žig]] | Dolgoročna veljavnost | | **Povezano** | [[.:signatur_verifizieren|8.4 Verifikacija podpisa]] | Preverjanje | ---- << [[.:dokument_signieren|← 8.1 Podpisovanje dokumentov]] | [[.:start|↑ Pregled podpisov]] | [[.:timestamp|8.3 Časovni žig →]] >> {{tag>scenarij podpis koda authenticode powershell nuget}} ---- //Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//