diff --git a/main.go b/main.go index de0897b..b7c1efd 100644 --- a/main.go +++ b/main.go @@ -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) { - if !jwsVerify { + lg := slog.New(slog.NewJSONHandler(os.Stdout, nil)) + slog.SetDefault(lg) + + if !jwsVerify { // Signaturprüfung ausgeschaltet (Debug) data, _ := io.ReadAll(r.Body) return &jwsPayload{Data: data}, true } - // read full body once - raw, err := io.ReadAll(r.Body) + body, err := io.ReadAll(r.Body) if err != nil { + lg.Error("read body", "http.StatusBadRequest", "") http.Error(w, "read body", http.StatusBadRequest) return nil, false } - // try JWS JSON first … - var sig jose.JSONWebSignature - if err := json.Unmarshal(raw, &sig); err != nil || len(sig.Signatures) == 0 { - // … fallback to compact serialization - cp, err2 := jose.ParseSigned(string(raw)) - if err2 != nil { - http.Error(w, "bad JWS", http.StatusBadRequest) - return nil, false - } - sig = *cp + // ── JSON-Serialisierung versuchen … ─────────────────────────────────────── + var sig *jose.JSONWebSignature + if err := json.Unmarshal(body, &sig); err == nil && len(sig.Signatures) > 0 { + // ok + } else if cp, err := jose.ParseSigned(string(body)); err == nil { // … sonst Compact + sig = cp + } else { + lg.Error("bad JWS", "http.StatusBadRequest", "") + http.Error(w, "bad JWS", http.StatusBadRequest) + 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) { + lg.Error("bad nonce", "http.StatusForbidden", "") http.Error(w, "bad nonce", http.StatusForbidden) return nil, false } - // Resolve verification key + // passenden öffentlichen Schlüssel bestimmen var key *jose.JSONWebKey switch { - case prot.JSONWebKey != nil: + case prot.JSONWebKey != nil: // inline JWK key = prot.JSONWebKey case prot.KeyID != "": - if k, err := s.db.accountKey(ctx, path.Base(prot.KeyID)); err == nil { - key = k - } else { + k, err := s.db.accountKey(ctx, path.Base(prot.KeyID)) + if err != nil { + lg.Error("unknown kid", "http.StatusUnauthorized", "") http.Error(w, "unknown kid", http.StatusUnauthorized) return nil, false } + key = k default: + lg.Error("no verification key", "http.StatusBadRequest", "") http.Error(w, "no verification key", http.StatusBadRequest) return nil, false } + // Signatur prüfen payload, err := sig.Verify(key) if err != nil { + lg.Error("signature invalid", "http.StatusUnauthorized", "") http.Error(w, "signature invalid", http.StatusUnauthorized) return nil, false }