Files
smgw-pki/docs/bsi-compliance.md
2026-05-12 19:25:14 +02:00

142 lines
7.3 KiB
Markdown

# BSI-Konformität
Mapping der Vorgaben aus den BSI-Richtlinien auf die Code-Stellen in diesem
Projekt. Quelle aller Anforderungen: **BSI TR-03129-4**, **BSI TR-03109-1**
und **SM-PKI Certificate Policy**.
## 1. TR-03129-4 — Schnittstelle zur Zertifizierungsstelle
### 1.1 Transportsicherheit (mTLS)
| Anforderung | Code-Stelle |
| ------------------------------------------------------------------ | -------------------------------------- |
| SOAP-Nachrichten enthalten **keine** Auth-Daten. | `builders/soap_req.rs` |
| Autorisierung + Verschlüsselung **ausschließlich** via mTLS. | `adapters/sub_ca.rs` |
| Client-Cert (EMT-Testzertifikat) konfiguriert in `reqwest`. | `SubCaSoapAdapter::new(...)` |
| Server-Cert der CA gegen vertrauten CA-Trust-Store verifiziert. | `SubCaSoapAdapter::new(...)` |
Konkret in `reqwest`:
```rust
reqwest::ClientBuilder::new()
.use_rustls_tls()
.identity(reqwest::Identity::from_pem(client_pem_bundle)?)
.add_root_certificate(reqwest::Certificate::from_pem(ca_pem)?)
.build()?
```
### 1.2 WSDL-Konformität
| Anforderung | Code-Stelle |
| -------------------------------------------------------- | ------------------------- |
| Envelope folgt der offiziellen BSI-WSDL. | `builders/soap_req.rs` |
| Operation `RequestCertificate` mit korrektem Namespace. | `SoapRequestBuilder::build_request_certificate` |
| CSR wird Base64-kodiert im Feld `certReq` übertragen. | dito |
Bewusste Entscheidung: **kein WSDL-Codegen**. Die Surface ist klein,
`quick-xml` reicht; Codegen-Crates für Rust sind unausgereift und brittle.
### 1.3 Asynchrone Callbacks (Polling-Verbot)
| Anforderung | Code-Stelle |
| ------------------------------------------------------ | -------------------------------------------------- |
| `callbackIndicator = callback_possible` im Request. | `SoapRequestBuilder::build_request_certificate` |
| Eindeutige `messageID` pro Anfrage. | `SoapRequestBuilder::message_id` |
| Synchroner Response enthält i.d.R. nur `returnCode`. | `SubCaSoapAdapter::request_certificate` |
| Webhook nimmt das fertige Zertifikat entgegen. | Axum-Handler (folgt; `POST /pki/callback`) |
| Zuordnung Callback → Request über `messageID`. | `StoragePort::save_pending_request` / Lookup |
| Zertifikatskette aus `certificateSeq` extrahieren. | Axum-Handler / `HandleCaCallback` |
**Sicherheitspunkt:** `messageID` allein ist **kein** Trust-Boundary. Der
Callback-Handler muss zusätzlich:
1. mTLS-Client-Cert der CA prüfen.
2. SOAP-Signatur der Nachricht prüfen.
Erst dann darf in der DB nachgeschlagen werden.
### 1.4 Datenfelder
| Feld | Inhalt | Quelle |
| ----------------- | ------------------------------------------ | ----------------------------------- |
| `certReq` | Base64(CSR-DER) — vom HSM erzeugt. | `HsmPort::sign_csr` |
| `messageID` | UUIDv4, persistiert in `pending_requests`. | `SoapRequestBuilder::message_id` |
| `callbackIndicator` | `callback_possible` | `SoapRequestBuilder` |
| `certificateSeq` | Antwort der CA via Callback. | Axum-Handler |
## 2. TR-03109-1 — Initial-Konfiguration
### 2.1 Dateiformat `iconfig.tar`
| Pflicht-Inhalt | Code-Stelle |
| ----------------------------------------------- | ------------------------------------ |
| `iconfig.xml` — Konfiguration. | `builders/iconfig.rs` |
| `iconfig.sig` — XML-DSig über `iconfig.xml`. | `builders/iconfig.rs` + `HsmPort` |
| Beide Dateien in einem Tar-Archiv verpackt. | `builders/iconfig.rs` (Tar-Stufe) |
### 2.2 Inhalt der `iconfig.xml`
Pflichtbestandteile:
- Admin-Zertifikate (öffentliche Teile).
- CA-Zertifikatskette.
- Netzwerkprofil (IP-Access für WAN).
- Kommunikationsprofil (TLS-Admin für WAN-Schnittstelle).
Generierung im `InitialConfigBuilder` via `quick-xml`. Eingangsdaten aus der
Domäne (`Gateway`) bzw. aus Konfig-Files.
### 2.3 Kryptografische Signatur `iconfig.sig`
| Anforderung | Code-Stelle |
| -------------------------------------------------------------------- | ------------------------------------ |
| Signatur mit `GWADM_SIG_PRV` (privater Signaturschlüssel des GWA). | `HsmPort::sign_xml` |
| Schlüssel liegt im HSM; Zugriff via PKCS#11. | `adapters/hsm.rs` (`cryptoki`) |
| Signatur über **kanonische** Bytes (XML-C14N). | `InitialConfigBuilder` |
**Implementierungs-Hinweis (XML-DSig):**
Reines Rust für XML-DSig ist nicht reif. Optionen:
1. `xmlsec1` CLI über `std::process::Command` aus dem Adapter aufrufen
(pragmatischer Start).
2. `libxmlsec1` über FFI binden.
3. C14N + Signatur manuell via `cryptoki` zusammensetzen (fehleranfällig
wegen exakter Canonicalization).
Wir starten mit Option 1 und kapseln das vollständig hinter `HsmPort::sign_xml`,
damit ein späterer Wechsel keinen Domänen-Code anfasst.
## 3. SM-PKI Certificate Policy
### 3.1 Schlüsselspeicherung
| Anforderung | Code-Stelle |
| ------------------------------------------------------------ | ------------------------- |
| Alle Teilnehmer-Schlüssel in HSMs ≥ "Security Level 1". | `adapters/hsm.rs` |
| SoftHSMv2 erfüllt SL1 **nur** für Entwicklung. | siehe Sicherheitshinweis |
In Produktion: zertifiziertes HSM (CC EAL4+) zwingend. Der `HsmPort` bleibt
identisch — nur das Backend tauscht.
### 3.2 Zertifikatslaufzeiten und Rotation
| Anforderung | Code-Stelle |
| -------------------------------------------------------- | ------------------------------------------ |
| Endentitäten/Sub-CAs in der Regel alle 2 Jahre. | Datenmodell `Certificate.not_after` |
| Erneuerung rechtzeitig vor Ablauf (Standard: 30 Tage). | `RenewExpiringCertificates::run(days=30)` |
| Asynchroner `RequestCertificate`-Flow. | siehe §1.3 |
| Testbare Zeitquelle. | `ClockPort` / `SystemClock` |
Das 30-Tage-Fenster ist Default, kein Gesetz — über Config einstellbar.
## 4. Offene Punkte
- Konkrete Werte der BSI-Namespace-URIs und Operationsnamen aus der aktuellen
WSDL-Version müssen in `builders/soap_req.rs` als Konstanten gepflegt
werden, sobald die WSDL aus dem BSI-Repo gezogen ist.
- Schema-Validierung der `iconfig.xml` gegen das BSI-XSD ist offen; sinnvoll
als zusätzlicher Adapter-Check vor dem Signieren.
- mTLS-Server (Axum für Callback) muss Client-Cert-Pinning auf die CA-Cert
durchsetzen — Konfiguration unter [`development.md`](development.md).