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