diff --git a/builtin/credential/cert/path_login.go b/builtin/credential/cert/path_login.go index faea1cecf9c2..5b9fec9a6c2b 100644 --- a/builtin/credential/cert/path_login.go +++ b/builtin/credential/cert/path_login.go @@ -279,6 +279,14 @@ func (b *backend) verifyCredentials(ctx context.Context, req *logical.Request, d // Check for client cert being explicitly listed in the config (and matching other constraints) if tCert.SerialNumber.Cmp(clientCert.SerialNumber) == 0 && bytes.Equal(tCert.AuthorityKeyId, clientCert.AuthorityKeyId) { + pkMatch, err := certutil.ComparePublicKeysAndType(tCert.PublicKey, clientCert.PublicKey) + if err != nil { + return nil, nil, err + } + if !pkMatch { + // Someone may be trying to pass off a forged certificate as the trusted non-CA cert. Reject early. + return nil, logical.ErrorResponse("public key mismatch of a trusted leaf certificate"), nil + } matches, err := b.matchesConstraints(ctx, clientCert, trustedNonCA.Certificates, trustedNonCA, verifyConf) // matchesConstraints returns an error when OCSP verification fails, diff --git a/changelog/25649.txt b/changelog/25649.txt new file mode 100644 index 000000000000..2ce669886201 --- /dev/null +++ b/changelog/25649.txt @@ -0,0 +1,5 @@ +```release-note:security +auth/cert: compare public keys of trusted non-CA certificates with incoming +client certificates to prevent trusting certs with the same serial number +but not the same public/private key. +``` \ No newline at end of file