Code Signing

Von Boris Sander10. November 2025
Code Signing

Code Signing

„Vertraue niemandem – außer dem, der unterschrieben hat. Und selbst dann..."


Sinn & Zweck

Code Signing ist die digitale Unterschrift für Software. Es beantwortet zwei fundamentale Fragen:

  1. Authentizität: Wer hat diese Software erstellt?
  2. Integrität: Wurde sie seit der Erstellung verändert?

Ohne Code Signing kann jeder behaupten, Software von "Microsoft" oder "Google" zu verteilen. Mit Code Signing gibt es einen kryptografischen Beweis für die Herkunft und Unversehrtheit.


Wie es funktioniert

Der Signing-Prozess

┌─────────────────────────────────────────────────────────────────┐
│                        Entwickler                                │
│  ┌─────────────┐                                                │
│  │  Software   │                                                │
│  │  (Binary)   │                                                │
│  └──────┬──────┘                                                │
│         │                                                        │
│         ↓ Hash (SHA-256)                                        │
│  ┌─────────────┐     ┌──────────────┐                           │
│  │   Hash      │────→│ Private Key  │                           │
│  │  (Digest)   │     │  (geheim!)   │                           │
│  └─────────────┘     └──────┬───────┘                           │
│                             │ Sign                               │
│                             ↓                                    │
│                      ┌─────────────┐                            │
│                      │  Signatur   │                            │
│                      └──────┬──────┘                            │
│                             │                                    │
│                             ↓                                    │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │              Signierte Software                           │   │
│  │  Binary + Signatur + Zertifikat (Public Key)             │   │
│  └──────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘

Die Verifikation

┌─────────────────────────────────────────────────────────────────┐
│                         Endnutzer                                │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │              Signierte Software                           │   │
│  └───────────────────────┬──────────────────────────────────┘   │
│                          │                                       │
│              ┌───────────┴───────────┐                          │
│              ↓                       ↓                          │
│       ┌─────────────┐         ┌─────────────┐                   │
│       │   Binary    │         │  Signatur   │                   │
│       └──────┬──────┘         └──────┬──────┘                   │
│              │ Hash                  │ Decrypt (Public Key)     │
│              ↓                       ↓                          │
│       ┌─────────────┐         ┌─────────────┐                   │
│       │   Hash A    │   ==?   │   Hash B    │                   │
│       └──────┬──────┘         └──────┬──────┘                   │
│              │                       │                          │
│              └───────────┬───────────┘                          │
│                          ↓                                       │
│                    Match? ✓ Valid                                │
│                  No Match? ✗ Tampered!                           │
└─────────────────────────────────────────────────────────────────┘

Arten von Code Signing

Authenticode (Windows)

Für Windows-Executables, DLLs, Treiber, PowerShell-Skripte.

# Signieren mit signtool
signtool sign /f certificate.pfx /p password /tr http://timestamp.digicert.com /td sha256 /fd sha256 myapp.exe

# Verifizieren
signtool verify /pa myapp.exe

macOS Code Signing

Für Apps, Installer, Kernel Extensions.

# Signieren
codesign --sign "Developer ID Application: My Company" --timestamp myapp.app

# Notarisierung (für Gatekeeper)
xcrun notarytool submit myapp.zip --apple-id "dev@example.com" --team-id ABC123

# Verifizieren
codesign --verify --verbose myapp.app
spctl --assess --verbose myapp.app

JAR Signing (Java)

# Keystore erstellen
keytool -genkeypair -alias mykey -keyalg RSA -keysize 2048 -keystore keystore.jks

# JAR signieren
jarsigner -keystore keystore.jks -tsa http://timestamp.digicert.com myapp.jar mykey

# Verifizieren
jarsigner -verify -verbose myapp.jar

GPG/PGP Signing

Für Open-Source-Software, Git Commits, Packages.

# Datei signieren
gpg --detach-sign --armor myfile.tar.gz
# Erzeugt: myfile.tar.gz.asc

# Verifizieren
gpg --verify myfile.tar.gz.asc myfile.tar.gz

Container Image Signing

Mit Cosign (Sigstore):

# Image signieren
cosign sign --key cosign.key registry.example.com/myapp:v1.0.0

# Verifizieren
cosign verify --key cosign.pub registry.example.com/myapp:v1.0.0

Zertifikate & PKI

Zertifikatshierarchie

┌─────────────────────────────────────┐
│         Root CA (Offline)           │
│   DigiCert, Sectigo, GlobalSign     │
└─────────────────┬───────────────────┘
                  │ Signs
                  ↓
┌─────────────────────────────────────┐
│        Intermediate CA              │
│   (mehrere Ebenen möglich)          │
└─────────────────┬───────────────────┘
                  │ Signs
                  ↓
┌─────────────────────────────────────┐
│      End-Entity Certificate         │
│   "My Company" Code Signing Cert    │
└─────────────────────────────────────┘

Zertifikatstypen

TypValidierungVertrauenPreis
OV (Organization Validation)Organisation geprüftMittel€€
EV (Extended Validation)Umfassende PrüfungHoch€€€
Self-SignedKeineKeins (extern)Kostenlos

EV-Zertifikate:

  • Strenge Identitätsprüfung
  • Höheres Vertrauen bei Windows SmartScreen
  • Erforderlich für Kernel-Treiber (Windows)

HSM (Hardware Security Module)

Für maximale Sicherheit: Private Keys in Hardware.

┌─────────────────────────────────────────────┐
│              HSM (Tamper-proof)              │
│  ┌─────────────────────────────────────┐    │
│  │         Private Key                  │    │
│  │    (verlässt HSM nie!)              │    │
│  └─────────────────────────────────────┘    │
│                    ↑                         │
│                    │ API Call: "Sign this"   │
│                    │                         │
│  ┌─────────────────────────────────────┐    │
│  │         Signing Operations           │    │
│  │    (passiert komplett im HSM)        │    │
│  └─────────────────────────────────────┘    │
└─────────────────────────────────────────────┘

Timestamping

Warum?

Zertifikate laufen ab. Ohne Timestamp ist die Signatur nach Ablauf ungültig.

Mit Timestamp:

"Diese Software wurde am 2024-01-15 signiert,
 als das Zertifikat noch gültig war."

Wie?

# SignTool mit Timestamp
signtool sign /tr http://timestamp.digicert.com /td sha256 myapp.exe

# Jarsigner mit Timestamp
jarsigner -tsa http://timestamp.digicert.com myapp.jar mykey

RFC 3161 Timestamp Server

Kostenlose Optionen:


CI/CD Integration

GitHub Actions

name: Build and Sign
on: [push]

jobs:
  build:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Build
        run: dotnet build -c Release
      
      - name: Sign
        env:
          CERTIFICATE: ${{ secrets.CODE_SIGNING_CERT }}
          PASSWORD: ${{ secrets.CERT_PASSWORD }}
        run: |
          # Zertifikat aus Secret dekodieren
          echo "$CERTIFICATE" | base64 -d > cert.pfx
          
          # Signieren
          signtool sign /f cert.pfx /p "$PASSWORD" /tr http://timestamp.digicert.com /td sha256 /fd sha256 bin/Release/myapp.exe
          
          # Aufräumen
          rm cert.pfx

Azure DevOps mit Azure Key Vault

- task: AzureKeyVault@2
  inputs:
    azureSubscription: 'My Subscription'
    KeyVaultName: 'my-keyvault'
    SecretsFilter: 'code-signing-cert'

- task: DotNetCoreCLI@2
  inputs:
    command: 'build'
    
- task: PowerShell@2
  inputs:
    targetType: 'inline'
    script: |
      $cert = Get-AzKeyVaultCertificate -VaultName "my-keyvault" -Name "code-signing-cert"
      # Sign using Azure SignTool or similar

Sigstore (Keyless Signing)

Keine langlebigen Keys nötig – Identity-basiert:

# Keyless Signing mit OIDC
cosign sign --oidc-issuer https://accounts.google.com myapp.tar.gz

# Verifiziert gegen OIDC-Identität
cosign verify --certificate-identity dev@example.com --certificate-oidc-issuer https://accounts.google.com myapp.tar.gz

Risiken & Angriffe

Gestohlene Private Keys

Beispiele:

  • Stuxnet (gestohlene Realtek/JMicron Zertifikate)
  • SolarWinds (kompromittierter Build-Prozess)
  • ASUS Live Update (2019)

Mitigationen

  1. HSM nutzen – Keys verlassen nie die Hardware
  2. Access Control – Wer kann signieren?
  3. Audit Logging – Jede Signatur protokollieren
  4. Short-lived Certificates – Weniger Zeit für Angreifer
  5. Multi-Person Signing – Separation of Duties

Zertifikatsmissbrauch erkennen

# Certificate Transparency Monitoring
# Überwache, ob jemand Zertifikate für deine Domain beantragt

# Tools:
# - crt.sh
# - Facebook CT Monitor
# - SSLMate Cert Spotter

Best Practices

1. Private Keys schützen

Schlecht:     Private Key auf Developer-Laptop
Besser:       Private Key auf Build-Server (verschlüsselt)
Am besten:    Private Key in HSM

2. Separation of Duties

Developer: Kann Code schreiben
QA: Kann Code testen
Release: Kann signieren
Niemand: Alles alleine

3. Audit Trail

{
  "timestamp": "2024-01-15T10:23:45Z",
  "action": "sign",
  "artifact": "myapp-v1.2.3.exe",
  "hash": "sha256:abc123...",
  "signer": "release-bot@company.com",
  "certificate": "CN=My Company, O=My Company Inc",
  "build_id": "build-12345"
}

4. Revocation planen

Was passiert, wenn der Key kompromittiert wird?

  • Wie schnell kann das Zertifikat widerrufen werden?
  • Wie werden Nutzer informiert?
  • Wie werden betroffene Versionen identifiziert?

5. Timestamping immer nutzen

# Immer mit Timestamp signieren!
signtool sign /tr http://timestamp.digicert.com ...

Plattform-spezifische Anforderungen

Windows

SzenarioAnforderung
User-Mode AppsOV oder EV Zertifikat
SmartScreen TrustEV Zertifikat (schneller)
Kernel-TreiberEV Zertifikat + Microsoft Signatur
UEFI BootloaderMicrosoft-Signatur

macOS

SzenarioAnforderung
App StoreApple Developer ID + App Review
Direct DistributionDeveloper ID + Notarization
Kernel ExtensionsApple approval + Notarization

Linux

SzenarioAnforderung
Distro PackagesDistro GPG Key
Secure BootMOK oder Distro Key
Custom PackagesEigener GPG Key

Tools & Infrastruktur

Signing-Services

ServiceTypKosten
DigiCert ONECloud HSMEnterprise
Azure Key VaultCloud HSMPay-per-use
AWS CloudHSMDedicated HSM$$$
SigstoreKeylessFree
SignPathSaaSSubscription

Lokale Tools

# Windows
signtool.exe (Windows SDK)

# macOS
codesign, notarytool, spctl

# Java
jarsigner, keytool

# Allgemein
gpg, cosign, openssl

Vorteile

Vertrauen

Nutzer wissen, dass die Software wirklich von dir kommt.

Integrität

Manipulation wird sofort erkannt.

Compliance

Viele Anforderungen verlangen signierte Software:

  • PCI-DSS
  • HIPAA
  • Government Standards

Reputation

SmartScreen und Gatekeeper vertrauen signierter Software schneller.

Supply Chain Security

Code Signing ist ein Baustein gegen Supply-Chain-Angriffe.


Fazit

Code Signing ist wie ein Wachssiegel auf einem Brief: Es beweist, von wem er kommt und dass er nicht geöffnet wurde. In einer Welt voller Malware und Supply-Chain-Angriffe ist es keine Option mehr – es ist Pflicht.

Ein unsigniertes Binary ist wie ein anonymer Brief: Niemand weiß, ob man ihm trauen kann.


Weiterführende Ressourcen: