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:
parent
91e32bcf83
commit
251ad45c24
123
ca/ca_test.go
123
ca/ca_test.go
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue