This commit is contained in:
51
main.go
51
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) {
|
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
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user