From 1765d55ac67c783cb8ad2b8af42f3bda3873e3ce Mon Sep 17 00:00:00 2001 From: jbergner Date: Tue, 29 Apr 2025 14:15:37 +0200 Subject: [PATCH] =?UTF-8?q?WACS-Kompatibilit=C3=A4t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.go | 55 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/main.go b/main.go index b5d063b..083afa5 100644 --- a/main.go +++ b/main.go @@ -420,45 +420,55 @@ type jwsPayload struct { JWK *jose.JSONWebKey } +// ----------------------------------------------------------------------------- +// JWS verification helper – supports both JSON & compact JWS formats +// ----------------------------------------------------------------------------- func (s *server) verifyJWS(ctx context.Context, w http.ResponseWriter, r *http.Request) (*jwsPayload, bool) { if !jwsVerify { data, _ := io.ReadAll(r.Body) return &jwsPayload{Data: data}, true } - // Decode incoming JWS (JSON serialization expected) + // read full body once + raw, err := io.ReadAll(r.Body) + if err != nil { + http.Error(w, "read body", http.StatusBadRequest) + return nil, false + } + + // try JWS JSON first … var sig jose.JSONWebSignature - if err := json.NewDecoder(r.Body).Decode(&sig); err != nil { - http.Error(w, "bad JWS", http.StatusBadRequest) - return nil, false - } - if len(sig.Signatures) == 0 { - http.Error(w, "no signature", http.StatusBadRequest) - return nil, false + 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 } - prot := sig.Signatures[0].Protected // already decoded in go‑jose v3 + prot := sig.Signatures[0].Protected // already base-64 decoded - // Nonce replay‑protection + // Nonce replay-protection if !s.db.takeNonce(ctx, prot.Nonce) { http.Error(w, "bad nonce", http.StatusForbidden) return nil, false } - // Resolve verification key (inline JWK or referenced by kid) + // Resolve verification key var key *jose.JSONWebKey - if prot.JSONWebKey != nil { + switch { + case prot.JSONWebKey != nil: key = prot.JSONWebKey - } else if prot.KeyID != "" { - id := path.Base(prot.KeyID) // everything after last '/' - k, err := s.db.accountKey(ctx, id) - if err != nil { + case prot.KeyID != "": + if k, err := s.db.accountKey(ctx, path.Base(prot.KeyID)); err == nil { + key = k + } else { http.Error(w, "unknown kid", http.StatusUnauthorized) return nil, false } - key = k - } - if key == nil { + default: http.Error(w, "no verification key", http.StatusBadRequest) return nil, false } @@ -468,7 +478,6 @@ func (s *server) verifyJWS(ctx context.Context, w http.ResponseWriter, r *http.R http.Error(w, "signature invalid", http.StatusUnauthorized) return nil, false } - return &jwsPayload{Data: payload, JWK: key}, true } @@ -489,6 +498,9 @@ func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) { w.Header().Set("Replay-Nonce", n) w.WriteHeader(http.StatusOK) + case r.Method == http.MethodGet && r.URL.Path == "/directory": + s.handleDirectory(w, r) + case r.Method == http.MethodPost && r.URL.Path == "/acme/new-account": s.handleNewAccount(ctx, w, r) @@ -501,9 +513,6 @@ func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) { case r.Method == http.MethodPost && r.URL.Path == "/acme/revoke-cert": s.handleRevoke(ctx, w, r) - case r.Method == http.MethodGet && r.URL.Path == "/acme/directory": - s.handleDirectory(w, r) - case r.Method == http.MethodGet && strings.HasPrefix(r.URL.Path, "/acme/order/"): s.handleGetOrder(ctx, w, r)