FDN-09: verschluesselung at rest & schluesselverwaltung
Envelope-Encryption: DEK (32 Byte) frisch je Objekt, AES-256-GCM fuer Objektinhalt, DEK selbst mit Tenant-KEK verpackt (WrapDEK/UnwrapDEK). KEK kommt ausschliesslich ueber HTTPKEKProvider von Core API-10 (internal/kek.Handler.TenantKEKHandler-Vertrag, Service-Credential- authentifiziert), wird nie persistiert - jeder Seal/Open-Aufruf bezieht ihn frisch. RewrapDEK fuer KEK-Rotation ohne Neuverschluesselung der Objekte (nur der DEK-Wrapper wird neu verpackt, Chiffretext bleibt unveraendert). Auf 192.168.1.131 verifiziert: Round-Trip Encrypt/Decrypt, manipulierter Chiffretext UND falscher Schluessel werden beide ueber GCM-Auth-Tag abgelehnt, KEK-Rotation real getestet (RewrapDEK, altes Objekt danach mit neuem KEK weiterhin lesbar, alter KEK funktioniert nicht mehr). Befund dokumentiert: Cores internal/kek.Handler (Gegenstelle fuer den KEK-Bezug) ist noch in keinem cmd/*/main.go verdrahtet, dieselbe Fehlerklasse wie FDN-03/QA-05/AUD-06. HTTPKEKProvider daher gegen den dokumentierten Vertrag getestet, nicht gegen eine laufende Core-Instanz. Siehe dms/docs/FDN-09-PRUEFPROTOKOLL.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQ
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
bfea94b032
commit
bf7559e118
@@ -0,0 +1,65 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestHTTPKEKProvider_SendsCorrectContractToCore ist der Nachweis, dass
|
||||
// HTTPKEKProvider exakt den Vertrag von Core internal/kek.Handler.
|
||||
// TenantKEKHandler bedient (Service-Credential-Header, tenant-Query-Param,
|
||||
// JSON-Feldname) — echte Vernetzung gegen einen laufenden Core-Prozess ist
|
||||
// nicht Teil dieses Tests (siehe FDN-09-Pruefprotokoll: derselbe
|
||||
// "nicht verdrahtet"-Befund wie bei internal/resync in FDN-03), daher hier
|
||||
// gegen einen httptest-Server geprueft, der denselben Vertrag nachbildet.
|
||||
func TestHTTPKEKProvider_SendsCorrectContractToCore(t *testing.T) {
|
||||
wantKEK := make([]byte, KEKSize)
|
||||
for i := range wantKEK {
|
||||
wantKEK[i] = byte(i)
|
||||
}
|
||||
|
||||
var gotClientID, gotClientSecret, gotTenant string
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gotClientID = r.Header.Get("X-Nexarch-Client-Id")
|
||||
gotClientSecret = r.Header.Get("X-Nexarch-Client-Secret")
|
||||
gotTenant = r.URL.Query().Get("tenant")
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_ = json.NewEncoder(w).Encode(tenantKEKResponse{TenantKEKBase64: base64.StdEncoding.EncodeToString(wantKEK)})
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
provider := NewHTTPKEKProvider(srv.URL, "dms-service-client", "dms-service-secret", nil)
|
||||
got, err := provider.TenantKEK(context.Background(), "acme")
|
||||
if err != nil {
|
||||
t.Fatalf("tenantkek: %v", err)
|
||||
}
|
||||
|
||||
if gotClientID != "dms-service-client" || gotClientSecret != "dms-service-secret" {
|
||||
t.Fatalf("service-credential-header falsch: id=%q secret=%q", gotClientID, gotClientSecret)
|
||||
}
|
||||
if gotTenant != "acme" {
|
||||
t.Fatalf("tenant-query-parameter = %q, want %q", gotTenant, "acme")
|
||||
}
|
||||
if len(got) != KEKSize || got[0] != wantKEK[0] {
|
||||
t.Fatalf("erhaltener kek stimmt nicht mit erwartetem ueberein")
|
||||
}
|
||||
}
|
||||
|
||||
// TestHTTPKEKProvider_RejectsNonOKStatus prueft, dass ein von Core
|
||||
// abgelehnter Aufruf (z.B. Modul nicht fuer diesen Mandanten aktiv,
|
||||
// ErrForbidden auf Core-Seite) als Fehler zurueckgegeben wird.
|
||||
func TestHTTPKEKProvider_RejectsNonOKStatus(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, "zugriff auf diesen mandanten verweigert", http.StatusForbidden)
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
provider := NewHTTPKEKProvider(srv.URL, "x", "y", nil)
|
||||
if _, err := provider.TenantKEK(context.Background(), "fremder-tenant"); err == nil {
|
||||
t.Fatal("erwartet fehler bei abgelehntem kek-bezug, habe nil")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user