WACS-Kompatibilität
All checks were successful
release-tag / release-image (push) Successful in 1m47s
All checks were successful
release-tag / release-image (push) Successful in 1m47s
This commit is contained in:
55
main.go
55
main.go
@@ -420,45 +420,55 @@ type jwsPayload struct {
|
|||||||
JWK *jose.JSONWebKey
|
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) {
|
func (s *server) verifyJWS(ctx context.Context, w http.ResponseWriter, r *http.Request) (*jwsPayload, bool) {
|
||||||
if !jwsVerify {
|
if !jwsVerify {
|
||||||
data, _ := io.ReadAll(r.Body)
|
data, _ := io.ReadAll(r.Body)
|
||||||
return &jwsPayload{Data: data}, true
|
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
|
var sig jose.JSONWebSignature
|
||||||
if err := json.NewDecoder(r.Body).Decode(&sig); err != nil {
|
if err := json.Unmarshal(raw, &sig); err != nil || len(sig.Signatures) == 0 {
|
||||||
http.Error(w, "bad JWS", http.StatusBadRequest)
|
// … fallback to compact serialization
|
||||||
return nil, false
|
cp, err2 := jose.ParseSigned(string(raw))
|
||||||
}
|
if err2 != nil {
|
||||||
if len(sig.Signatures) == 0 {
|
http.Error(w, "bad JWS", http.StatusBadRequest)
|
||||||
http.Error(w, "no signature", http.StatusBadRequest)
|
return nil, false
|
||||||
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) {
|
if !s.db.takeNonce(ctx, prot.Nonce) {
|
||||||
http.Error(w, "bad nonce", http.StatusForbidden)
|
http.Error(w, "bad nonce", http.StatusForbidden)
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve verification key (inline JWK or referenced by kid)
|
// Resolve verification key
|
||||||
var key *jose.JSONWebKey
|
var key *jose.JSONWebKey
|
||||||
if prot.JSONWebKey != nil {
|
switch {
|
||||||
|
case prot.JSONWebKey != nil:
|
||||||
key = prot.JSONWebKey
|
key = prot.JSONWebKey
|
||||||
} else if prot.KeyID != "" {
|
case prot.KeyID != "":
|
||||||
id := path.Base(prot.KeyID) // everything after last '/'
|
if k, err := s.db.accountKey(ctx, path.Base(prot.KeyID)); err == nil {
|
||||||
k, err := s.db.accountKey(ctx, id)
|
key = k
|
||||||
if err != nil {
|
} else {
|
||||||
http.Error(w, "unknown kid", http.StatusUnauthorized)
|
http.Error(w, "unknown kid", http.StatusUnauthorized)
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
key = k
|
default:
|
||||||
}
|
|
||||||
if key == nil {
|
|
||||||
http.Error(w, "no verification key", http.StatusBadRequest)
|
http.Error(w, "no verification key", http.StatusBadRequest)
|
||||||
return nil, false
|
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)
|
http.Error(w, "signature invalid", http.StatusUnauthorized)
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
return &jwsPayload{Data: payload, JWK: key}, true
|
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.Header().Set("Replay-Nonce", n)
|
||||||
w.WriteHeader(http.StatusOK)
|
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":
|
case r.Method == http.MethodPost && r.URL.Path == "/acme/new-account":
|
||||||
s.handleNewAccount(ctx, w, r)
|
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":
|
case r.Method == http.MethodPost && r.URL.Path == "/acme/revoke-cert":
|
||||||
s.handleRevoke(ctx, w, r)
|
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/"):
|
case r.Method == http.MethodGet && strings.HasPrefix(r.URL.Path, "/acme/order/"):
|
||||||
s.handleGetOrder(ctx, w, r)
|
s.handleGetOrder(ctx, w, r)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user