The `SigningTime` property has been removed from the `PdfSignOptionsDto` class and related client-side input handling. It is now set automatically on the server side based on the `UseUtcSigningTime` configuration (`UtcNow` or local time). Updated the `PdfDigitalSignatureService` to always set `SigningTime` server-side, ensuring consistent and deterministic behavior. Removed `SigningTime` from the `PdfSignatureController` and adjusted the logic to exclude it from the `signOptions` object. Updated the `README.md` to reflect these changes, clarifying that `SigningTime` is now server-side only. These changes improve security and simplify client integration.
12 KiB
EnvelopeGenerator.Infrastructure.Crypt
Umfassende technische Dokumentation der PKCS#11/SoftHSM-Integration fuer EnvelopeGenerator.
Dieses Dokument konsolidiert und ersetzt die verteilten Runbooks aus:
pkcs11-proxy-production/README.mdpkcs11-proxy-production/SSH_TEMP_ACCESS_MUST_DO.md- aeltere Abschnitte in diesem README
Zielgruppe: Senior Developer, Platform Engineers, DevOps, Security Owner.
1. Architekturueberblick
1.1 Ziel
EnvelopeGenerator.Infrastructure.Crypt stellt die kryptographische Infrastruktur fuer PDF-Signaturen bereit:
- Signaturerzeugung mit Schluesseln in SoftHSM/PKCS#11
- Zertifikat-Auslese aus Token
- Signaturpruefung auf PDF-Ebene
- Health/Startup-Selbsttest fuer Betriebsfaehigkeit
1.2 Topologie (aktueller Betriebsmodus)
Der aktuell implementierte Produktions-nahe Pfad ist:
- Linux hostet SoftHSM +
pkcs11-daemon(Proxy-Server). - Windows hostet
EnvelopeGenerator.Server. - Windows laedt ein Windows-kompatibles Proxy-PKCS#11-Modul (
libpkcs11-proxy.dll). - PKCS#11-Operationen werden ueber Socket (
PKCS11_PROXY_SOCKET) an Linux weitergeleitet.
Wichtig:
- Ein Windows-Prozess kann kein Linux
.sodirekt laden. - Private Keys verbleiben im Token (nicht exportierbar).
1.3 Laufzeitpfade in der Anwendung
Pkcs11InteropBootstrap loest Assets relativ zu Crypt:Pkcs11:AssetsRootPath auf:
- Modul:
pkcs11\windows\proxy\libpkcs11-proxy.dll - Tool-Fallback:
pkcs11\windows\opensc\tools\pkcs11-tool.exe
Wenn AssetsRootPath leer ist, wird AppContext.BaseDirectory verwendet.
2. Linux-Seite: SoftHSM + Proxy Setup
2.1 Basispakete
Beispiel (Debian/Ubuntu):
sudo apt-get update && sudo apt-get install -y softhsm2 opensc p11-kit libengine-pkcs11-openssl
2.2 SoftHSM-Modulpfad pruefen
ldconfig -p | grep softhsm
find /usr -name "libsofthsm2.so" 2>/dev/null
2.3 Token initialisieren
softhsm2-util --show-slots
softhsm2-util --init-token --slot <uninitialized-slot> --label CompanyProdToken --so-pin <so-pin> --pin <user-pin>
softhsm2-util --show-slots
Hinweis: Nach --init-token wird der Slot i. d. R. neu zugewiesen.
2.4 Schluesselpaar erzeugen
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so \
--slot <slot-id> --login --pin <user-pin> \
--keypairgen --key-type rsa:3072 --label company-sign-key-v1 --id 01
2.5 Zertifikat importieren
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so \
--slot <slot-id> --login --pin <user-pin> \
--write-object ./company-sign-cert-v1.der --type cert --id 01 --label company-sign-cert-v1
2.6 Objektzustand verifizieren
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot <slot-id> --login --pin <user-pin> --list-objects
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot <slot-id> --login --pin <user-pin> --list-objects --type cert
2.7 Proxy-Daemon endpoint stabilisieren
Ein wiederkehrendes Betriebsproblem war ein zufaelliger/local-only Listener. Fix:
sudo mkdir -p /etc/systemd/system/pkcs11-proxy.service.d
printf "[Service]\nEnvironment=PKCS11_DAEMON_SOCKET=tcp://0.0.0.0:5657\n" | sudo tee /etc/systemd/system/pkcs11-proxy.service.d/override.conf
sudo systemctl daemon-reload
sudo systemctl restart pkcs11-proxy.service
Pruefung:
systemctl show pkcs11-proxy.service -p Environment --no-pager
ss -ltnp | grep 5657
3. Web-API/Server-Seite: Installation und Asset-Bereitstellung
3.1 Bezugsquellen der Windows-Artefakte
Fuer den Proxy-Betrieb werden auf Windows benoetigt:
- Proxy-PKCS#11-DLL (
libpkcs11-proxy.dll) - Abhaengige Runtime-DLLs (z. B. MinGW runtime, je nach Build)
pkcs11-tool.exe+ zugehoerige OpenSC-DLLs fuer Fallback
Beschaffung:
- Build aus derselben
pkcs11-proxy-Codebasis/Commit wie Linux-Daemon (Kompatibilitaet sicherstellen) - oder kontrolliert bereitgestellte, intern freigegebene Binaries
3.2 Empfohlene Ablage im Repo
Bundled Assets liegen unter:
EnvelopeGenerator.Infrastructure.Crypt/resources/pkcs11/windows/proxy/EnvelopeGenerator.Infrastructure.Crypt/resources/pkcs11/windows/opensc/tools/EnvelopeGenerator.Infrastructure.Crypt/resources/pkcs11/windows/opensc/pkcs11/
Diese werden beim Build in den Output kopiert (siehe .csproj-Copy-Regeln).
3.3 Deployment-Muster
Es gibt zwei gueltige Wege:
-
Bundled (Dev/QA, schnelle Reproduzierbarkeit)
- Assets werden mit dem Build ausgeliefert.
AssetsRootPath = null-> Aufloesung viaAppContext.BaseDirectory.
-
Zentraler Asset-Root (Prod, betriebliche Kontrolle)
- Assets in zentralem Pfad (z. B.
E:\DataFiles\Digital Data\EnvelopeGenerator). AssetsRootPathinappsettings.jsonauf diesen Root setzen.
- Assets in zentralem Pfad (z. B.
3.4 Anwendungskonfiguration (Crypt:Pkcs11)
Beispiel:
{
"Crypt": {
"Pkcs11": {
"AssetsRootPath": "E:\\DataFiles\\Digital Data\\EnvelopeGenerator",
"SlotId": 2021549410,
"TokenLabel": "CompanyProdToken",
"ProxySocket": "tcp://172.24.12.64:5657",
"UserPin": "<secret>",
"PrivateKeyLabel": "company-sign-key-v1",
"CertificateLabel": "company-sign-cert-v1",
"ApplicationName": "signFLOW",
"DefaultReason": null,
"UseUtcSigningTime": true,
"DefaultCertificationLevel": "NoCertification"
}
}
}
Sicherheitsregel:
UserPinniemals in versionierte Dateien einchecken.- Secrets nur in Secret Store / nicht versionierte
appsettings.Secrets.json/ Vault.
4. Implementierte Services, Modelle, DTOs
4.1 DI und Startverhalten
AddCryptInfrastructure(...)inDependencyInjection/ServiceCollectionExtensions.cs- bindet
Pkcs11Options - registriert
IPdfDigitalSignatureService - registriert Startup-Self-Test Hosted Service
- bindet
4.2 Konfigurationsmodell
Pkcs11Options(EnvelopeGenerator.Application/Common/Configurations/Pkcs11Options.cs)AssetsRootPath,SlotId,TokenLabel,ProxySocketUserPin,PrivateKeyLabel,CertificateLabelApplicationName,DefaultReason,UseUtcSigningTime,DefaultCertificationLevelResolvedLibraryPath,ResolvedToolPath(Runtime-resolved)
4.3 Kernservices
-
PdfDigitalSignatureService- Signiert PDF via DevExpress
PdfDeferredSignatureBuilder - Nutzt
Pkcs11ExternalSignerfuer externe Signatur - Erzwingt
ApplicationNameaus Config (nicht client-overridable) - Erweitert
Reasonum strukturiertes Metaformat:SFMETA:v1;doc=<uuid>;sha256=<hash>
- Parse beim Verify und Mapping in DTO
- Signiert PDF via DevExpress
-
Pkcs11InteropBootstrap- Loest Modul-/Toolpfade auf
- Setzt
PKCS11_PROXY_SOCKET/PKCS11_DAEMON_SOCKET - PATH-Ergaenzung fuer native Abhaengigkeiten
- Warmup via
pkcs11-tool -L
-
Pkcs11SessionRunner- Interop Library-Load mit mehreren Init-Modi (Fallback-Reihenfolge)
- Slot-Resolution (
SlotId/TokenLabel) - Session Login/Logout
-
Pkcs11ToolBridge- Fallback via Prozessaufruf von
pkcs11-tool - Cert read und DigestInfo-Signatur
- Fallback via Prozessaufruf von
-
Pkcs11StartupSelfTestHostedService- Fuehrt beim Start Interop-Probe aus
- Fallback-Probe bei Interop-Fehler
- Schreibt strukturierten Status
4.4 Wichtige Interfaces/DTOs
IPdfDigitalSignatureServiceSignPdfAsync(...),CheckPdfSignatureAsync(...),ExtractOriginalPdfAsync(...)
IPkcs11SelfTestStatusProviderPdfSignOptionsDtoUUID,Reason,Name,Location,ContactInfo,SigningTime,CertificationLevel
PdfSignatureCheckResultDto/PdfSignatureCheckItemDto- inklusive
BusinessReason,UUID,OriginalDocumentSha256
- inklusive
Pkcs11SelfTestStatusDto
5. Betriebserfahrungen und Challenges
5.1 Interop vs Tool-Verhalten
Beobachtetes Muster in der realen Umgebung:
pkcs11-toolkonnte erfolgreich auf Token zugreifen und signieren.Pkcs11Interopscheiterte mitCKR_FUNCTION_NOT_SUPPORTEDbzw. fehlendemC_InitializePointer in bestimmten Modi.
Konsequenz:
- Architektur wurde auf interop-first + controlled tool-fallback erweitert.
- Health-Endpunkt differenziert Modus (
interop,pkcs11-tool,failed).
5.2 Typische Fehlbilder
CKR_DEVICE_ERRORbei Socket-/Proxy-ProblemenCRYPT_PROVIDER_UNAVAILABLEbei Pfad/ABI/Dependency-MismatchCRYPT_SLOT_NOT_FOUNDbei Slot-/Label-MismatchCKR_PIN_INCORRECTbei PIN-Fehler- 307 Redirects bei HTTP/HTTPS-Mix in manuellen Tests
5.3 Plattformfallen
- MSVC vs MinGW Build-Unterschiede fuer Proxy-Client
- fehlende Laufzeit-DLLs (
PATH/Side-by-side) - Architektur-Mismatch x86 vs x64
- Daemon-Bindings nicht stabil (random localhost port statt fixed endpoint)
6. Health, Monitoring und Verifikation
6.1 API Health
- Endpoint:
GET /api/health/crypt - Liefert:
success,mode,summary,interopError,toolError,checkedAtUtc
Empfehlung:
- In Monitoring aufnehmen und bei
mode=pkcs11-toolueber laengere Zeit Warnung triggern.
6.2 Smoke-Test (empfohlen vor Release)
GET /api/health/crypt->success=truePOST /api/PdfSignature/signmit Test-PDFPOST /api/PdfSignature/is-signed- Pruefen:
signed=trueallSignaturesCryptographicallyValid=trueUUID/OriginalDocumentSha256korrekt gemappt
7. Sicherheits- und Betriebsrichtlinien
7.1 Geheimnisse
- PIN, SO-PIN, Root-Creds niemals in Doku/Screenshots/Repo.
- Nach Troubleshooting: Credentials rotieren.
7.2 Temporare SSH-Freigaben zwingend rueckbauen
Wenn SSH temporaer geoeffnet wurde, MUSS danach Rollback erfolgen:
sudo systemctl disable --now ssh && sudo ufw delete allow from 172.24.10.11 to any port 22 proto tcp && sudo ufw status verbose && sudo systemctl status ssh --no-pager
Optional harte Bereinigung:
sudo apt-get purge -y openssh-server && sudo apt-get autoremove -y
7.3 Schluesselrotation
- Neue Labels (
...-v2) anlegen - App umkonfigurieren
- Sign/Verify Regression testen
- Altmaterial erst nach Freigabe entfernen
8. API-Verhalten bei Signaturmetadaten
Aktueller Standard:
UUIDkommt aus Sign-Input (nullable string). Wenn ungeltig/leer -> neue Guid wird erzeugt.Reasonwird intern angereichert mit strukturiertem Meta (SFMETA:v1).ApplicationNameist rein serverseitig ausappsettingsgesetzt.SigningTimeist rein serverseitig und wird automatisch gesetzt (UseUtcSigningTime=true=>UtcNow, sonst lokale Zeit).CertificationLevelwird im Controller serverseitig gesetzt (FormFillingAndAnnotations), nicht vom Client.
Damit ist das Verhalten deterministisch und manipulationsaermer fuer Integrationsclients.
9. Troubleshooting-Checkliste (praxisnah)
- Erreichbarkeit Linux Proxy:
Test-NetConnection <linux-host> -Port 5657
- Token sichtbar?
pkcs11-tool --module <dll> -L -v
- Zertifikat lesbar?
--read-object --type cert --label <cert-label>
- Signatur technisch moeglich?
--sign -m SHA256-RSA-PKCS ...
- App-Health check:
/api/health/crypt
- App-sign/verify end-to-end:
/api/PdfSignature/sign+/api/PdfSignature/is-signed
Wenn Interop scheitert, aber Tool funktioniert:
- Betrieb bleibt verfuegbar (Fallback),
- aber Incident/Bug fuer Interop-Kompatibilitaet erfassen.
10. Ausblick / empfohlene Verbesserungen
- Binary Transport statt Base64 bei grossen PDFs in Render/Sign-Pipelines.
- Persistente Metriken fuer Fallback-Quote (
interopvstool). - Zertifikatskette/OCSP/CRL Validierung als optionales Policy-Modul.
- CI-Pruefung auf unsichere SQL-Muster (parallel zum Security-Workstream).
- Standardisierte Toast/UX-Rueckmeldungen fuer Signierfehler in UI.
11. Referenzen
- SoftHSMv2:
https://github.com/softhsm/SoftHSMv2 - OpenSC / pkcs11-tool:
https://github.com/OpenSC/OpenSC/wiki/Using-pkcs11-tool-and-OpenSSL - PKCS#11 Standard:
https://www.oasis-open.org/committees/pkcs11/