Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ var (
ErrNoBearerToken = errors.New("no bearer token given")
ErrInvalidBearerToken = errors.New("invalid bearer token given")
ErrInsufficientScope = errors.New("bearer token does not have sufficient scope")
ErrCouldNotLoadCertificate = errors.New("failed to load certificate")
ErrCouldNotLoadPublicKey = errors.New("failed to load public key")
ErrEventTypeEmpty = errors.New("event type empty")
ErrEventSinkIsNil = errors.New("event sink is nil")
ErrUnsupportedEventSink = errors.New("event sink is not supported")
Expand Down
36 changes: 24 additions & 12 deletions pkg/api/authn.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package api

import (
"context"
"crypto"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
Expand Down Expand Up @@ -402,15 +403,17 @@ func (amw *AuthnMiddleware) tryAuthnHandlers(ctlr *Controller) mux.MiddlewareFun
}

func bearerAuthHandler(ctlr *Controller) mux.MiddlewareFunc {
certificate, err := loadCertificateFromFile(ctlr.Config.HTTP.Auth.Bearer.Cert)
// although the configuration option is called 'cert', this function will also parse a public key directly
// see https://github.com/project-zot/zot/issues/3173 for info
publicKey, err := loadPublicKeyFromFile(ctlr.Config.HTTP.Auth.Bearer.Cert)
if err != nil {
ctlr.Log.Panic().Err(err).Msg("failed to load certificate for bearer authentication")
ctlr.Log.Panic().Err(err).Msg("failed to load public key for bearer authentication")
}

authorizer := NewBearerAuthorizer(
ctlr.Config.HTTP.Auth.Bearer.Realm,
ctlr.Config.HTTP.Auth.Bearer.Service,
certificate.PublicKey,
publicKey,
)

return func(next http.Handler) http.Handler {
Expand Down Expand Up @@ -902,21 +905,30 @@ func GenerateAPIKey(uuidGenerator guuid.Generator, log log.Logger,
return apiKey, apiKeyID.String(), err
}

func loadCertificateFromFile(path string) (*x509.Certificate, error) {
rawCert, err := os.ReadFile(path)
func loadPublicKeyFromFile(path string) (crypto.PublicKey, error) {
raw, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("%w: %w, path %s", zerr.ErrCouldNotLoadCertificate, err, path)
return nil, fmt.Errorf("%w: %w, path %s", zerr.ErrCouldNotLoadPublicKey, err, path)
}

block, _ := pem.Decode(rawCert)
block, _ := pem.Decode(raw)
if block == nil {
return nil, fmt.Errorf("%w: no valid PEM data found", zerr.ErrCouldNotLoadCertificate)
return nil, fmt.Errorf("%w: no valid PEM data found", zerr.ErrCouldNotLoadPublicKey)
}

cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, fmt.Errorf("%w: %w", zerr.ErrCouldNotLoadCertificate, err)
pemBytes := block.Bytes

if cert, err := x509.ParseCertificate(pemBytes); err == nil {
return cert.PublicKey, nil
}

if key, err := x509.ParsePKIXPublicKey(pemBytes); err == nil {
return key, nil
}

if key, err := x509.ParsePKCS1PublicKey(pemBytes); err == nil {
return key, nil
}

return cert, nil
return nil, fmt.Errorf("%w: no valid x509 certificate or public key found", zerr.ErrCouldNotLoadPublicKey)
}
34 changes: 31 additions & 3 deletions pkg/api/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,15 @@ import (
const (
ServerCert = "../../test/data/server.cert"
ServerKey = "../../test/data/server.key"
ServerPublicKey = "../../test/data/server-public.key"
ServerPublicKeyPKCS1 = "../../test/data/server-public-pkcs1.key"
CACert = "../../test/data/ca.crt"
ServerCertECDSA = "../../test/data/server-ecdsa.cert"
ServerKeyECDSA = "../../test/data/server-ecdsa.key"
ServerPublicKeyECDSA = "../../test/data/server-public-ecdsa.key"
ServerCertED25519 = "../../test/data/server-ed25519.cert"
ServerKeyED25519 = "../../test/data/server-ed25519.key"
ServerPublicKeyED25519 = "../../test/data/server-public-ed25519.key"
UnauthorizedNamespace = "fortknox/notallowed"
AuthorizationNamespace = "authz/image"
LDAPAddress = "127.0.0.1"
Expand Down Expand Up @@ -3921,23 +3925,47 @@ func TestBearerAuthMultipleAlgorithms(t *testing.T) {
alg string
}{
{
"RSA signing key",
"RSA signing key using certificate",
ServerKey,
ServerCert,
"RS256",
},
{
"ECDSA signing key",
"RSA signing key using public key",
ServerKey,
ServerPublicKey,
"RS256",
},
{
"RSA signing key using public key in PKCS1 format",
ServerKey,
ServerPublicKeyPKCS1,
"RS256",
},
{
"ECDSA signing key using certificate",
ServerKeyECDSA,
ServerCertECDSA,
"ES256",
},
{
"ED25519 signing key",
"ECDSA signing key using public key",
ServerKeyECDSA,
ServerPublicKeyECDSA,
"ES256",
},
{
"ED25519 signing key using certificate",
ServerKeyED25519,
ServerCertED25519,
"EdDSA",
},
{
"ED25519 signing key using public key",
ServerKeyED25519,
ServerPublicKeyED25519,
"EdDSA",
},
}

for _, testCase := range testCases {
Expand Down
20 changes: 20 additions & 0 deletions test/scripts/gen_certs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ openssl req \
-out server.csr \
-subj "/OU=TestServer/CN=*"

openssl rsa \
-in server.key \
-pubout \
-out server-public.key

openssl rsa \
-in server.key \
-RSAPublicKey_out \
-out server-public-pkcs1.key

openssl x509 \
-req \
-days 3650 \
Expand Down Expand Up @@ -76,6 +86,11 @@ openssl req \
-out server-ecdsa.csr \
-subj "/OU=TestServer/CN=*"

openssl ec \
-in server-ecdsa.key \
-pubout \
-out server-public-ecdsa.key

openssl x509 \
-req \
-days 3650 \
Expand Down Expand Up @@ -112,6 +127,11 @@ openssl req \
-out server-ed25519.csr \
-subj "/OU=TestServer/CN=*"

openssl pkey \
-in server-ed25519.key \
-pubout \
-out server-public-ed25519.key

openssl x509 \
-req \
-days 3650 \
Expand Down