CA: Refactor Must-Staple tests. (#2912)

Refactor must-staple tests to make them easier to adapt for precertificate-based
issuance.
This commit is contained in:
Brian Smith 2017-07-28 05:57:05 -10:00 committed by Jacob Hoffman-Andrews
parent 91e32bcf83
commit 251ad45c24
1 changed files with 74 additions and 49 deletions

View File

@ -264,6 +264,10 @@ func TestIssueCertificate(t *testing.T) {
{"AllowNoCN", issueCertificateSubTestDefaultSetup, issueCertificateSubTestAllowNoCN},
{"ProfileSelectionRSA", issueCertificateSubTestDefaultSetup, issueCertificateSubTestProfileSelectionRSA},
{"ProfileSelectionECDSA", issueCertificateSubTestDefaultSetup, issueCertificateSubTestProfileSelectionECDSA},
{"MustStapleWhenDisabled", issueCertificateSubTestMustStapleDisabledSetup, issueCertificateSubTestMustStapleWhenDisabled},
{"MustStapleWhenEnabled", issueCertificateSubTestMustStapleEnabledSetup, issueCertificateSubTestMustStapleWhenEnabled},
{"MustStapleDuplicate", issueCertificateSubTestMustStapleEnabledSetup, issueCertificateSubTestDuplicateMustStaple},
{"UnknownExtension", issueCertificateSubTestMustStapleEnabledSetup, issueCertificateSubTestUnknownExtension},
}
for _, testCase := range testCases {
@ -461,6 +465,7 @@ func TestInvalidCSRs(t *testing.T) {
testCases := []struct {
name string
csrPath string
check func(t *testing.T, ca *CertificateAuthorityImpl, sa *mockSA)
errorMessage string
}{
// Test that the CA rejects CSRs that have no names.
@ -469,7 +474,7 @@ func TestInvalidCSRs(t *testing.T) {
// * Random RSA public key.
// * CN = [none]
// * DNSNames = [none]
{"RejectNoHostnames", "./testdata/no_names.der.csr", "Issued certificate with no names"},
{"RejectNoHostnames", "./testdata/no_names.der.csr", nil, "Issued certificate with no names"},
// Test that the CA rejects CSRs that have too many names.
//
@ -477,7 +482,7 @@ func TestInvalidCSRs(t *testing.T) {
// * Random public key
// * CN = [none]
// * DNSNames = not-example.com, www.not-example.com, mail.example.com
{"RejectTooManyHostnames", "./testdata/too_many_names.der.csr", "Issued certificate with too many names"},
{"RejectTooManyHostnames", "./testdata/too_many_names.der.csr", nil, "Issued certificate with too many names"},
// Test that the CA rejects CSRs that have public keys that are too short.
//
@ -485,17 +490,23 @@ func TestInvalidCSRs(t *testing.T) {
// * Random public key -- 512 bits long
// * CN = (none)
// * DNSNames = not-example.com, www.not-example.com, mail.not-example.com
{"RejectShortKey", "./testdata/short_key.der.csr", "Issued a certificate with too short a key."},
{"RejectShortKey", "./testdata/short_key.der.csr", nil, "Issued a certificate with too short a key."},
// CSR generated by Go:
// * Random RSA public key.
// * CN = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com
// * DNSNames = [none]
{"RejectLongCommonName", "./testdata/long_cn.der.csr", "Issued a certificate with a CN over 64 bytes."},
{"RejectLongCommonName", "./testdata/long_cn.der.csr", nil, "Issued a certificate with a CN over 64 bytes."},
// CSR generated by OpenSSL:
// Edited signature to become invalid.
{"RejectWrongSignature", "./testdata/invalid_signature.der.csr", "Issued a certificate based on a CSR with an invalid signature."},
{"RejectWrongSignature", "./testdata/invalid_signature.der.csr", nil, "Issued a certificate based on a CSR with an invalid signature."},
// CSR generated by Go:
// * Random public key
// * CN = not-example.com
// * Includes an extensionRequest attribute for an empty TLS Feature extension
{"TLSFeatureUnknown", "./testdata/tls_feature_unknown.der.csr", issueCertificateSubTestTLSFeatureUnknown, "Issued a certificate based on a CSR with an empty TLS feature extension."},
}
testCtx := setup(t)
@ -517,6 +528,10 @@ func TestInvalidCSRs(t *testing.T) {
_, err = ca.IssueCertificate(ctx, &caPB.IssueCertificateRequest{Csr: serializedCSR, RegistrationID: &arbitraryRegID})
test.AssertError(t, err, testCase.errorMessage)
test.Assert(t, berrors.Is(err, berrors.Malformed), "Incorrect error type returned")
test.AssertEquals(t, signatureCountByPurpose("cert", ca.signatureCount), 0)
if testCase.check != nil {
testCase.check(t, ca, sa)
}
})
}
}
@ -606,6 +621,18 @@ func issueCertificateSubTestProfileSelectionECDSA(t *testing.T, ca *CertificateA
test.AssertEquals(t, cert.KeyUsage, expectedKeyUsage)
}
func issueCertificateSubTestMustStapleDisabledSetup(t *testing.T) (*CertificateAuthorityImpl, *mockSA) {
ca, sa := issueCertificateSubTestDefaultSetup(t)
ca.enableMustStaple = false
return ca, sa
}
func issueCertificateSubTestMustStapleEnabledSetup(t *testing.T) (*CertificateAuthorityImpl, *mockSA) {
ca, sa := issueCertificateSubTestDefaultSetup(t)
ca.enableMustStaple = true
return ca, sa
}
func countMustStaple(t *testing.T, cert *x509.Certificate) (count int) {
oidTLSFeature := asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 24}
for _, ext := range cert.Extensions {
@ -618,71 +645,69 @@ func countMustStaple(t *testing.T, cert *x509.Certificate) (count int) {
return count
}
func TestExtensions(t *testing.T) {
testCtx := setup(t)
testCtx.caConfig.MaxNames = 3
sa := &mockSA{}
ca, err := NewCertificateAuthorityImpl(
testCtx.caConfig,
sa,
testCtx.pa,
testCtx.fc,
testCtx.stats,
testCtx.issuers,
testCtx.keyPolicy,
testCtx.logger)
sign := func(csr []byte) *x509.Certificate {
ca.csrExtensionCount.Reset()
ca.signatureCount.Reset()
coreCert, err := ca.IssueCertificate(ctx, &caPB.IssueCertificateRequest{Csr: csr, RegistrationID: &arbitraryRegID})
test.AssertNotError(t, err, "Failed to issue")
cert, err := x509.ParseCertificate(coreCert.DER)
test.AssertNotError(t, err, "Error parsing certificate produced by CA")
return cert
}
func issueCertificateSubTestMustStapleWhenDisabled(t *testing.T, ca *CertificateAuthorityImpl, _ *mockSA) {
// With ca.enableMustStaple = false, should issue successfully and not add
// Must Staple.
noStapleCert := sign(MustStapleCSR)
coreCert, err := ca.IssueCertificate(ctx, &caPB.IssueCertificateRequest{Csr: MustStapleCSR, RegistrationID: &arbitraryRegID})
test.AssertNotError(t, err, "Failed to issue")
cert, err := x509.ParseCertificate(coreCert.DER)
test.AssertNotError(t, err, "Error parsing certificate produced by CA")
test.AssertEquals(t, count(csrExtensionCategory, csrExtensionTLSFeature, ca.csrExtensionCount), 1)
test.AssertEquals(t, count(csrExtensionCategory, csrExtensionTLSFeatureInvalid, ca.csrExtensionCount), 0)
test.AssertEquals(t, signatureCountByPurpose("cert", ca.signatureCount), 1)
test.AssertEquals(t, countMustStaple(t, noStapleCert), 0)
test.AssertEquals(t, countMustStaple(t, cert), 0)
}
func issueCertificateSubTestMustStapleWhenEnabled(t *testing.T, ca *CertificateAuthorityImpl, _ *mockSA) {
// With ca.enableMustStaple = true, a TLS feature extension should put a must-staple
// extension into the cert
ca.enableMustStaple = true
singleStapleCert := sign(MustStapleCSR)
// extension into the cert.
coreCert, err := ca.IssueCertificate(ctx, &caPB.IssueCertificateRequest{Csr: MustStapleCSR, RegistrationID: &arbitraryRegID})
test.AssertNotError(t, err, "Failed to issue")
cert, err := x509.ParseCertificate(coreCert.DER)
test.AssertNotError(t, err, "Error parsing certificate produced by CA")
test.AssertEquals(t, count(csrExtensionCategory, csrExtensionTLSFeature, ca.csrExtensionCount), 1)
test.AssertEquals(t, count(csrExtensionCategory, csrExtensionTLSFeatureInvalid, ca.csrExtensionCount), 0)
test.AssertEquals(t, signatureCountByPurpose("cert", ca.signatureCount), 1)
test.AssertEquals(t, countMustStaple(t, singleStapleCert), 1)
test.AssertEquals(t, countMustStaple(t, cert), 1)
}
func issueCertificateSubTestDuplicateMustStaple(t *testing.T, ca *CertificateAuthorityImpl, _ *mockSA) {
// Even if there are multiple TLS Feature extensions, only one extension should be included
duplicateMustStapleCert := sign(DuplicateMustStapleCSR)
coreCert, err := ca.IssueCertificate(ctx, &caPB.IssueCertificateRequest{Csr: DuplicateMustStapleCSR, RegistrationID: &arbitraryRegID})
test.AssertNotError(t, err, "Failed to issue")
cert, err := x509.ParseCertificate(coreCert.DER)
test.AssertNotError(t, err, "Error parsing certificate produced by CA")
test.AssertEquals(t, count(csrExtensionCategory, csrExtensionTLSFeature, ca.csrExtensionCount), 1)
test.AssertEquals(t, count(csrExtensionCategory, csrExtensionTLSFeatureInvalid, ca.csrExtensionCount), 0)
test.AssertEquals(t, signatureCountByPurpose("cert", ca.signatureCount), 1)
test.AssertEquals(t, countMustStaple(t, duplicateMustStapleCert), 1)
test.AssertEquals(t, countMustStaple(t, cert), 1)
}
// ... but if it doesn't ask for stapling, there should be an error
ca.csrExtensionCount.Reset()
ca.signatureCount.Reset()
_, err = ca.IssueCertificate(ctx, &caPB.IssueCertificateRequest{Csr: TLSFeatureUnknownCSR, RegistrationID: &arbitraryRegID})
func issueCertificateSubTestTLSFeatureUnknown(t *testing.T, ca *CertificateAuthorityImpl, _ *mockSA) {
test.AssertEquals(t, count(csrExtensionCategory, csrExtensionTLSFeature, ca.csrExtensionCount), 1)
test.AssertEquals(t, count(csrExtensionCategory, csrExtensionTLSFeatureInvalid, ca.csrExtensionCount), 1)
test.AssertEquals(t, signatureCountByPurpose("cert", ca.signatureCount), 0)
test.AssertError(t, err, "Allowed a CSR with an empty TLS feature extension")
test.Assert(t, berrors.Is(err, berrors.Malformed), "Wrong error type when rejecting a CSR with empty TLS feature extension")
}
func issueCertificateSubTestUnknownExtension(t *testing.T, ca *CertificateAuthorityImpl, _ *mockSA) {
// Unsupported extensions in the CSR should be silently ignored.
coreCert, err := ca.IssueCertificate(ctx, &caPB.IssueCertificateRequest{Csr: UnsupportedExtensionCSR, RegistrationID: &arbitraryRegID})
test.AssertNotError(t, err, "Failed to issue")
cert, err := x509.ParseCertificate(coreCert.DER)
test.AssertNotError(t, err, "Error parsing certificate produced by CA")
// Unsupported extensions should be silently ignored, having the same
// extensions as the TLS Feature cert above, minus the TLS Feature Extension
unsupportedExtensionCert := sign(UnsupportedExtensionCSR)
test.AssertEquals(t, count(csrExtensionCategory, csrExtensionOther, ca.csrExtensionCount), 1)
test.AssertEquals(t, signatureCountByPurpose("cert", ca.signatureCount), 1)
test.AssertEquals(t, len(unsupportedExtensionCert.Extensions), len(singleStapleCert.Extensions)-1)
// NOTE: The hard-coded value here will have to change over time as Boulder
// adds new (unrequested) extensions to certificates.
test.AssertEquals(t, len(cert.Extensions), 9)
}
func signatureCountByPurpose(signatureType string, signatureCount *prometheus.CounterVec) int {