Neue Tests fuer Archive/Mail/Core-kek (Pruefung 1/2 je Stelle, identisches Muster wie die bereits vorhandenen DMS-Tests). Alle Pruefungen real gegen Postgres auf Host 204 durchgefuehrt (siehe Pruefprotokoll), inkl. vollstaendiger Regression von dms/qa02, internal/kek, internal/ldapsync, internal/webhook. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
5.7 KiB
OPS-13 – Prüfprotokoll: Additional Authenticated Data bei AES-GCM (F-21)
Datum: 2026-09-26. Testhost: 192.168.1.204, Wegwerf-Postgres-Rollen/-Datenbanken (nach jedem Lauf entfernt).
Umgesetzte Änderung
Alle vier in QA-15/F-21 genannten Stellen binden jetzt ein Additional Authenticated Data (AAD) an ihre AES-256-GCM-Chiffretexte:
| Ort | AAD-Quelle |
|---|---|
dms/internal/crypto/envelope.go (WrapDEK/UnwrapDEK/EncryptStream/DecryptStream) |
Tenant-Slug (Service.Seal/Open/NewDataKey/UnwrapDataKey — Signatur unverändert, ~30 externe Aufrufstellen nicht angefasst) |
archive/internal/backupcrypto/envelope.go (WrapDEK/UnwrapDEK, plus direkte seal/open-Aufrufe in file.go) |
Tenant-Slug (RepoPassword/EncryptFile/DecryptFile — bereits vorhandener Parameter) |
mail/internal/crypto/envelope.go (WrapDEK/UnwrapDEK/EncryptStream/DecryptStream, plus kekversions.go) |
Tenant-Slug (Service.Seal/Open/OpenAtVersion, ARC-08-KEK-Versionsverwaltung) |
internal/kek/master.go (wrap/unwrap, EncryptWithTenantKEK/DecryptWithTenantKEK) und internal/kek/store.go (Tenant-KEK-Verpackung durch den Master-Key) |
Tenant-ID (Store.CreateForTenant/GetDecrypted/RotateTenantKEK/RotateMasterKey); für die drei realen externen Aufrufer von EncryptWithTenantKEK/DecryptWithTenantKEK: internal/ldapsync (Tenant-ID + Zweck-Bezeichner), internal/webhook (Ziel-URL des Abonnements), cmd/account-api modulekeys (fester Zweck-Bezeichner, siehe „Bekannte Grenze“ unten) |
Rückwärtskompatibilität: jedes open/unwrap versucht zuerst mit dem neuen AAD, fällt bei Fehlschlag auf kein-AAD zurück. Vor dieser Änderung versiegelte Datensätze bleiben ohne Neuverschlüsselung lesbar.
Akzeptanzkriterien
- Alle vier Stellen binden AAD an ihren Chiffretext — erfüllt, siehe Tabelle oben.
- Simulierter Schlüssel-/Chiffretext-Austausch zwischen zwei Kontexten wird erkannt — erfüllt, siehe Prüfung 1 unten für alle vier Stellen.
- Bereits verschlüsselte Datensätze bleiben lesbar — erfüllt, siehe Prüfung 2 unten.
Prüfungen (real durchgeführt, nicht nur behauptet)
DMS (dms/internal/crypto)
- Prüfung 1 (
TestWrapDEK_AADBindsContext): DEK mit AAD"tenant-a"verpackt, Entpacken mit AAD"tenant-b"liefertErrDecryptFailed. Bestanden. - Prüfung 2 (
TestUnwrapDEK_LegacyWithoutAADStillReadable): mitWrapDEK(kek, dek, nil)versiegelter Alt-Datensatz bleibt mitUnwrapDEK(kek, wrapped, []byte("tenant-a"))lesbar. Bestanden. - Prüfung 3 (Regression): komplette bestehende
internal/crypto-Testsuite (9 Tests) grün,internal/qa02-End-zu-Ende-Suite (6 Tests, echter Postgres, u. a.TestKeyManagement_RewrapKeepsContentReadableWithNewKEKOnly— der realeRewrapDEK-Produktionspfad) grün.
Archive (archive/internal/backupcrypto)
- Prüfung 1 (
TestWrapDEK_AADBindsContext): identisches Muster wie DMS. Bestanden. - Prüfung 2 (
TestUnwrapDEK_LegacyWithoutAADStillReadable): Bestanden. - Prüfung 3 (Regression): 3 Tests grün (Paket hatte zuvor keine eigene Testdatei — neu angelegt, keine Alttests zu brechen).
Mail (mail/internal/crypto)
- Prüfung 1/2: Bestanden (neue
envelope_test.go, gleiches Muster). - Prüfung 3 (Regression, echter Postgres):
TestKEKVersionStore_RecordIfNewDetectsRotationOnly,TestKEKVersionStore_RevokeBlocksOnlyThatVersion,TestRotation_OldArchiveStaysReadableAfterMasterKeyRotation,TestRotation_CompromisedOldKeyCanBeRevoked— alle 4 grün (ARC-08-KEK-Versionsverwaltung nutzt dieselben Primitive, keine Regression durch die AAD-Umstellung inkekversions.go).
Core (internal/kek, internal/ldapsync, internal/webhook, cmd/account-api)
- Prüfung 1/2 (
TestEncryptWithTenantKEK_AADBindsContext,TestDecryptWithTenantKEK_LegacyWithoutAADStillReadable): Bestanden. - Prüfung 3 (Regression, echter Postgres):
internal/kekkomplette Suite (17 Tests, inkl.TestRotateMasterKey_AllTenantKEKsRemainDecryptableWithSamePlaintext,TestRotateTenantKEK_OnlyAffectsThatTenant— beide nutzen die geändertenwrap/unwrap-Aufrufe instore.goreal) grün.internal/ldapsync(8 Tests, inkl.TestConfigStore_WrongTenantKEK_CannotDecrypt) grün.internal/webhook(7 Tests, inkl.TestSubscribe_SecretIsEncryptedAtRest,TestProcessDue_RetriesWithBackoffThenMarksFailed— durchläuft den geänderten Decrypt-Pfad mehrfach mit unterschiedlichen Ziel-URLs) grün.cmd/account-apiBestandstest grün.
Bekannte, dokumentierte Grenze
Diese Kachel bindet AAD an den verfügbaren Kontext (Tenant-Slug/-ID, Ziel-URL, fester Zweck-Bezeichner) — nicht an eine Datensatz-ID. Ein Austausch zwischen zwei Datensätzen desselben Mandanten/Kontexts (z. B. zwei Dokument-Revisionen desselben Tenants) bleibt dadurch unerkannt, da beide dasselbe AAD tragen würden. Eine vollständige Bindung an den einzelnen Datensatz würde eine Datensatz-ID an rund 30 Aufrufstellen in DMS/Mail durchreichen (Service.Seal/Open) bzw. das generische SecretCipher-Interface in internal/moduletrust ändern (betrifft mehrere Module, die dasselbe Interface für Modul-/Sitzungs-Signaturschlüssel nutzen) — beides bewusst außerhalb der "kleinsten Lösung" dieser Kachel. F-21 selbst stuft das Risiko als moderat ein, weil bereits Schreibzugriff auf die Datenbank vorausgesetzt ist; diese Kachel schließt die praktisch bedeutsamste Variante (Kontext-/Mandanten-Verwechslung), nicht die theoretisch verbleibende Variante (Verwechslung innerhalb desselben Kontexts).
Zusammenfassung
Alle Akzeptanzkriterien und Prüfungen bestanden. Keine Regression in den vier betroffenen Modulen (DMS, Archive, Mail, Core) und ihren jeweils sieben echten Aufrufern. Kein Merge, kein Deploy.