auth: fix token verification chain

There was a small regression introduced in
https://github.com/distribution/distribution/pull/4349.

Specifically, if the certificate chain verification succeeds we should
return immediately instead of following up with further token verification
checks.

This commit fixes that: we only follow up with further token
verifications if x5c header is missing.

We've also refactored this method so it's hopefully clearer.

Co-authored-by: Kyle Squizzato <ksquizz@gmail.com>
Signed-off-by: Milos Gajdos <milosthegajdos@gmail.com>
This commit is contained in:
Milos Gajdos
2024-07-21 10:48:55 +01:00
parent 21f3291612
commit 70e0d8850c

View File

@@ -162,7 +162,7 @@ func (t *Token) Verify(verifyOpts VerifyOptions) (*ClaimSet, error) {
} }
// VerifySigningKey attempts to verify and return the signing key which was used to sign the token. // VerifySigningKey attempts to verify and return the signing key which was used to sign the token.
func (t *Token) VerifySigningKey(verifyOpts VerifyOptions) (signingKey crypto.PublicKey, err error) { func (t *Token) VerifySigningKey(verifyOpts VerifyOptions) (crypto.PublicKey, error) {
if len(t.JWT.Headers) == 0 { if len(t.JWT.Headers) == 0 {
return nil, ErrInvalidToken return nil, ErrInvalidToken
} }
@@ -172,26 +172,27 @@ func (t *Token) VerifySigningKey(verifyOpts VerifyOptions) (signingKey crypto.Pu
// verifying the first one in the list only at the moment. // verifying the first one in the list only at the moment.
header := t.JWT.Headers[0] header := t.JWT.Headers[0]
signingKey, err = verifyCertChain(header, verifyOpts.Roots) signingKey, err := verifyCertChain(header, verifyOpts.Roots)
if err != nil {
// NOTE(milosgajdos): if the x5c header is missing // NOTE(milosgajdos): if the x5c header is missing
// the token may have been signed by a JWKS. // the token may have been signed by a JWKS.
if err != nil && err != jose.ErrMissingX5cHeader { if errors.Is(err, jose.ErrMissingX5cHeader) {
return
}
switch { switch {
case header.JSONWebKey != nil: case header.JSONWebKey != nil:
signingKey, err = verifyJWK(header, verifyOpts) return verifyJWK(header, verifyOpts)
case len(header.KeyID) > 0: case header.KeyID != "":
signingKey = verifyOpts.TrustedKeys[header.KeyID] if signingKey, ok := verifyOpts.TrustedKeys[header.KeyID]; ok {
if signingKey == nil { return signingKey, nil
err = fmt.Errorf("token signed by untrusted key with ID: %q", header.KeyID)
} }
return nil, fmt.Errorf("token signed by untrusted key with ID: %q", header.KeyID)
default: default:
err = ErrInvalidToken return nil, ErrInvalidToken
}
}
return nil, err
} }
return return signingKey, nil
} }
func verifyCertChain(header jose.Header, roots *x509.CertPool) (signingKey crypto.PublicKey, err error) { func verifyCertChain(header jose.Header, roots *x509.CertPool) (signingKey crypto.PublicKey, err error) {