~~NOTOC~~
====== Scenarij 8.2: Potpisivanje koda ======
**Kategorija:** [[.:start|Digitalni potpisi]] \\
**Složenost:** ⭐⭐⭐⭐ (Visoka) \\
**Preduvjeti:** Code-Signing certifikat \\
**Procijenjeno vrijeme:** 20-30 minuta
----
===== Opis =====
Ovaj scenarij opisuje **potpisivanje koda i izvršnih datoteka** s Post-Quantum-sigurnim algoritmima. Code Signing omogućuje:
* **Autentifikaciju** izdavača softvera
* **Zaštitu integriteta** od manipulacije
* **Povjerenje** za krajnje korisnike
* **Usklađenost** sa sigurnosnim smjernicama
**Podržani formati:**
* Windows Authenticode (EXE, DLL, MSI)
* PowerShell Scripts (.ps1)
* NuGet Packages (.nupkg)
* Java JAR Files
* macOS Code Signature
----
===== Tijek rada =====
flowchart LR
CODE[Executable/DLL] --> HASH[Authenticode Hash]
HASH --> SIGN[ML-DSA + RSA Potpis]
KEY[Code-Signing ključ] --> SIGN
SIGN --> TS[Dodavanje vremenske oznake]
TSA[TSA Server] --> TS
TS --> OUTPUT[Potpisana datoteka]
style SIGN fill:#e8f5e9
style TS fill:#fff3e0
----
===== Primjer koda: Authenticode potpisivanje =====
using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
using System.Security.Cryptography;
using var ctx = PqCryptoContext.Initialize();
// Učitavanje Code-Signing certifikata i ključa
var codeSignCert = ctx.LoadCertificate("codesign.crt.pem");
var codeSignKey = ctx.LoadPrivateKey("codesign.key.pem", "KeyPassword!");
// Kreiranje Authenticode potpisa
var signatureOptions = new AuthenticodeSignatureOptions
{
Certificate = codeSignCert,
PrivateKey = codeSignKey,
HashAlgorithm = HashAlgorithmName.SHA256,
TimestampUrl = "http://timestamp.digicert.com",
TimestampHashAlgorithm = HashAlgorithmName.SHA256,
Mode = CryptoMode.Hybrid,
Description = "MyApp - Sigurna aplikacija",
DescriptionUrl = "https://myapp.example.com"
};
// Potpisivanje EXE datoteke
var inputPath = "MyApp.exe";
var outputPath = "MyApp-signed.exe";
ctx.SignAuthenticode(inputPath, outputPath, signatureOptions);
Console.WriteLine($"Kod potpisan: {outputPath}");
Console.WriteLine($" Potpisnik: {codeSignCert.Subject}");
Console.WriteLine($" Vremenska oznaka: {signatureOptions.TimestampUrl}");
----
===== Windows SignTool integracija =====
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 nije uspio: {error}");
}
Console.WriteLine($"Potpisano: {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;
}
}
----
===== Potpisivanje PowerShell skripte =====
public class PowerShellSigner
{
public void SignScript(string scriptPath, X509Certificate2 cert)
{
// Dodavanje PowerShell CMS potpisa
var scriptContent = File.ReadAllText(scriptPath);
// Kreiranje bloka potpisa
var signatureBlock = CreatePowerShellSignature(scriptContent, cert);
// Dodavanje potpisa skripti
var signedContent = scriptContent + Environment.NewLine + signatureBlock;
File.WriteAllText(scriptPath, signedContent);
Console.WriteLine($"PowerShell skripta potpisana: {scriptPath}");
}
private string CreatePowerShellSignature(string content, X509Certificate2 cert)
{
using var ctx = PqCryptoContext.Initialize();
// Hash skripte
var hash = SHA256.HashData(Encoding.UTF8.GetBytes(content));
// CMS potpis
var contentInfo = new ContentInfo(hash);
var signedCms = new SignedCms(contentInfo, true);
var signer = new CmsSigner(cert);
signedCms.ComputeSignature(signer);
// Base64-kodirani blok potpisa
var signatureBase64 = Convert.ToBase64String(signedCms.Encode());
return $@"
# SIG # Begin signature block
# {signatureBase64}
# SIG # End signature block";
}
}
----
===== Potpisivanje NuGet paketa =====
public class NuGetSigner
{
public async Task SignPackage(
string packagePath,
X509Certificate2 cert,
AsymmetricAlgorithm privateKey,
string timestampUrl)
{
using var ctx = PqCryptoContext.Initialize();
// Otvaranje NuGet paketa
using var package = new ZipArchive(File.Open(packagePath, FileMode.Open), ZipArchiveMode.Update);
// Kreiranje .signature.p7s
var signatureEntry = package.CreateEntry(".signature.p7s");
// Izračun hasha paketa (bez unosa potpisa)
var packageHash = ComputePackageHash(package);
// CMS potpis
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);
// Dodavanje vremenske oznake
await AddTimestamp(signedCms, timestampUrl);
// Pisanje potpisa
using var signatureStream = signatureEntry.Open();
signatureStream.Write(signedCms.Encode());
Console.WriteLine($"NuGet paket potpisan: {packagePath}");
}
}
----
===== Dual-Signature (Legacy + PQ) =====
Za prijelazno razdoblje: Oba potpisa paralelno
public class DualSignature
{
public void SignWithDualSignature(string exePath, SigningCredentials credentials)
{
using var ctx = PqCryptoContext.Initialize();
// 1. Prvi potpis: SHA-1 (za Windows XP/Vista kompatibilnost)
ctx.SignAuthenticode(exePath, exePath, new AuthenticodeSignatureOptions
{
Certificate = credentials.LegacyCert,
PrivateKey = credentials.LegacyKey,
HashAlgorithm = HashAlgorithmName.SHA1,
TimestampUrl = credentials.TimestampUrl,
AppendSignature = false // Prvi potpis
});
// 2. Drugi potpis: SHA-256 + PQ (za moderne sustave)
ctx.SignAuthenticode(exePath, exePath, new AuthenticodeSignatureOptions
{
Certificate = credentials.PqCert,
PrivateKey = credentials.PqKey,
HashAlgorithm = HashAlgorithmName.SHA256,
Mode = CryptoMode.Hybrid,
TimestampUrl = credentials.TimestampUrl,
AppendSignature = true // Dodavanje drugog potpisa
});
Console.WriteLine("Dual-Signature kreiran (SHA-1 + SHA-256/PQ)");
}
}
----
===== Timestamp serveri =====
^ Pružatelj ^ 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 |
**VAŽNO:** Bez vremenske oznake potpis postaje nevaljan nakon isteka certifikata!
----
===== Zahtjevi specifični za industriju =====
^ Industrija ^ Standard ^ Zahtjevi ^
| **Windows** | Authenticode | EV certifikat za SmartScreen |
| **Automobilska** | UNECE R156 | Firmware potpisivanje, HSM |
| **Zdravstvo** | DiGAV | Kvalificirani potpis |
| **Industrija** | IEC 62443 | SPS-Firmware |
----
===== Povezani scenariji =====
^ Povezanost ^ Scenarij ^ Opis ^
| **Preduvjet** | [[hr:int:pqcrypt:szenarien:zertifikate:codesign_cert|3.3 Code-Signing Cert]] | Kreiranje certifikata |
| **Važno** | [[.:timestamp|8.3 Vremenska oznaka]] | Dugoročna valjanost |
| **Povezano** | [[.:signatur_verifizieren|8.4 Verifikacija potpisa]] | Provjera |
----
<< [[.:dokument_signieren|← 8.1 Potpisivanje dokumenata]] | [[.:start|↑ Pregled potpisa]] | [[.:timestamp|8.3 Vremenska oznaka →]] >>
{{tag>scenarij potpis kod authenticode powershell nuget}}
----
//Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//