diff --git a/registry/auth/token/accesscontroller.go b/registry/auth/token/accesscontroller.go index b86cb3673..f8f9210e7 100644 --- a/registry/auth/token/accesscontroller.go +++ b/registry/auth/token/accesscontroller.go @@ -354,6 +354,9 @@ func newAccessController(options map[string]interface{}) (auth.AccessController, if key := GetJWKThumbprint(rootCert.PublicKey); key != "" { trustedKeys[key] = rootCert.PublicKey } + if key := GetLibtrustKeyID(rootCert.PublicKey); key != "" { + trustedKeys[key] = rootCert.PublicKey + } } if jwks != nil { diff --git a/registry/auth/token/accesscontroller_test.go b/registry/auth/token/accesscontroller_test.go index ba3d0a37a..c762a7e58 100644 --- a/registry/auth/token/accesscontroller_test.go +++ b/registry/auth/token/accesscontroller_test.go @@ -143,8 +143,8 @@ func TestRootCertIncludedInTrustedKeys(t *testing.T) { // newAccessController return type is an interface built from // accessController struct. The type check can be safely ignored. ac2, _ := ac.(*accessController) - if got := len(ac2.trustedKeys); got != 1 { - t.Fatalf("Unexpected number of trusted keys, expected 1 got: %d", got) + if got := len(ac2.trustedKeys); got != 2 { + t.Fatalf("Unexpected number of trusted keys, expected 2 got: %d", got) } } diff --git a/registry/auth/token/util.go b/registry/auth/token/util.go index 88079cce7..50ea84a04 100644 --- a/registry/auth/token/util.go +++ b/registry/auth/token/util.go @@ -1,14 +1,18 @@ package token import ( + "bytes" "crypto" "crypto/ecdsa" "crypto/ed25519" "crypto/rsa" "crypto/sha256" + "crypto/x509" + "encoding/base32" "encoding/base64" "fmt" "math/big" + "strings" ) // actionSet is a special type of stringSet. @@ -101,3 +105,26 @@ func getJWKThumbprint(publickey crypto.PublicKey, skipED25519 bool) string { return "" } } + +// Returns a libtrust-compatible Key ID, for backwards compatibility +// with JWT headers expected by distribution/v2 +func GetLibtrustKeyID(publickey crypto.PublicKey) string { + keyBytes, err := x509.MarshalPKIXPublicKey(publickey) + if err != nil { + return "" + } + + sum := sha256.Sum256(keyBytes) + b64 := strings.TrimRight(base32.StdEncoding.EncodeToString(sum[:30]), "=") + + var buf bytes.Buffer + var i int + for i = 0; i < len(b64)/4-1; i++ { + start := i * 4 + end := start + 4 + buf.WriteString(b64[start:end] + ":") + } + buf.WriteString(b64[i*4:]) + + return buf.String() +}