gematik lib-vau / lib-vau-csharp
VAU-Handshake führt nur 2 von 6 vorgeschriebenen Server-Schlüssel-Prüfungen aus
Beide Referenz-VAU-Clients deserialisieren die SignedPublicVauKeys-Struktur des Servers während Message 2 des Handshakes, lesen aber die Felder für Signatur, Zertifikatskette und OCSP nie aus. Nur Schlüsselformat und Ablauf werden geprüft, sodass ein netzwerkpositionierter MITM eigene ECDH- und Kyber-Public-Keys in Message 2 einschleusen und allen nachfolgenden VAU-Verkehr entschlüsseln oder modifizieren kann.
Beschreibung
gemSpec_Krypt A_24624-01 verlangt vom VAU-Client sechs Prüfschritte auf den SignedPublicVauKeys des Servers während des Handshakes: Zertifikatsketten-Prüfung gegen den TI-PKI-Root, OCSP-Sperrprüfung (max. 24 h), Rollen-OID-Prüfung (oid_epa_vau), ES256-Signaturprüfung über das Schlüsselmaterial, ECC/Kyber-Schlüsselformat-Validierung und Ablaufprüfung (exp > now). Beide Referenzimplementierungen führen nur die letzten beiden aus.
In der Java-Referenzimplementierung (lib-vau) befindet sich die Lücke im Handshake hier:
lib-vau VauClientStateMachine.java:108-120
SignedPublicVauKeys signedPublicVauKeys;try { signedPublicVauKeys = decodeCborMessageToClass( transferredSignedServerPublicKey, SignedPublicVauKeys.class);} catch (Exception e) { throw new IllegalArgumentException( "Could not CBOR decode Signed Server Public Keys...", e);}
VauPublicKeys transferredSignedServerPublicKeyList = signedPublicVauKeys.extractVauKeys();checkCertificateExpired( transferredSignedServerPublicKeyList.getExp());verifyClientMessageIsWellFormed( transferredSignedServerPublicKeyList.getEcdhPublicKey(), transferredSignedServerPublicKeyList);Die Datenklasse SignedPublicVauKeys deserialisiert die relevanten Felder, liest sie aber nie aus:
lib-vau SignedPublicVauKeys.java:45-58
@JsonProperty("signature-ES256")byte[] signatureEs256;
@JsonProperty("cert_hash")byte[] certHash;
@JsonProperty("ocsp_response")byte[] ocspResponse;Die Klasse stellt eine sign()-Methode für die Server-Seite bereit, jedoch keine verify()-Methode, und auch keine Schnittstelle oder Callback, über die Konsumenten eine Prüfung einhängen könnten. Die README erklärt "Es werden keine Zertifikate geprüft." Sie dokumentiert nicht, dass Konsumenten die Prüfung selbst bereitstellen müssen, und auch nicht wie.
Die C#-Referenzimplementierung (lib-vau-csharp) hat dieselbe Form:
lib-vau-csharp VauClientStateMachine.cs:109-113
SignedPublicVauKeys signedPublicVauKeysClient = SignedPublicVauKeys.fromCbor(transferredSignedServerPublicKey);VauPublicKeys transferredSignedServerPublicKeyList = signedPublicVauKeysClient.ExtractVauKeys();KeyUtils.CheckCertificateExpired(transferredSignedServerPublicKeyList.Exp);KeyUtils.VerifyClientMessageIsWellFormed(transferredSignedServerPublicKeyList.EcdhPublicKey, transferredSignedServerPublicKeyList);lib-vau-csharp SignedPublicVauKeys.cs:33-36
readonly byte[] SignatureEs256;readonly byte[] CertHash;readonly byte[] OcspResponse;A_24624-01-Umsetzungsstand über beide Bibliotheken:
| Anforderung | Java | C# |
|---|---|---|
| OCSP-Prüfung (max. 24 h) | Fehlend | Fehlend |
| Zertifikatskette zum TI-PKI-Root | Fehlend | Fehlend |
Rollen-OID oid_epa_vau | Fehlend | Fehlend |
| ES256-Signaturprüfung | Fehlend | Fehlend |
| ECC/Kyber-Schlüsselformat-Validierung | Vorhanden | Vorhanden |
Ablaufprüfung (exp > now) | Vorhanden | Vorhanden |
Konsumenten übernehmen die Referenzimplementierung wie sie ist. Die fehlende Prüfung pflanzt sich in produktive Clients fort: med-united/epa4all bindet lib-vau als Submodul ein und übernimmt die Lücke unverändert, und gematiks offizieller Beispielcode in epa4all-examples (v0.1.6, inzwischen archiviert) ruft receiveMessage2() ohne jeden Schritt zur Server-Schlüssel-Prüfung auf. Siehe Oviva: VAU-Signature-Verification-Bypass.
Auswirkung
- Die innere VAU-Schicht ist dafür konzipiert, Patientendaten gegen die Kompromittierung von TLS-Infrastruktur außerhalb der TEE-Grenze zu schützen. Der Angriff erfordert eine Position auf genau dieser Grenze: dem TI- oder Klinik-Netzwerk-Segment vor dem VAU-Endpunkt.
- Aus dieser Position kann ein netzwerkpositionierter MITM Message 1 des Handshakes abfangen, eine KEM-Encapsulation mit den Schlüsseln des Clients durchführen und mit einer Message 2 antworten, die in der AEAD-Payload angreiferkontrollierte ECDH- und Kyber-Public-Keys trägt. Das Feld
signatureEs256kann beliebige Bytes enthalten. - Da der Client weder Signatur noch Zertifikatskette, OCSP-Antwort oder Rollen-OID prüft, leitet er die Session-Keys aus den Schlüsseln des Angreifers ab. Der MITM hält dann beide Hälften der Sitzung und kann jede nachfolgende VAU-Nachricht im Klartext entschlüsseln und neu verschlüsseln: Medikationsdaten, Diagnoseberichte und Verordnungshistorie einer betroffenen Person, gelesen vom ePA-Client, in das ePA-Backend zurückgeschriebene Dokumente sowie die Autorisierungstransaktionen, die den Zugriff auf die Patientenakte steuern.
Abhilfe
Konsumenten, die eine der Bibliotheken produktiv einsetzen, sollten ein SignedPublicKeysTrustValidator-Interface ergänzen und den Konstruktor von VauClientStateMachine so anpassen, dass er das Interface verpflichtend entgegennimmt. Rufen Sie den Validator in receiveMessage2() vor der KEM-Encapsulation auf. Default-deny: wenn kein Validator bereitgestellt wird, soll der Handshake fehlschlagen. Der Validator sollte die vollständige A_24624-01-Kette durchführen: Zertifikat per cert_hash abrufen, OCSP-Antwort validieren, Kette gegen TI-PKI-Roots prüfen, auf die Rollen-OID oid_epa_vau prüfen und die ES256-Signatur über den signierten Schlüsselblock verifizieren. Verwenden Sie den booleschen Rückgabewert von Signature.verify() (Java) oder VerifyData() (C#); ein verworfener Rückgabewert entspricht keiner Prüfung.
Checkliste für Betreiber
Prüfen, ob Sie lib-vau / lib-vau-csharp ausliefern.
Wenn Ihr ePA-Client (oder irgendein Produkt, das VAU spricht) lib-vau oder lib-vau-csharp direkt, über einen Fork oder über ein Git-Submodul einbindet, betrifft Sie die Lücke. Zwei produktiv ausgelieferte ePA-Implementierungen haben die fehlende Prüfung unverändert übernommen: med-united/epa4all (lib-vau als Git-Submodul) und oviva-ag/epa4all-client (ein Validator wurde ergänzt, aber falsch verdrahtet; siehe CVE-2026-44900).
Einen Trust-Validator mit Default-deny ergänzen.
Der Konstruktor von
VauClientStateMachinemuss verpflichtend einenSignedPublicKeysTrustValidator-Parameter erhalten, der inreceiveMessage2()vor der KEM-Encapsulation aufgerufen wird. Wenn kein Validator bereitgestellt wird, muss der Handshake fehlschlagen und nicht stillschweigend fortgesetzt werden. Ersetzen Sie den bisherigen no-arg-Konstruktor durch einen, der den Validator-Parameter verpflichtend entgegennimmt, und entfernen Sie die no-arg-Form, damit Aufrufer ohne Validator beim Kompilieren scheitern. In C# entsprechend fürVauClientStateMachine().Die vollständige A_24624-01-Kette umsetzen.
Cert-Hash-Lookup, OCSP innerhalb von 24 h, Kette zum TI-PKI-Root, Rollen-OID
oid_epa_vau, ES256-Signaturprüfung über den signierten Schlüsselblock. Alle sechs Prüfungen müssen erfolgreich sein, damit der Handshake fortgesetzt wird. TI-PKI-Root-Zertifikate liegen nicht im Standard-Truststore des Systems; beziehen Sie sie aus der veröffentlichten TI-PKI von gematik (gemSpec_PKI, Anhang zur TI-Root-CA) und pinnen Sie sie explizit in Ihrem Validator.Prüfen, dass der boolesche Rückgabewert gelesen wird.
Sowohl Javas
Signature.verify()als auch C#'sVerifyData()liefern bei ungültiger Signaturfalsezurück, statt eine Exception zu werfen. Ein verworfener Rückgabewert entspricht stillschweigendem Pass. Der Oviva-Vorfall (CVE-2026-44900) ist genau dieser Fall.Den Validator mit einer gefälschten Message 2 prüfen.
Bauen Sie einen lokalen VAU-Gegenpart, der auf Message 1 mit einer Message 2 antwortet, die wohlgeformte, aber nicht signierte öffentliche Schlüssel sowie beliebige Bytes im Feld
signatureEs256enthält. Der Client muss den Handshake ablehnen. Falls nicht, ist der Validator nicht eingehängt.
Bewertung im Detail
Referenzen
- gemSpec_Krypt A_24624-01 (Client-Prüfung der signierten öffentlichen Server-Schlüssel)
- gematik-lib-vau-Repository (Java)
- gematik-lib-vau-csharp-Repository
- gematik-epa4all-examples (archiviert)
- Verwandt: Oviva-epa4all-client-Signaturprüfung verworfen (CVE-2026-44900)
- Verwandt: ePA-VAU-Client-Sicherheit (Übersicht)
So können wir helfen
Wer wir sind
Die Sicherheitsforscher hinter diesem Sicherheitshinweis.

Dr. rer. nat. Simon Weber
Senior Pentester & MedSec-Forscher
Ich evaluiere Ihr SaMD mit derselben branchenprägenden Sicherheitsexpertise, die ich dem BAK MV für die Überarbeitung des B3S-Standards beigetragen habe.
- Promotion über Krankenhaus-Cybersicherheit
- Kritische Schwachstellen in Krankenhaussystemen gefunden
- Alumni der THB MedSec-Forschungsgruppe
- gematik Security Hero

Dipl.-Inf. Volker Schönefeld
Senior Application Security Expert
Als ehemaliger CTO und Entwickler, der zum Pentester wurde, arbeite ich mit Ihrem Team zusammen, um Schwachstellen aufzudecken und Lösungen zu finden, die zu Ihrer Architektur passen.
- 20+ Jahre als CTO, 50+ Mio. App-Downloads
- Architektur und Absicherung großer IoT-Flotten
- Certified Web Exploitation Specialist
- gematik Security Hero
Penetrationstest gesucht?
Machine Spirits ist spezialisiert auf Sicherheitsbewertungen für Medizinprodukte und Gesundheits-IT. Von MDR-Penetrationstests bis C5-Cloud-Compliance helfen wir MedTech-Unternehmen, regulatorische Anforderungen zu erfüllen.
