From 7672d9bc99c37a2f1fbca7761005c736791bfc38 Mon Sep 17 00:00:00 2001 From: Aaron Gable Date: Fri, 18 Sep 2020 16:10:12 -0700 Subject: [PATCH] CA: Verify digitalSignature and certSign key usages (#5091) When the CA loads new issuers (both their certificates and their private keys), it performs a variety of sanity checks, such as ensuring that the profile's signature algorithm matches the key type. With this change, we also check that the issuer's certificate has the appropriate key usage bits set: `certSign`, if it is going to be issuing end-entity certs; and `digitalSignature`, because it will be signing OCSP responses for previously-issued certificates. Fixes #5068 --- issuance/issuance.go | 11 +++++++ issuance/issuance_test.go | 68 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/issuance/issuance.go b/issuance/issuance.go index da6cde4ce..79fa31768 100644 --- a/issuance/issuance.go +++ b/issuance/issuance.go @@ -353,6 +353,17 @@ func NewIssuer(cert *x509.Certificate, signer crypto.Signer, profile *Profile, l default: return nil, errors.New("unsupported issuer key type") } + + if profile.useForRSALeaves || profile.useForECDSALeaves { + if cert.KeyUsage&x509.KeyUsageCertSign == 0 { + return nil, errors.New("end-entity signing cert does not have keyUsage certSign") + } + } + // TODO(#5086): Only do this check for ocsp-issuing issuers. + if cert.KeyUsage&x509.KeyUsageDigitalSignature == 0 { + return nil, errors.New("end-entity ocsp signing cert does not have keyUsage digitalSignature") + } + i := &Issuer{ Cert: cert, Signer: signer, diff --git a/issuance/issuance_test.go b/issuance/issuance_test.go index 4e2179a40..0ac6facc8 100644 --- a/issuance/issuance_test.go +++ b/issuance/issuance_test.go @@ -67,7 +67,7 @@ func TestMain(m *testing.M) { Subject: pkix.Name{ CommonName: "big ca", }, - KeyUsage: x509.KeyUsageCertSign, + KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature, SubjectKeyId: []byte{1, 2, 3, 4, 5, 6, 7, 8}, } issuer, err := x509.CreateCertificate(rand.Reader, template, template, tk.Public(), tk) @@ -409,7 +409,18 @@ func TestGenerateTemplate(t *testing.T) { } } -func TestNewSignerUnsupportedKeyType(t *testing.T) { +func TestNewIssuer(t *testing.T) { + _, err := NewIssuer( + issuerCert, + issuerSigner, + defaultProfile(), + &lint.Linter{}, + clock.NewFake(), + ) + test.AssertNotError(t, err, "NewIssuer failed") +} + +func TestNewIssuerUnsupportedKeyType(t *testing.T) { _, err := NewIssuer( &x509.Certificate{ PublicKey: &ed25519.PublicKey{}, @@ -423,6 +434,59 @@ func TestNewSignerUnsupportedKeyType(t *testing.T) { test.AssertEquals(t, err.Error(), "unsupported issuer key type") } +func TestNewIssuerNoCertSign(t *testing.T) { + _, err := NewIssuer( + &x509.Certificate{ + PublicKey: &ecdsa.PublicKey{ + Curve: elliptic.P256(), + }, + KeyUsage: 0, + }, + issuerSigner, + defaultProfile(), + &lint.Linter{}, + clock.NewFake(), + ) + test.AssertError(t, err, "NewIssuer didn't fail") + test.AssertEquals(t, err.Error(), "end-entity signing cert does not have keyUsage certSign") +} + +func TestNewIssuerNoDigitalSignature(t *testing.T) { + _, err := NewIssuer( + &x509.Certificate{ + PublicKey: &ecdsa.PublicKey{ + Curve: elliptic.P256(), + }, + KeyUsage: x509.KeyUsageCertSign, + }, + issuerSigner, + defaultProfile(), + &lint.Linter{}, + clock.NewFake(), + ) + test.AssertError(t, err, "NewIssuer didn't fail") + test.AssertEquals(t, err.Error(), "end-entity ocsp signing cert does not have keyUsage digitalSignature") +} + +func TestNewIssuerOCSPOnly(t *testing.T) { + p := defaultProfile() + p.useForRSALeaves = false + p.useForECDSALeaves = false + _, err := NewIssuer( + &x509.Certificate{ + PublicKey: &ecdsa.PublicKey{ + Curve: elliptic.P256(), + }, + KeyUsage: x509.KeyUsageDigitalSignature, + }, + issuerSigner, + p, + &lint.Linter{}, + clock.NewFake(), + ) + test.AssertNotError(t, err, "NewIssuer failed") +} + func TestIssue(t *testing.T) { for _, tc := range []struct { name string