forked from TrueCloudLab/certificates
Add support for revocation using JWK
This commit is contained in:
parent
84e7d468f2
commit
0e56932e76
3 changed files with 59 additions and 8 deletions
|
@ -94,11 +94,17 @@ func (h *Handler) Route(r api.Router) {
|
|||
r.MethodFunc("GET", getPath(DirectoryLinkType, "{provisionerID}"), h.baseURLFromRequest(h.lookupProvisioner(h.GetDirectory)))
|
||||
r.MethodFunc("HEAD", getPath(DirectoryLinkType, "{provisionerID}"), h.baseURLFromRequest(h.lookupProvisioner(h.GetDirectory)))
|
||||
|
||||
validatingMiddleware := func(next nextHTTP) nextHTTP {
|
||||
return h.baseURLFromRequest(h.lookupProvisioner(h.addNonce(h.addDirLink(h.verifyContentType(h.parseJWS(next))))))
|
||||
}
|
||||
extractPayloadByJWK := func(next nextHTTP) nextHTTP {
|
||||
return h.baseURLFromRequest(h.lookupProvisioner(h.addNonce(h.addDirLink(h.verifyContentType(h.parseJWS(h.validateJWS(h.extractJWK(h.verifyAndExtractJWSPayload(next)))))))))
|
||||
return validatingMiddleware(h.extractJWK(h.verifyAndExtractJWSPayload(next)))
|
||||
}
|
||||
extractPayloadByKid := func(next nextHTTP) nextHTTP {
|
||||
return h.baseURLFromRequest(h.lookupProvisioner(h.addNonce(h.addDirLink(h.verifyContentType(h.parseJWS(h.validateJWS(h.lookupJWK(h.verifyAndExtractJWSPayload(next)))))))))
|
||||
return validatingMiddleware(h.lookupJWK(h.verifyAndExtractJWSPayload(next)))
|
||||
}
|
||||
extractPayloadByKidOrJWK := func(next nextHTTP) nextHTTP {
|
||||
return validatingMiddleware(h.extractOrLookupJWK(h.verifyAndExtractJWSPayload(next)))
|
||||
}
|
||||
|
||||
r.MethodFunc("POST", getPath(NewAccountLinkType, "{provisionerID}"), extractPayloadByJWK(h.NewAccount))
|
||||
|
@ -111,7 +117,7 @@ func (h *Handler) Route(r api.Router) {
|
|||
r.MethodFunc("POST", getPath(AuthzLinkType, "{provisionerID}", "{authzID}"), extractPayloadByKid(h.isPostAsGet(h.GetAuthorization)))
|
||||
r.MethodFunc("POST", getPath(ChallengeLinkType, "{provisionerID}", "{authzID}", "{chID}"), extractPayloadByKid(h.GetChallenge))
|
||||
r.MethodFunc("POST", getPath(CertificateLinkType, "{provisionerID}", "{certID}"), extractPayloadByKid(h.isPostAsGet(h.GetCertificate)))
|
||||
r.MethodFunc("POST", getPath(RevokeCertLinkType, "{provisionerID}"), extractPayloadByKid(h.RevokeCert)) // TODO: check kid vs. jws; revoke can do both
|
||||
r.MethodFunc("POST", getPath(RevokeCertLinkType, "{provisionerID}"), extractPayloadByKidOrJWK(h.RevokeCert))
|
||||
}
|
||||
|
||||
// GetNonce just sets the right header since a Nonce is added to each response
|
||||
|
|
|
@ -352,6 +352,37 @@ func (h *Handler) lookupJWK(next nextHTTP) nextHTTP {
|
|||
}
|
||||
}
|
||||
|
||||
// extractOrLookupJWK forwards handling to either extractJWK or
|
||||
// lookupJWK based on the presence of a JWK or a KID, respectively.
|
||||
func (h *Handler) extractOrLookupJWK(next nextHTTP) nextHTTP {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
jws, err := jwsFromContext(ctx)
|
||||
if err != nil {
|
||||
api.WriteError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
// at this point the JWS has already been verified (if correctly configured in middleware),
|
||||
// and it can be used to check if a jwk exists.
|
||||
if canExtractJWKFrom(jws) {
|
||||
h.extractJWK(next)(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// default to looking up the JWK based on KID
|
||||
h.lookupJWK(next)(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
// canExtractJWKFrom checks if the JWS has a JWK that can be extracted
|
||||
func canExtractJWKFrom(jws *jose.JSONWebSignature) bool {
|
||||
if len(jws.Signatures) == 0 {
|
||||
return false
|
||||
}
|
||||
return jws.Signatures[0].Protected.JSONWebKey != nil
|
||||
}
|
||||
|
||||
// verifyAndExtractJWSPayload extracts the JWK from the JWS and saves it in the context.
|
||||
// Make sure to parse and validate the JWS before running this middleware.
|
||||
func (h *Handler) verifyAndExtractJWSPayload(next nextHTTP) nextHTTP {
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/smallstep/certificates/acme"
|
||||
"github.com/smallstep/certificates/api"
|
||||
"github.com/smallstep/certificates/authority"
|
||||
"go.step.sm/crypto/jose"
|
||||
"golang.org/x/crypto/ocsp"
|
||||
)
|
||||
|
||||
|
@ -19,16 +20,21 @@ type revokePayload struct {
|
|||
|
||||
func (h *Handler) RevokeCert(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// TODO: support the non-kid case, i.e. JWK with the public key of the cert
|
||||
// base the account + certificate JWK instead of the kid (which is now the case)
|
||||
|
||||
ctx := r.Context()
|
||||
_, err := accountFromContext(ctx)
|
||||
jws, err := jwsFromContext(ctx)
|
||||
if err != nil {
|
||||
api.WriteError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
if shouldCheckAccount(jws) {
|
||||
_, err := accountFromContext(ctx)
|
||||
if err != nil {
|
||||
api.WriteError(w, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: do checks on account, i.e. is it still valid? is it allowed to do revocations? Revocations on the to be revoked cert?
|
||||
|
||||
_, err = provisionerFromContext(ctx)
|
||||
|
@ -65,7 +71,7 @@ func (h *Handler) RevokeCert(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
certID := certToBeRevoked.SerialNumber.String()
|
||||
// TODO: retrieving the certificate to verify the account does not seem to work? Results in certificate not found error.
|
||||
// TODO: retrieving the certificate to verify the account does not seem to work, so far? Results in certificate not found error.
|
||||
// When Revoke is called, the certificate IS in fact found? The (h *Handler) GetCertificate function is fairly similar, too.
|
||||
// existingCert, err := h.db.GetCertificate(ctx, certID)
|
||||
// if err != nil {
|
||||
|
@ -101,6 +107,7 @@ func (h *Handler) RevokeCert(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
w.Header().Add("Link", link(h.linker.GetLink(ctx, DirectoryLinkType), "index"))
|
||||
w.Write(nil)
|
||||
}
|
||||
|
||||
|
@ -130,3 +137,10 @@ func reason(reasonCode int) string {
|
|||
return "unspecified reason"
|
||||
}
|
||||
}
|
||||
|
||||
// shouldUseAccount indicates whether an account should be
|
||||
// retrieved from the context, so that it can be used for
|
||||
// additional checks
|
||||
func shouldCheckAccount(jws *jose.JSONWebSignature) bool {
|
||||
return !canExtractJWKFrom(jws)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue