diff --git a/lib/subca/parsed.go b/lib/subca/parsed.go index 60c445aa93c..83c359c201a 100644 --- a/lib/subca/parsed.go +++ b/lib/subca/parsed.go @@ -23,7 +23,6 @@ import ( "fmt" "regexp" "slices" - "strings" "github.com/gravitational/trace" @@ -131,7 +130,7 @@ func parseCertificateAndPublicKey(co *subcav1.CertificateOverride) (_ *x509.Cert } // Normalize user-supplied public keys. - pkh := strings.ToLower(co.GetPublicKey()) + pkh := NormalizePublicKey(co.GetPublicKey()) return nil, pkh, nil } @@ -220,7 +219,7 @@ func validateCertificateOverride( if !certificateOverridePublicKeyRE.MatchString(co.GetPublicKey()) { return nil, "", errors.New("invalid public key") } - if wantPublicKey != "" && !strings.EqualFold(co.GetPublicKey(), wantPublicKey) { + if wantPublicKey != "" && NormalizePublicKey(co.GetPublicKey()) != wantPublicKey { return nil, "public_key", fmt.Errorf("certificate public key mismatch (want %q)", wantPublicKey) } } @@ -289,7 +288,7 @@ func validateCertificateOverride( // Normalize public key to lowercase so it matches HashPublicKey. publicKey := cmp.Or(wantPublicKey, co.GetPublicKey()) - publicKey = strings.ToLower(publicKey) + publicKey = NormalizePublicKey(publicKey) return &ParsedCertificateOverride{ CertificateOverride: co, diff --git a/lib/subca/public_key_hash.go b/lib/subca/public_key_hash.go index 3f481e1977f..c0ee5d074b5 100644 --- a/lib/subca/public_key_hash.go +++ b/lib/subca/public_key_hash.go @@ -20,6 +20,7 @@ import ( "crypto/sha256" "crypto/x509" "encoding/hex" + "strings" ) // HashCertificatePublicKey hashes a certificate's public key in the @@ -41,3 +42,12 @@ func HashPublicKey(rawSubjectPublicKeyInfo []byte) string { sum := sha256.Sum256(rawSubjectPublicKeyInfo) return hex.EncodeToString(sum[:]) } + +// NormalizePublicKey normalizes user-supplied Sub CA public keys to the same +// form as returned by [HashCertificatePublicKey] and [HashPublicKey] (ie, it +// makes it lowercase). +// +// Normalized public keys can be compared directly for equality. +func NormalizePublicKey(pk string) string { + return strings.ToLower(pk) +} diff --git a/lib/subca/public_key_hash_test.go b/lib/subca/public_key_hash_test.go index 98a488f7da5..76f333a67c4 100644 --- a/lib/subca/public_key_hash_test.go +++ b/lib/subca/public_key_hash_test.go @@ -19,6 +19,7 @@ package subca_test import ( "crypto/x509" "encoding/hex" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -49,3 +50,15 @@ func TestHashPublicKey(t *testing.T) { assert.Equal(t, want, got) }) } + +func TestNormalizePublicKey(t *testing.T) { + t.Parallel() + + const examplePubKey = `99c968f51266531bde14cbb0cd1cc52d0cc5590bde0a760da27f9be8a7ea7ad7` + // Normalizing a "normal" pub key is a noop. + assert.Equal(t, examplePubKey, subca.NormalizePublicKey(examplePubKey)) + + // Normalize an upper-case pub key. + abnormalPubKey := strings.ToUpper(examplePubKey) + assert.Equal(t, examplePubKey, subca.NormalizePublicKey(abnormalPubKey)) +}