Refactor README.md with localized and detailed guidance

The README.md has been extensively restructured to improve clarity, technical depth, and usability. Key changes include:

- Shifted most sections from English to German for localization.
- Consolidated distributed runbooks into a unified reference for PKCS#11/SoftHSM integration.
- Expanded architecture overview with deployment patterns and runtime paths.
- Replaced PKCS#11 basics with detailed setup instructions and troubleshooting tips.
- Updated runtime configuration examples with security best practices.
- Highlighted implemented services, models, and DTOs in the DI setup.
- Added sections on operational challenges, troubleshooting, and monitoring.
- Introduced an API health endpoint and smoke test recommendations.
- Clarified API behavior for signature metadata to ensure deterministic integration.
- Expanded security guidelines, including key rotation and SSH rollback procedures.
- Added a forward-looking section on potential improvements.
- Retained and updated references to official documentation and tools.

These changes aim to provide a comprehensive, structured, and production-aligned guide for developers and engineers.
This commit is contained in:
2026-10-14 14:47:40 +02:00
parent 6b3622b366
commit 5194d638ac

View File

@@ -1,391 +1,383 @@
# EnvelopeGenerator.Infrastructure.Crypt # EnvelopeGenerator.Infrastructure.Crypt
PKCS#11-based cryptographic infrastructure for FES (Advanced Electronic Signature) workflows. Umfassende technische Dokumentation der PKCS#11/SoftHSM-Integration fuer `EnvelopeGenerator`.
Official references: Dieses Dokument konsolidiert und ersetzt die verteilten Runbooks aus:
- SoftHSMv2 (official): `https://github.com/softhsm/SoftHSMv2` - `pkcs11-proxy-production/README.md`
- OpenSC `pkcs11-tool` docs: `https://github.com/OpenSC/OpenSC/wiki/Using-pkcs11-tool-and-OpenSSL` - `pkcs11-proxy-production/SSH_TEMP_ACCESS_MUST_DO.md`
- PKCS#11 standard overview (OASIS): `https://www.oasis-open.org/committees/pkcs11/` - aeltere Abschnitte in diesem README
Zielgruppe: Senior Developer, Platform Engineers, DevOps, Security Owner.
--- ---
## 1) Scope ## 1. Architekturueberblick
This project is the crypto layer only. ### 1.1 Ziel
- Signs hashes via keys in HSM/SoftHSM. `EnvelopeGenerator.Infrastructure.Crypt` stellt die kryptographische Infrastruktur fuer PDF-Signaturen bereit:
- Reads certificates from HSM/SoftHSM.
- Verifies signatures.
- Exposes abstractions for Application/Server integration.
This project is not: - Signaturerzeugung mit Schluesseln in SoftHSM/PKCS#11
- Zertifikat-Auslese aus Token
- Signaturpruefung auf PDF-Ebene
- Health/Startup-Selbsttest fuer Betriebsfaehigkeit
- a REST API, ### 1.2 Topologie (aktueller Betriebsmodus)
- a UI module,
- a full document orchestration workflow. 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) SoftHSM and PKCS#11 basics ## 2. Linux-Seite: SoftHSM + Proxy Setup
- SoftHSM is a software implementation of an HSM. ### 2.1 Basispakete
- It does not expose REST endpoints.
- Access is via PKCS#11 shared library (`.so`/`.dll`).
- App loads module path and performs PKCS#11 operations.
Supported deployment patterns: Beispiel (Debian/Ubuntu):
1. Direct module (`libsofthsm2.so`, `softhsm2-x64.dll`, etc.) ```bash
2. PKCS#11 proxy module (remote HSM/SoftHSM backend) sudo apt-get update && sudo apt-get install -y softhsm2 opensc p11-kit libengine-pkcs11-openssl
Critical platform rule:
- A Windows process cannot load a Linux `.so` directly.
- `Crypt:Pkcs11:AssetsRootPath` must resolve to a directory that contains the expected native assets for the host OS.
- If `AssetsRootPath` is empty, runtime resolves assets from `AppContext.BaseDirectory`.
---
## 2.1) Windows Server + Linux SoftHSM architecture (decision TODO)
Current business requirement: `EnvelopeGenerator.Server` runs on Windows, SoftHSM runs on Linux.
This repository must use one of the following three paths:
1. Linux signing service (recommended)
- Windows `EnvelopeGenerator.Server` calls HTTPS signing API.
- Linux service performs PKCS#11 operations against SoftHSM.
- Private keys stay on Linux.
2. PKCS#11 proxy bridge
- Windows app loads a Windows PKCS#11 proxy client DLL.
- Proxy forwards operations to Linux-side PKCS#11 endpoint connected to SoftHSM.
3. Local Windows SoftHSM (dev/test only, optional)
- SoftHSM is also installed on Windows.
- App talks to local Windows PKCS#11 module.
TODO - architecture lock-in:
- [ ] Select one path as production standard (`1` is recommended).
- [ ] Document final runtime topology (hosts, ports, TLS, auth).
- [ ] Define where audit metadata (IP/email/phone/device) is stored and signed/linked.
- [ ] Update `SignatureController.Submit` integration contract for FES branch.
- [ ] Add environment-specific runbook for Windows host + Linux HSM operations.
---
## 3) FES flow mapping
- Step 6: hash is sent to HSM signing operation -> `ISignatureProvider`
- Step 7: signature and certificate context are resolved -> `Pkcs11SignatureProvider`, `ICertificateProvider`
- Step 8: PDF embedding + audit trail are completed by upper layers; this project provides crypto primitives
---
## 4) Service surface
Main interfaces:
- `ISignatureProvider`
- `ICertificateProvider`
- `ISignatureVerifier`
- `ICryptographicHealthCheck`
DI entry point:
- `CryptDependencyInjection.AddCryptInfrastructure(...)`
---
## 5) Runtime configuration
Configuration section: `Crypt:Pkcs11`
```json
{
"Crypt": {
"Pkcs11": {
"AssetsRootPath": "E:\\DataFiles\\Digital Data\\EnvelopeGenerator",
"SlotId": 1720207650,
"TokenLabel": "DevToken",
"ProxySocket": "tcp://172.24.12.64:5657",
"UserPin": "***",
"PrivateKeyLabel": "sign-key",
"CertificateLabel": "sign-cert",
"ApplicationName": "signFLOW",
"UseUtcSigningTime": true
}
}
}
``` ```
Security rules: ### 2.2 SoftHSM-Modulpfad pruefen
- Never commit real PINs.
- Use environment variables or secret vault.
- Use test-only tokens for development.
Production naming convention used in this repository:
- Token label: `CompanyProdToken`
- Private key label: `company-sign-key-v1`
- Certificate label: `company-sign-cert-v1`
These names are also exposed as constants in `EnvelopeGenerator.Infrastructure.Crypt/Options/Pkcs11ProviderOptions.cs`.
---
## 6) Test configuration source
Crypt tests read PKCS#11 values from `EnvelopeGenerator.Tests/appsettings.json` under `Crypt:Pkcs11`.
Required keys:
- `Crypt:Pkcs11:AssetsRootPath` (optional; if missing, app base directory is used)
- `Crypt:Pkcs11:SlotId` (or `Crypt:Pkcs11:TokenLabel`)
- `Crypt:Pkcs11:UserPin`
- `Crypt:Pkcs11:PrivateKeyLabel`
- `Crypt:Pkcs11:CertificateLabel`
No environment variable is required for crypt tests in this repository anymore.
---
## 7) Full SoftHSM lifecycle runbook (project scope)
### 7.1 Discover module path
```bash ```bash
ldconfig -p | grep softhsm ldconfig -p | grep softhsm
find /usr -name "libsofthsm2.so" 2>/dev/null find /usr -name "libsofthsm2.so" 2>/dev/null
``` ```
### 7.2 List slots/tokens ### 2.3 Token initialisieren
```bash ```bash
softhsm2-util --show-slots softhsm2-util --show-slots
softhsm2-util --init-token --slot <uninitialized-slot> --label CompanyProdToken --so-pin <so-pin> --pin <user-pin>
softhsm2-util --show-slots
``` ```
### 7.3 Create new token (recommended for new company/test tenant) Hinweis: Nach `--init-token` wird der Slot i. d. R. neu zugewiesen.
### 2.4 Schluesselpaar erzeugen
```bash ```bash
softhsm2-util --init-token --slot <uninitialized-slot> --label <token-label> --so-pin <so-pin> --pin <user-pin> 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
``` ```
Important: ### 2.5 Zertifikat importieren
- After init, token is reassigned to a new slot id. ```bash
- Re-run `--show-slots` and use the new slot id. 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
```
### 7.4 Login and inspect objects ### 2.6 Objektzustand verifizieren
```bash ```bash
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
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot <slot-id> --login --pin <user-pin> --list-objects --type cert
``` ```
### 7.5 Generate company signing key pair ### 2.7 Proxy-Daemon endpoint stabilisieren
Ein wiederkehrendes Betriebsproblem war ein zufaelliger/local-only Listener. Fix:
```bash ```bash
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot <slot-id> --login --pin <user-pin> \ sudo mkdir -p /etc/systemd/system/pkcs11-proxy.service.d
--keypairgen --key-type rsa:3072 --label sign-key --id 01 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
``` ```
### 7.6 Import company certificate Pruefung:
```bash ```bash
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot <slot-id> --login --pin <user-pin> \ systemctl show pkcs11-proxy.service -p Environment --no-pager
--write-object company-sign-cert.der --type cert --label sign-cert --id 01 ss -ltnp | grep 5657
```
### 7.7 Read object metadata (for diagnostics)
```bash
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-mechanisms
```
### 7.8 Update operations
PKCS#11 objects are usually immutable for key/cert payload; updates are done by rotation:
1. Create/import new key/cert with new label or id.
2. Update app config/env labels.
3. Validate with integration tests.
4. Delete old objects when safe.
PIN operations:
- User PIN change (while logged in):
```bash
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot <slot-id> --login --pin <old-user-pin> --change-pin --new-pin <new-user-pin>
```
- User PIN reset via SO credentials:
```bash
softhsm2-util --init-pin --slot <slot-id> --so-pin <so-pin> --pin <new-user-pin>
```
### 7.9 Delete operations
Delete by label/id/type:
```bash
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot <slot-id> --login --pin <user-pin> \
--delete-object --type cert --label sign-cert
```
Token-level destructive reset (do not use unless approved):
```bash
softhsm2-util --delete-token --token <token-label>
``` ```
--- ---
## 8) New company onboarding checklist ## 3. Web-API/Server-Seite: Installation und Asset-Bereitstellung
For company-level signing model (one company key/cert pair): ### 3.1 Bezugsquellen der Windows-Artefakte
1. Create token with company label (or assign dedicated token in remote HSM). Fuer den Proxy-Betrieb werden auf Windows benoetigt:
2. Generate key pair in token.
3. Obtain CA certificate and import into token. 1. Proxy-PKCS#11-DLL (`libpkcs11-proxy.dll`)
4. Record secure runtime values: 2. Abhaengige Runtime-DLLs (z. B. MinGW runtime, je nach Build)
- module path 3. `pkcs11-tool.exe` + zugehoerige OpenSC-DLLs fuer Fallback
- slot id or token label
- user pin Beschaffung:
- private key label
- certificate label - Build aus derselben `pkcs11-proxy`-Codebasis/Commit wie Linux-Daemon (Kompatibilitaet sicherstellen)
5. Run crypt integration tests. - oder kontrolliert bereitgestellte, intern freigegebene Binaries
6. Store values in vault and wire app environment.
### 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": "<secret>",
"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.
--- ---
## 9) Rotation/update checklist ## 4. Implementierte Services, Modelle, DTOs
1. Create new key/cert (`sign-key-v2`, `sign-cert-v2`). ### 4.1 DI und Startverhalten
2. Configure app env to new labels.
3. Run integration tests. - `AddCryptInfrastructure(...)` in `DependencyInjection/ServiceCollectionExtensions.cs`
4. Deploy. - bindet `Pkcs11Options`
5. Keep old key/cert during grace period. - registriert `IPdfDigitalSignatureService`
6. Remove old key/cert after legal/operational confirmation. - 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=<uuid>;sha256=<hash>`
- 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`
--- ---
## 10) Running tests ## 5. Betriebserfahrungen und Challenges
Before running, configure `EnvelopeGenerator.Tests/appsettings.json` -> `Crypt:Pkcs11` with real Linux SoftHSM values. ### 5.1 Interop vs Tool-Verhalten
Run crypt tests: Beobachtetes Muster in der realen Umgebung:
```bash - `pkcs11-tool` konnte erfolgreich auf Token zugreifen und signieren.
dotnet test "EnvelopeGenerator.Tests/EnvelopeGenerator.Tests.csproj" -f net8.0 --filter "FullyQualifiedName~EnvelopeGenerator.Tests.Application.Crypt" - `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)
--- ---
## 11) Common failures ## 6. Health, Monitoring und Verifikation
- `CKR_PIN_INCORRECT`: wrong user pin for that token. ### 6.1 API Health
- `CRYPT_PROVIDER_UNAVAILABLE`: bad module path or native load issue.
- `CRYPT_SLOT_NOT_FOUND`: wrong slot id or token label. - Endpoint: `GET /api/health/crypt`
- `CRYPT_LOGIN_FAILED`: login failed (pin/token mismatch). - Liefert:
- `CRYPT_KEY_NOT_FOUND`: key label/id mismatch. - `success`, `mode`, `summary`, `interopError`, `toolError`, `checkedAtUtc`
- `CRYPT_CERT_NOT_FOUND`: certificate label/id mismatch.
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
--- ---
## 12) Integration note ## 7. Sicherheits- und Betriebsrichtlinien
Current implementation uses `CKM_SHA256_RSA_PKCS` while caller provides hash bytes. Validate mechanism semantics in your provider/HSM policy. If provider expects raw payload instead of digest for selected mechanism, signing flow must be adjusted. ### 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
--- ---
## 13) Production-first onboarding (single-line checkpoints) ## 8. API-Verhalten bei Signaturmetadaten
This section is the authoritative path for production-style setup (critical documents, FES). Aktueller Standard:
### 13.1 Step 1 - Initialize dedicated company token - `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.
- `CertificationLevel` wird im Controller serverseitig gesetzt (`FormFillingAndAnnotations`), nicht vom Client.
One-line command: Damit ist das Verhalten deterministisch und manipulationsaermer fuer Integrationsclients.
```bash ---
mkdir -p ./fes-prod && cd ./fes-prod && export SO_PIN="$(openssl rand -hex 16)" USER_PIN="$(openssl rand -hex 12)" && softhsm2-util --init-token --slot <uninitialized-slot> --label CompanyProdToken --so-pin "$SO_PIN" --pin "$USER_PIN" && softhsm2-util --show-slots
```
Checkpoint: ## 9. Troubleshooting-Checkliste (praxisnah)
- Token appears as initialized with label `CompanyProdToken`. 1. Erreichbarkeit Linux Proxy:
- SoftHSM reassigns token to a new slot ID; use that slot ID in all next commands. - `Test-NetConnection <linux-host> -Port 5657`
2. Token sichtbar?
- `pkcs11-tool --module <dll> -L -v`
3. Zertifikat lesbar?
- `--read-object --type cert --label <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`
Security note: Wenn Interop scheitert, aber Tool funktioniert:
- Do not print/store PINs in shell history in real production operations. - Betrieb bleibt verfuegbar (Fallback),
- Persist secrets in a vault or protected secret store. - aber Incident/Bug fuer Interop-Kompatibilitaet erfassen.
### 13.2 Step 2 - Generate company signing key pair inside HSM ---
One-line command: ## 10. Ausblick / empfohlene Verbesserungen
```bash 1. Binary Transport statt Base64 bei grossen PDFs in Render/Sign-Pipelines.
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot <company-slot-id> --login --pin "$USER_PIN" --keypairgen --key-type rsa:3072 --label company-sign-key-v1 --id 01 && pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot <company-slot-id> --login --pin "$USER_PIN" --list-objects 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.
Checkpoint: ---
- `Private Key Object` and `Public Key Object` exist for label `company-sign-key-v1`, id `01`. ## 11. Referenzen
- Private key remains non-extractable in token.
### 13.3 Step 3 - Obtain CA-issued certificate for HSM key - SoftHSMv2: `https://github.com/softhsm/SoftHSMv2`
- OpenSC / pkcs11-tool: `https://github.com/OpenSC/OpenSC/wiki/Using-pkcs11-tool-and-OpenSSL`
Required policy: - PKCS#11 Standard: `https://www.oasis-open.org/committees/pkcs11/`
- Certificate must be issued by enterprise CA for the key generated in token.
- Do not use self-signed cert for production signing identity.
Operational note:
- CSR generation method depends on installed PKCS#11 OpenSSL integration (`engine_pkcs11` / provider).
- After CA issues certificate, import certificate DER into token with matching id/label family.
OpenSSL 3 prerequisite check:
```bash
openssl version && openssl engine -t -c 2>/dev/null | grep -i pkcs11 || true
```
If no PKCS#11 engine/provider is listed, install integration packages first (distribution specific), then continue.
### 13.4 Step 4 - Import CA certificate into token
One-line command:
```bash
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot <company-slot-id> --login --pin "$USER_PIN" --write-object ./company-sign-cert-v1.der --type cert --id 01 --label company-sign-cert-v1 && pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot <company-slot-id> --login --pin "$USER_PIN" --list-objects
```
Checkpoint:
- `Certificate Object` exists with id `01` and expected label.
### 13.5 Step 5 - Wire runtime/test configuration
Server runtime (`EnvelopeGenerator.Server/EnvelopeGenerator.Server/appsettings.json`) must include:
- `Crypt:Pkcs11:AssetsRootPath` = base directory that contains `pkcs11\windows\proxy\libpkcs11-proxy.dll`
- If null/empty, runtime resolves assets from application output (`AppContext.BaseDirectory`)
- `Crypt:Pkcs11:SlotId` = `2021549410` (or current company slot)
- `Crypt:Pkcs11:TokenLabel` = `CompanyProdToken`
- `Crypt:Pkcs11:ProxySocket` = `tcp://172.24.12.64:5657`
- `Crypt:Pkcs11:UserPin` = real user pin
- `Crypt:Pkcs11:PrivateKeyLabel` = `company-sign-key-v1`
- `Crypt:Pkcs11:CertificateLabel` = `company-sign-cert-v1`
Test runtime (`EnvelopeGenerator.Tests/appsettings.json`) must mirror the same `Crypt:Pkcs11` values.
Then run tests:
```bash
dotnet test "EnvelopeGenerator.Tests/EnvelopeGenerator.Tests.csproj" -f net8.0 --filter "FullyQualifiedName~EnvelopeGenerator.Tests.Application.Crypt"
```