# 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.md` - `pkcs11-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: 1. Linux hostet SoftHSM + `pkcs11-daemon` (Proxy-Server). 2. Windows hostet `EnvelopeGenerator.Server`. 3. Windows laedt ein Windows-kompatibles Proxy-PKCS#11-Modul (`libpkcs11-proxy.dll`). 4. PKCS#11-Operationen werden ueber Socket (`PKCS11_PROXY_SOCKET`) an Linux weitergeleitet. Wichtig: - Ein Windows-Prozess kann **kein Linux `.so`** direkt 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): ```bash sudo apt-get update && sudo apt-get install -y softhsm2 opensc p11-kit libengine-pkcs11-openssl ``` ### 2.2 SoftHSM-Modulpfad pruefen ```bash ldconfig -p | grep softhsm find /usr -name "libsofthsm2.so" 2>/dev/null ``` ### 2.3 Token initialisieren ```bash softhsm2-util --show-slots softhsm2-util --init-token --slot --label CompanyProdToken --so-pin --pin softhsm2-util --show-slots ``` Hinweis: Nach `--init-token` wird der Slot i. d. R. neu zugewiesen. ### 2.4 Schluesselpaar erzeugen ```bash pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so \ --slot --login --pin \ --keypairgen --key-type rsa:3072 --label company-sign-key-v1 --id 01 ``` ### 2.5 Zertifikat importieren ```bash pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so \ --slot --login --pin \ --write-object ./company-sign-cert-v1.der --type cert --id 01 --label company-sign-cert-v1 ``` ### 2.6 Objektzustand verifizieren ```bash pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot --login --pin --list-objects pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot --login --pin --list-objects --type cert ``` ### 2.7 Proxy-Daemon endpoint stabilisieren Ein wiederkehrendes Betriebsproblem war ein zufaelliger/local-only Listener. Fix: ```bash 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: ```bash 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: 1. Proxy-PKCS#11-DLL (`libpkcs11-proxy.dll`) 2. Abhaengige Runtime-DLLs (z. B. MinGW runtime, je nach Build) 3. `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: 1. **Bundled (Dev/QA, schnelle Reproduzierbarkeit)** - Assets werden mit dem Build ausgeliefert. - `AssetsRootPath = null` -> Aufloesung via `AppContext.BaseDirectory`. 2. **Zentraler Asset-Root (Prod, betriebliche Kontrolle)** - Assets in zentralem Pfad (z. B. `E:\DataFiles\Digital Data\EnvelopeGenerator`). - `AssetsRootPath` in `appsettings.json` auf diesen Root setzen. ### 3.4 Anwendungskonfiguration (`Crypt:Pkcs11`) Beispiel: ```json { "Crypt": { "Pkcs11": { "AssetsRootPath": "E:\\DataFiles\\Digital Data\\EnvelopeGenerator", "SlotId": 2021549410, "TokenLabel": "CompanyProdToken", "ProxySocket": "tcp://172.24.12.64:5657", "UserPin": "", "PrivateKeyLabel": "company-sign-key-v1", "CertificateLabel": "company-sign-cert-v1", "ApplicationName": "signFLOW", "DefaultReason": null, "UseUtcSigningTime": true, "DefaultCertificationLevel": "NoCertification" } } } ``` Sicherheitsregel: - `UserPin` niemals 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(...)` in `DependencyInjection/ServiceCollectionExtensions.cs` - bindet `Pkcs11Options` - registriert `IPdfDigitalSignatureService` - registriert Startup-Self-Test Hosted Service ### 4.2 Konfigurationsmodell - `Pkcs11Options` (`EnvelopeGenerator.Application/Common/Configurations/Pkcs11Options.cs`) - `AssetsRootPath`, `SlotId`, `TokenLabel`, `ProxySocket` - `UserPin`, `PrivateKeyLabel`, `CertificateLabel` - `ApplicationName`, `DefaultReason`, `UseUtcSigningTime`, `DefaultCertificationLevel` - `ResolvedLibraryPath`, `ResolvedToolPath` (Runtime-resolved) ### 4.3 Kernservices 1. `PdfDigitalSignatureService` - Signiert PDF via DevExpress `PdfDeferredSignatureBuilder` - Nutzt `Pkcs11ExternalSigner` fuer externe Signatur - Erzwingt `ApplicationName` aus Config (nicht client-overridable) - Erweitert `Reason` um strukturiertes Metaformat: - `SFMETA:v1;doc=;sha256=` - Parse beim Verify und Mapping in DTO 2. `Pkcs11InteropBootstrap` - Loest Modul-/Toolpfade auf - Setzt `PKCS11_PROXY_SOCKET`/`PKCS11_DAEMON_SOCKET` - PATH-Ergaenzung fuer native Abhaengigkeiten - Warmup via `pkcs11-tool -L` 3. `Pkcs11SessionRunner` - Interop Library-Load mit mehreren Init-Modi (Fallback-Reihenfolge) - Slot-Resolution (`SlotId`/`TokenLabel`) - Session Login/Logout 4. `Pkcs11ToolBridge` - Fallback via Prozessaufruf von `pkcs11-tool` - Cert read und DigestInfo-Signatur 5. `Pkcs11StartupSelfTestHostedService` - Fuehrt beim Start Interop-Probe aus - Fallback-Probe bei Interop-Fehler - Schreibt strukturierten Status ### 4.4 Wichtige Interfaces/DTOs - `IPdfDigitalSignatureService` - `SignPdfAsync(...)`, `CheckPdfSignatureAsync(...)`, `ExtractOriginalPdfAsync(...)` - `IPkcs11SelfTestStatusProvider` - `PdfSignOptionsDto` - `UUID`, `Reason`, `Name`, `Location`, `ContactInfo`, `SigningTime`, `CertificationLevel` - `PdfSignatureCheckResultDto` / `PdfSignatureCheckItemDto` - inklusive `BusinessReason`, `UUID`, `OriginalDocumentSha256` - `Pkcs11SelfTestStatusDto` --- ## 5. Betriebserfahrungen und Challenges ### 5.1 Interop vs Tool-Verhalten Beobachtetes Muster in der realen Umgebung: - `pkcs11-tool` konnte erfolgreich auf Token zugreifen und signieren. - `Pkcs11Interop` scheiterte mit `CKR_FUNCTION_NOT_SUPPORTED` bzw. fehlendem `C_Initialize` Pointer 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_ERROR` bei Socket-/Proxy-Problemen - `CRYPT_PROVIDER_UNAVAILABLE` bei Pfad/ABI/Dependency-Mismatch - `CRYPT_SLOT_NOT_FOUND` bei Slot-/Label-Mismatch - `CKR_PIN_INCORRECT` bei 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-tool` ueber laengere Zeit Warnung triggern. ### 6.2 Smoke-Test (empfohlen vor Release) 1. `GET /api/health/crypt` -> `success=true` 2. `POST /api/PdfSignature/sign` mit Test-PDF 3. `POST /api/PdfSignature/is-signed` 4. Pruefen: - `signed=true` - `allSignaturesCryptographicallyValid=true` - `UUID`/`OriginalDocumentSha256` korrekt 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: ```bash 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: ```bash 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: - `UUID` kommt aus Sign-Input (nullable string). Wenn ungeltig/leer -> neue Guid wird erzeugt. - `Reason` wird intern angereichert mit strukturiertem Meta (`SFMETA:v1`). - `ApplicationName` ist rein serverseitig aus `appsettings` gesetzt. - `SigningTime` ist rein serverseitig und wird automatisch gesetzt (`UseUtcSigningTime=true` => `UtcNow`, sonst lokale Zeit). - `CertificationLevel` wird im Controller serverseitig gesetzt (`FormFillingAndAnnotations`), nicht vom Client. Damit ist das Verhalten deterministisch und manipulationsaermer fuer Integrationsclients. --- ## 9. Troubleshooting-Checkliste (praxisnah) 1. Erreichbarkeit Linux Proxy: - `Test-NetConnection -Port 5657` 2. Token sichtbar? - `pkcs11-tool --module -L -v` 3. Zertifikat lesbar? - `--read-object --type cert --label ` 4. Signatur technisch moeglich? - `--sign -m SHA256-RSA-PKCS ...` 5. App-Health check: - `/api/health/crypt` 6. 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 1. Binary Transport statt Base64 bei grossen PDFs in Render/Sign-Pipelines. 2. Persistente Metriken fuer Fallback-Quote (`interop` vs `tool`). 3. Zertifikatskette/OCSP/CRL Validierung als optionales Policy-Modul. 4. CI-Pruefung auf unsichere SQL-Muster (parallel zum Security-Workstream). 5. 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/`