Patch1
All checks were successful
release-tag / release-image (push) Successful in 1m45s

This commit is contained in:
jbergner
2025-04-29 15:02:54 +02:00
parent 08f1c19bc3
commit 1c4e736a6d

51
main.go
View File

@@ -421,60 +421,69 @@ type jwsPayload struct {
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// JWS verification helper supports both JSON & compact JWS formats // verifyJWS akzeptiert JSON- und Compact-Serialisierung ohne Base64-Gefrickel
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
func (s *server) verifyJWS(ctx context.Context, w http.ResponseWriter, r *http.Request) (*jwsPayload, bool) { func (s *server) verifyJWS(ctx context.Context, w http.ResponseWriter, r *http.Request) (*jwsPayload, bool) {
if !jwsVerify { lg := slog.New(slog.NewJSONHandler(os.Stdout, nil))
slog.SetDefault(lg)
if !jwsVerify { // Signaturprüfung ausgeschaltet (Debug)
data, _ := io.ReadAll(r.Body) data, _ := io.ReadAll(r.Body)
return &jwsPayload{Data: data}, true return &jwsPayload{Data: data}, true
} }
// read full body once body, err := io.ReadAll(r.Body)
raw, err := io.ReadAll(r.Body)
if err != nil { if err != nil {
lg.Error("read body", "http.StatusBadRequest", "")
http.Error(w, "read body", http.StatusBadRequest) http.Error(w, "read body", http.StatusBadRequest)
return nil, false return nil, false
} }
// try JWS JSON first … // ── JSON-Serialisierung versuchen … ───────────────────────────────────────
var sig jose.JSONWebSignature var sig *jose.JSONWebSignature
if err := json.Unmarshal(raw, &sig); err != nil || len(sig.Signatures) == 0 { if err := json.Unmarshal(body, &sig); err == nil && len(sig.Signatures) > 0 {
// … fallback to compact serialization // ok
cp, err2 := jose.ParseSigned(string(raw)) } else if cp, err := jose.ParseSigned(string(body)); err == nil { // … sonst Compact
if err2 != nil { sig = cp
http.Error(w, "bad JWS", http.StatusBadRequest) } else {
return nil, false lg.Error("bad JWS", "http.StatusBadRequest", "")
} http.Error(w, "bad JWS", http.StatusBadRequest)
sig = *cp return nil, false
} }
prot := sig.Signatures[0].Protected // already base-64 decoded // geschützter Header ist schon dekodiert
prot := sig.Signatures[0].Protected // jose.Header
// Nonce replay-protection // Nonce-Replay-Schutz
if !s.db.takeNonce(ctx, prot.Nonce) { if !s.db.takeNonce(ctx, prot.Nonce) {
lg.Error("bad nonce", "http.StatusForbidden", "")
http.Error(w, "bad nonce", http.StatusForbidden) http.Error(w, "bad nonce", http.StatusForbidden)
return nil, false return nil, false
} }
// Resolve verification key // passenden öffentlichen Schlüssel bestimmen
var key *jose.JSONWebKey var key *jose.JSONWebKey
switch { switch {
case prot.JSONWebKey != nil: case prot.JSONWebKey != nil: // inline JWK
key = prot.JSONWebKey key = prot.JSONWebKey
case prot.KeyID != "": case prot.KeyID != "":
if k, err := s.db.accountKey(ctx, path.Base(prot.KeyID)); err == nil { k, err := s.db.accountKey(ctx, path.Base(prot.KeyID))
key = k if err != nil {
} else { lg.Error("unknown kid", "http.StatusUnauthorized", "")
http.Error(w, "unknown kid", http.StatusUnauthorized) http.Error(w, "unknown kid", http.StatusUnauthorized)
return nil, false return nil, false
} }
key = k
default: default:
lg.Error("no verification key", "http.StatusBadRequest", "")
http.Error(w, "no verification key", http.StatusBadRequest) http.Error(w, "no verification key", http.StatusBadRequest)
return nil, false return nil, false
} }
// Signatur prüfen
payload, err := sig.Verify(key) payload, err := sig.Verify(key)
if err != nil { if err != nil {
lg.Error("signature invalid", "http.StatusUnauthorized", "")
http.Error(w, "signature invalid", http.StatusUnauthorized) http.Error(w, "signature invalid", http.StatusUnauthorized)
return nil, false return nil, false
} }