1 package ca
2
3 import (
4 "context"
5 "crypto"
6 "crypto/x509"
7 "crypto/x509/pkix"
8 "encoding/asn1"
9 "errors"
10 "fmt"
11 "os"
12 "strings"
13 "testing"
14 "time"
15
16 ct "github.com/google/certificate-transparency-go"
17 cttls "github.com/google/certificate-transparency-go/tls"
18 ctx509 "github.com/google/certificate-transparency-go/x509"
19 "github.com/jmhodges/clock"
20 "github.com/prometheus/client_golang/prometheus"
21 "google.golang.org/grpc"
22 "google.golang.org/protobuf/types/known/emptypb"
23
24 capb "github.com/letsencrypt/boulder/ca/proto"
25 "github.com/letsencrypt/boulder/config"
26 "github.com/letsencrypt/boulder/core"
27 corepb "github.com/letsencrypt/boulder/core/proto"
28 berrors "github.com/letsencrypt/boulder/errors"
29 "github.com/letsencrypt/boulder/features"
30 "github.com/letsencrypt/boulder/goodkey"
31 "github.com/letsencrypt/boulder/issuance"
32 "github.com/letsencrypt/boulder/linter"
33 blog "github.com/letsencrypt/boulder/log"
34 "github.com/letsencrypt/boulder/metrics"
35 "github.com/letsencrypt/boulder/must"
36 "github.com/letsencrypt/boulder/policy"
37 sapb "github.com/letsencrypt/boulder/sa/proto"
38 "github.com/letsencrypt/boulder/test"
39 )
40
41 func TestImplementation(t *testing.T) {
42 test.AssertImplementsGRPCServer(t, &certificateAuthorityImpl{}, capb.UnimplementedCertificateAuthorityServer{})
43 }
44
45 var (
46
47
48
49 CNandSANCSR = mustRead("./testdata/cn_and_san.der.csr")
50
51
52
53
54
55 MustStapleCSR = mustRead("./testdata/must_staple.der.csr")
56
57
58
59
60
61
62
63
64
65
66 UnsupportedExtensionCSR = mustRead("./testdata/unsupported_extension.der.csr")
67
68
69
70
71
72
73 CTPoisonExtensionCSR = mustRead("./testdata/ct_poison_extension.der.csr")
74
75
76
77
78
79
80 CTPoisonExtensionEmptyCSR = mustRead("./testdata/ct_poison_extension_empty.der.csr")
81
82
83
84
85
86 ECDSACSR = mustRead("./testdata/ecdsa.der.csr")
87
88
89 OIDExtensionCTPoison = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 3}
90
91
92 OIDExtensionSCTList = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 2}
93 )
94
95 const arbitraryRegID int64 = 1001
96
97
98 const caKeyFile = "../test/test-ca.key"
99 const caCertFile = "../test/test-ca.pem"
100 const caCertFile2 = "../test/test-ca2.pem"
101
102 func mustRead(path string) []byte {
103 return must.Do(os.ReadFile(path))
104 }
105
106 type testCtx struct {
107 pa core.PolicyAuthority
108 ocsp *ocspImpl
109 crl *crlImpl
110 certExpiry time.Duration
111 certBackdate time.Duration
112 serialPrefix int
113 maxNames int
114 boulderIssuers []*issuance.Issuer
115 keyPolicy goodkey.KeyPolicy
116 fc clock.FakeClock
117 stats prometheus.Registerer
118 signatureCount *prometheus.CounterVec
119 signErrorCount *prometheus.CounterVec
120 logger *blog.Mock
121 }
122
123 type mockSA struct {
124 certificate core.Certificate
125 }
126
127 func (m *mockSA) AddCertificate(ctx context.Context, req *sapb.AddCertificateRequest, _ ...grpc.CallOption) (*emptypb.Empty, error) {
128 m.certificate.DER = req.Der
129 return nil, nil
130 }
131
132 func (m *mockSA) AddPrecertificate(ctx context.Context, req *sapb.AddCertificateRequest, _ ...grpc.CallOption) (*emptypb.Empty, error) {
133 return &emptypb.Empty{}, nil
134 }
135
136 func (m *mockSA) AddSerial(ctx context.Context, req *sapb.AddSerialRequest, _ ...grpc.CallOption) (*emptypb.Empty, error) {
137 return &emptypb.Empty{}, nil
138 }
139
140 func (m *mockSA) GetCertificate(ctx context.Context, req *sapb.Serial, _ ...grpc.CallOption) (*corepb.Certificate, error) {
141 return nil, berrors.NotFoundError("cannot find the cert")
142 }
143
144 func (m *mockSA) SetCertificateStatusReady(ctx context.Context, req *sapb.Serial, _ ...grpc.CallOption) (*emptypb.Empty, error) {
145 return &emptypb.Empty{}, nil
146 }
147
148 var caKey crypto.Signer
149 var caCert *issuance.Certificate
150 var caCert2 *issuance.Certificate
151 var caLinter *linter.Linter
152 var caLinter2 *linter.Linter
153 var ctx = context.Background()
154
155 func init() {
156 var err error
157 caCert, caKey, err = issuance.LoadIssuer(issuance.IssuerLoc{
158 File: caKeyFile,
159 CertFile: caCertFile,
160 })
161 if err != nil {
162 panic(fmt.Sprintf("Unable to load %q and %q: %s", caKeyFile, caCertFile, err))
163 }
164 caCert2, err = issuance.LoadCertificate(caCertFile2)
165 if err != nil {
166 panic(fmt.Sprintf("Unable to parse %q: %s", caCertFile2, err))
167 }
168 caLinter, _ = linter.New(caCert.Certificate, caKey, []string{"n_subject_common_name_included"})
169 caLinter2, _ = linter.New(caCert2.Certificate, caKey, []string{"n_subject_common_name_included"})
170 }
171
172 func setup(t *testing.T) *testCtx {
173 features.Reset()
174 fc := clock.NewFake()
175 fc.Add(1 * time.Hour)
176
177 pa, err := policy.New(nil, blog.NewMock())
178 test.AssertNotError(t, err, "Couldn't create PA")
179 err = pa.LoadHostnamePolicyFile("../test/hostname-policy.yaml")
180 test.AssertNotError(t, err, "Couldn't set hostname policy")
181
182 boulderProfile := func(rsa, ecdsa bool) *issuance.Profile {
183 res, _ := issuance.NewProfile(
184 issuance.ProfileConfig{
185 AllowMustStaple: true,
186 AllowCTPoison: true,
187 AllowSCTList: true,
188 AllowCommonName: true,
189 Policies: []issuance.PolicyConfig{
190 {OID: "2.23.140.1.2.1"},
191 },
192 MaxValidityPeriod: config.Duration{Duration: time.Hour * 8760},
193 MaxValidityBackdate: config.Duration{Duration: time.Hour},
194 },
195 issuance.IssuerConfig{
196 UseForECDSALeaves: ecdsa,
197 UseForRSALeaves: rsa,
198 IssuerURL: "http://not-example.com/issuer-url",
199 OCSPURL: "http://not-example.com/ocsp",
200 CRLURL: "http://not-example.com/crl",
201 },
202 )
203 return res
204 }
205 boulderIssuers := []*issuance.Issuer{
206
207 {
208 Cert: caCert2,
209 Signer: caKey,
210 Profile: boulderProfile(false, true),
211 Linter: caLinter2,
212 Clk: fc,
213 },
214 {
215 Cert: caCert,
216 Signer: caKey,
217 Profile: boulderProfile(true, true),
218 Linter: caLinter,
219 Clk: fc,
220 },
221 }
222
223 keyPolicy := goodkey.KeyPolicy{
224 AllowRSA: true,
225 AllowECDSANISTP256: true,
226 AllowECDSANISTP384: true,
227 }
228 signatureCount := prometheus.NewCounterVec(
229 prometheus.CounterOpts{
230 Name: "signatures",
231 Help: "Number of signatures",
232 },
233 []string{"purpose", "issuer"})
234 signErrorCount := prometheus.NewCounterVec(prometheus.CounterOpts{
235 Name: "signature_errors",
236 Help: "A counter of signature errors labelled by error type",
237 }, []string{"type"})
238
239 ocsp, err := NewOCSPImpl(
240 boulderIssuers,
241 time.Hour,
242 0,
243 time.Second,
244 blog.NewMock(),
245 metrics.NoopRegisterer,
246 signatureCount,
247 signErrorCount,
248 fc,
249 )
250 test.AssertNotError(t, err, "Failed to create ocsp impl")
251
252 crl, err := NewCRLImpl(
253 boulderIssuers,
254 time.Hour,
255 "http://c.boulder.test",
256 100,
257 blog.NewMock(),
258 )
259 test.AssertNotError(t, err, "Failed to create crl impl")
260
261 return &testCtx{
262 pa: pa,
263 ocsp: ocsp,
264 crl: crl,
265 certExpiry: 8760 * time.Hour,
266 certBackdate: time.Hour,
267 serialPrefix: 17,
268 maxNames: 2,
269 boulderIssuers: boulderIssuers,
270 keyPolicy: keyPolicy,
271 fc: fc,
272 stats: metrics.NoopRegisterer,
273 signatureCount: signatureCount,
274 signErrorCount: signErrorCount,
275 logger: blog.NewMock(),
276 }
277 }
278
279 func TestFailNoSerialPrefix(t *testing.T) {
280 testCtx := setup(t)
281
282 _, err := NewCertificateAuthorityImpl(
283 nil,
284 nil,
285 nil,
286 nil,
287 testCtx.certExpiry,
288 testCtx.certBackdate,
289 0,
290 testCtx.maxNames,
291 testCtx.keyPolicy,
292 testCtx.logger,
293 testCtx.stats,
294 nil,
295 nil,
296 testCtx.fc)
297 test.AssertError(t, err, "CA should have failed with no SerialPrefix")
298 }
299
300 type TestCertificateIssuance struct {
301 ca *certificateAuthorityImpl
302 sa *mockSA
303 req *x509.CertificateRequest
304 certDER []byte
305 cert *x509.Certificate
306 }
307
308 func TestIssuePrecertificate(t *testing.T) {
309 testCases := []struct {
310 name string
311 csr []byte
312 subTest func(t *testing.T, i *TestCertificateIssuance)
313 }{
314 {"IssuePrecertificate", CNandSANCSR, issueCertificateSubTestIssuePrecertificate},
315 {"ValidityUsesCAClock", CNandSANCSR, issueCertificateSubTestValidityUsesCAClock},
316 {"ProfileSelectionRSA", CNandSANCSR, issueCertificateSubTestProfileSelectionRSA},
317 {"ProfileSelectionECDSA", ECDSACSR, issueCertificateSubTestProfileSelectionECDSA},
318 {"MustStaple", MustStapleCSR, issueCertificateSubTestMustStaple},
319 {"UnknownExtension", UnsupportedExtensionCSR, issueCertificateSubTestUnknownExtension},
320 {"CTPoisonExtension", CTPoisonExtensionCSR, issueCertificateSubTestCTPoisonExtension},
321 {"CTPoisonExtensionEmpty", CTPoisonExtensionEmptyCSR, issueCertificateSubTestCTPoisonExtension},
322 }
323
324 for _, testCase := range testCases {
325
326
327
328
329 for _, mode := range []string{"precertificate", "certificate-for-precertificate"} {
330 ca, sa := issueCertificateSubTestSetup(t, nil)
331
332 t.Run(fmt.Sprintf("%s - %s", mode, testCase.name), func(t *testing.T) {
333 req, err := x509.ParseCertificateRequest(testCase.csr)
334 test.AssertNotError(t, err, "Certificate request failed to parse")
335
336 issueReq := &capb.IssueCertificateRequest{Csr: testCase.csr, RegistrationID: arbitraryRegID}
337
338 var certDER []byte
339 response, err := ca.IssuePrecertificate(ctx, issueReq)
340
341 test.AssertNotError(t, err, "Failed to issue precertificate")
342 certDER = response.DER
343
344 cert, err := x509.ParseCertificate(certDER)
345 test.AssertNotError(t, err, "Certificate failed to parse")
346
347 poisonExtension := findExtension(cert.Extensions, OIDExtensionCTPoison)
348 test.AssertNotNil(t, poisonExtension, "Precert doesn't contain poison extension")
349 if poisonExtension != nil {
350 test.AssertEquals(t, poisonExtension.Critical, true)
351 test.AssertDeepEquals(t, poisonExtension.Value, []byte{0x05, 0x00})
352 }
353
354 i := TestCertificateIssuance{
355 ca: ca,
356 sa: sa,
357 req: req,
358 certDER: certDER,
359 cert: cert,
360 }
361
362 testCase.subTest(t, &i)
363 })
364 }
365 }
366 }
367
368 func issueCertificateSubTestSetup(t *testing.T, e *ECDSAAllowList) (*certificateAuthorityImpl, *mockSA) {
369 testCtx := setup(t)
370 ecdsaAllowList := &ECDSAAllowList{}
371 if e == nil {
372 e = ecdsaAllowList
373 }
374 sa := &mockSA{}
375 ca, err := NewCertificateAuthorityImpl(
376 sa,
377 testCtx.pa,
378 testCtx.boulderIssuers,
379 e,
380 testCtx.certExpiry,
381 testCtx.certBackdate,
382 testCtx.serialPrefix,
383 testCtx.maxNames,
384 testCtx.keyPolicy,
385 testCtx.logger,
386 testCtx.stats,
387 testCtx.signatureCount,
388 testCtx.signErrorCount,
389 testCtx.fc)
390 test.AssertNotError(t, err, "Failed to create CA")
391 return ca, sa
392 }
393
394 func issueCertificateSubTestIssuePrecertificate(t *testing.T, i *TestCertificateIssuance) {
395 cert := i.cert
396
397 test.AssertEquals(t, cert.Subject.CommonName, "not-example.com")
398
399 if len(cert.DNSNames) == 1 {
400 if cert.DNSNames[0] != "not-example.com" {
401 t.Errorf("Improper list of domain names %v", cert.DNSNames)
402 }
403 t.Errorf("Improper list of domain names %v", cert.DNSNames)
404 }
405
406 if len(cert.Subject.Country) > 0 {
407 t.Errorf("Subject contained unauthorized values: %v", cert.Subject)
408 }
409 }
410
411 func issueCertificateSubTestValidityUsesCAClock(t *testing.T, i *TestCertificateIssuance) {
412 test.AssertEquals(t, i.cert.NotBefore, i.ca.clk.Now().Add(-1*i.ca.backdate))
413 test.AssertEquals(t, i.cert.NotAfter.Add(time.Second).Sub(i.cert.NotBefore), i.ca.validityPeriod)
414 }
415
416
417 func TestNoIssuers(t *testing.T) {
418 testCtx := setup(t)
419 sa := &mockSA{}
420 _, err := NewCertificateAuthorityImpl(
421 sa,
422 testCtx.pa,
423 nil,
424 nil,
425 testCtx.certExpiry,
426 testCtx.certBackdate,
427 testCtx.serialPrefix,
428 testCtx.maxNames,
429 testCtx.keyPolicy,
430 testCtx.logger,
431 testCtx.stats,
432 testCtx.signatureCount,
433 testCtx.signErrorCount,
434 testCtx.fc)
435 test.AssertError(t, err, "No issuers found during CA construction.")
436 test.AssertEquals(t, err.Error(), "must have at least one issuer")
437 }
438
439
440 func TestMultipleIssuers(t *testing.T) {
441 testCtx := setup(t)
442 sa := &mockSA{}
443 ca, err := NewCertificateAuthorityImpl(
444 sa,
445 testCtx.pa,
446 testCtx.boulderIssuers,
447 nil,
448 testCtx.certExpiry,
449 testCtx.certBackdate,
450 testCtx.serialPrefix,
451 testCtx.maxNames,
452 testCtx.keyPolicy,
453 testCtx.logger,
454 testCtx.stats,
455 testCtx.signatureCount,
456 testCtx.signErrorCount,
457 testCtx.fc)
458 test.AssertNotError(t, err, "Failed to remake CA")
459
460
461 issuedCert, err := ca.IssuePrecertificate(ctx, &capb.IssueCertificateRequest{Csr: CNandSANCSR, RegistrationID: arbitraryRegID})
462 test.AssertNotError(t, err, "Failed to issue certificate")
463 cert, err := x509.ParseCertificate(issuedCert.DER)
464 test.AssertNotError(t, err, "Certificate failed to parse")
465 err = cert.CheckSignatureFrom(caCert2.Certificate)
466 test.AssertNotError(t, err, "Certificate failed signature validation")
467
468
469 issuedCert, err = ca.IssuePrecertificate(ctx, &capb.IssueCertificateRequest{Csr: ECDSACSR, RegistrationID: arbitraryRegID})
470 test.AssertNotError(t, err, "Failed to issue certificate")
471 cert, err = x509.ParseCertificate(issuedCert.DER)
472 test.AssertNotError(t, err, "Certificate failed to parse")
473 err = cert.CheckSignatureFrom(caCert2.Certificate)
474 test.AssertNotError(t, err, "Certificate failed signature validation")
475 }
476
477 func TestECDSAAllowList(t *testing.T) {
478 req := &capb.IssueCertificateRequest{Csr: ECDSACSR, RegistrationID: arbitraryRegID}
479
480
481 regIDMap := makeRegIDsMap([]int64{arbitraryRegID})
482 ca, _ := issueCertificateSubTestSetup(t, &ECDSAAllowList{regIDMap})
483 result, err := ca.IssuePrecertificate(ctx, req)
484 test.AssertNotError(t, err, "Failed to issue certificate")
485 cert, err := x509.ParseCertificate(result.DER)
486 test.AssertNotError(t, err, "Certificate failed to parse")
487 test.AssertByteEquals(t, cert.RawIssuer, caCert2.RawSubject)
488
489
490 regIDMap = makeRegIDsMap([]int64{2002})
491 ca, _ = issueCertificateSubTestSetup(t, &ECDSAAllowList{regIDMap})
492 result, err = ca.IssuePrecertificate(ctx, req)
493 test.AssertNotError(t, err, "Failed to issue certificate")
494 cert, err = x509.ParseCertificate(result.DER)
495 test.AssertNotError(t, err, "Certificate failed to parse")
496 test.AssertByteEquals(t, cert.RawIssuer, caCert.RawSubject)
497
498
499 ca, _ = issueCertificateSubTestSetup(t, nil)
500 _ = features.Set(map[string]bool{"ECDSAForAll": true})
501 defer features.Reset()
502 result, err = ca.IssuePrecertificate(ctx, req)
503 test.AssertNotError(t, err, "Failed to issue certificate")
504 cert, err = x509.ParseCertificate(result.DER)
505 test.AssertNotError(t, err, "Certificate failed to parse")
506 test.AssertByteEquals(t, cert.RawIssuer, caCert2.RawSubject)
507 }
508
509 func TestInvalidCSRs(t *testing.T) {
510 testCases := []struct {
511 name string
512 csrPath string
513 check func(t *testing.T, ca *certificateAuthorityImpl, sa *mockSA)
514 errorMessage string
515 errorType berrors.ErrorType
516 }{
517
518
519
520
521
522
523 {"RejectNoHostnames", "./testdata/no_names.der.csr", nil, "Issued certificate with no names", berrors.BadCSR},
524
525
526
527
528
529
530
531 {"RejectTooManyHostnames", "./testdata/too_many_names.der.csr", nil, "Issued certificate with too many names", berrors.BadCSR},
532
533
534
535
536
537
538
539 {"RejectShortKey", "./testdata/short_key.der.csr", nil, "Issued a certificate with too short a key.", berrors.BadCSR},
540
541
542
543
544
545
546
547
548 {"RejectBadAlgorithm", "./testdata/bad_algorithm.der.csr", nil, "Issued a certificate based on a CSR with a bad signature algorithm.", berrors.BadCSR},
549
550
551
552
553
554 {"RejectLongCommonName", "./testdata/long_cn.der.csr", nil, "Issued a certificate with a CN over 64 bytes.", berrors.BadCSR},
555
556
557
558 {"RejectWrongSignature", "./testdata/invalid_signature.der.csr", nil, "Issued a certificate based on a CSR with an invalid signature.", berrors.BadCSR},
559 }
560
561 for _, testCase := range testCases {
562 testCtx := setup(t)
563 sa := &mockSA{}
564 ca, err := NewCertificateAuthorityImpl(
565 sa,
566 testCtx.pa,
567 testCtx.boulderIssuers,
568 nil,
569 testCtx.certExpiry,
570 testCtx.certBackdate,
571 testCtx.serialPrefix,
572 testCtx.maxNames,
573 testCtx.keyPolicy,
574 testCtx.logger,
575 testCtx.stats,
576 testCtx.signatureCount,
577 testCtx.signErrorCount,
578 testCtx.fc)
579 test.AssertNotError(t, err, "Failed to create CA")
580
581 t.Run(testCase.name, func(t *testing.T) {
582 serializedCSR := mustRead(testCase.csrPath)
583 issueReq := &capb.IssueCertificateRequest{Csr: serializedCSR, RegistrationID: arbitraryRegID}
584 _, err = ca.IssuePrecertificate(ctx, issueReq)
585
586 test.AssertErrorIs(t, err, testCase.errorType)
587 test.AssertMetricWithLabelsEquals(t, ca.signatureCount, prometheus.Labels{"purpose": "cert"}, 0)
588
589 test.AssertError(t, err, testCase.errorMessage)
590 if testCase.check != nil {
591 testCase.check(t, ca, sa)
592 }
593 })
594 }
595 }
596
597 func TestRejectValidityTooLong(t *testing.T) {
598 testCtx := setup(t)
599 sa := &mockSA{}
600 ca, err := NewCertificateAuthorityImpl(
601 sa,
602 testCtx.pa,
603 testCtx.boulderIssuers,
604 nil,
605 testCtx.certExpiry,
606 testCtx.certBackdate,
607 testCtx.serialPrefix,
608 testCtx.maxNames,
609 testCtx.keyPolicy,
610 testCtx.logger,
611 testCtx.stats,
612 nil,
613 nil,
614 testCtx.fc)
615 test.AssertNotError(t, err, "Failed to create CA")
616
617
618 future, err := time.Parse(time.RFC3339, "2025-02-10T00:30:00Z")
619
620 test.AssertNotError(t, err, "Failed to parse time")
621 testCtx.fc.Set(future)
622
623 _, err = ca.IssuePrecertificate(ctx, &capb.IssueCertificateRequest{Csr: CNandSANCSR, RegistrationID: arbitraryRegID})
624 test.AssertError(t, err, "Cannot issue a certificate that expires after the intermediate certificate")
625 test.AssertErrorIs(t, err, berrors.InternalServer)
626 }
627
628 func issueCertificateSubTestProfileSelectionRSA(t *testing.T, i *TestCertificateIssuance) {
629
630 expectedKeyUsage := x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment
631 t.Logf("expected key usage %v, got %v", expectedKeyUsage, i.cert.KeyUsage)
632 test.AssertEquals(t, i.cert.KeyUsage, expectedKeyUsage)
633 }
634
635 func issueCertificateSubTestProfileSelectionECDSA(t *testing.T, i *TestCertificateIssuance) {
636
637 expectedKeyUsage := x509.KeyUsageDigitalSignature
638 t.Logf("expected key usage %v, got %v", expectedKeyUsage, i.cert.KeyUsage)
639 test.AssertEquals(t, i.cert.KeyUsage, expectedKeyUsage)
640 }
641
642 func countMustStaple(t *testing.T, cert *x509.Certificate) (count int) {
643 oidTLSFeature := asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 24}
644 mustStapleFeatureValue := []byte{0x30, 0x03, 0x02, 0x01, 0x05}
645 for _, ext := range cert.Extensions {
646 if ext.Id.Equal(oidTLSFeature) {
647 test.Assert(t, !ext.Critical, "Extension was marked critical")
648 test.AssertByteEquals(t, ext.Value, mustStapleFeatureValue)
649 count++
650 }
651 }
652 return count
653 }
654
655 func issueCertificateSubTestMustStaple(t *testing.T, i *TestCertificateIssuance) {
656 test.AssertMetricWithLabelsEquals(t, i.ca.signatureCount, prometheus.Labels{"purpose": "precertificate"}, 1)
657 test.AssertEquals(t, countMustStaple(t, i.cert), 1)
658 }
659
660 func issueCertificateSubTestUnknownExtension(t *testing.T, i *TestCertificateIssuance) {
661 test.AssertMetricWithLabelsEquals(t, i.ca.signatureCount, prometheus.Labels{"purpose": "precertificate"}, 1)
662
663
664
665 expectedExtensionCount := 10
666 test.AssertEquals(t, len(i.cert.Extensions), expectedExtensionCount)
667 }
668
669 func issueCertificateSubTestCTPoisonExtension(t *testing.T, i *TestCertificateIssuance) {
670 test.AssertMetricWithLabelsEquals(t, i.ca.signatureCount, prometheus.Labels{"purpose": "precertificate"}, 1)
671 }
672
673 func findExtension(extensions []pkix.Extension, id asn1.ObjectIdentifier) *pkix.Extension {
674 for _, ext := range extensions {
675 if ext.Id.Equal(id) {
676 return &ext
677 }
678 }
679 return nil
680 }
681
682 func makeSCTs() ([][]byte, error) {
683 sct := ct.SignedCertificateTimestamp{
684 SCTVersion: 0,
685 Timestamp: 2020,
686 Signature: ct.DigitallySigned{
687 Signature: []byte{0},
688 },
689 }
690 sctBytes, err := cttls.Marshal(sct)
691 if err != nil {
692 return nil, err
693 }
694 return [][]byte{sctBytes}, err
695 }
696
697 func TestIssueCertificateForPrecertificate(t *testing.T) {
698 testCtx := setup(t)
699 sa := &mockSA{}
700 ca, err := NewCertificateAuthorityImpl(
701 sa,
702 testCtx.pa,
703 testCtx.boulderIssuers,
704 nil,
705 testCtx.certExpiry,
706 testCtx.certBackdate,
707 testCtx.serialPrefix,
708 testCtx.maxNames,
709 testCtx.keyPolicy,
710 testCtx.logger,
711 testCtx.stats,
712 testCtx.signatureCount,
713 testCtx.signErrorCount,
714 testCtx.fc)
715 test.AssertNotError(t, err, "Failed to create CA")
716
717 issueReq := capb.IssueCertificateRequest{Csr: CNandSANCSR, RegistrationID: arbitraryRegID, OrderID: 0}
718 precert, err := ca.IssuePrecertificate(ctx, &issueReq)
719 test.AssertNotError(t, err, "Failed to issue precert")
720 parsedPrecert, err := x509.ParseCertificate(precert.DER)
721 test.AssertNotError(t, err, "Failed to parse precert")
722
723
724 poisonExtension := findExtension(parsedPrecert.Extensions, OIDExtensionCTPoison)
725 test.AssertNotNil(t, poisonExtension, "Couldn't find CTPoison extension")
726 test.AssertEquals(t, poisonExtension.Critical, true)
727 test.AssertDeepEquals(t, poisonExtension.Value, []byte{0x05, 0x00})
728
729 sctBytes, err := makeSCTs()
730 if err != nil {
731 t.Fatal(err)
732 }
733
734 test.AssertNotError(t, err, "Failed to marshal SCT")
735 cert, err := ca.IssueCertificateForPrecertificate(ctx, &capb.IssueCertificateForPrecertificateRequest{
736 DER: precert.DER,
737 SCTs: sctBytes,
738 RegistrationID: arbitraryRegID,
739 OrderID: 0,
740 })
741 test.AssertNotError(t, err, "Failed to issue cert from precert")
742 parsedCert, err := x509.ParseCertificate(cert.Der)
743 test.AssertNotError(t, err, "Failed to parse cert")
744
745
746 sctListExtension := findExtension(parsedCert.Extensions, OIDExtensionSCTList)
747 test.AssertNotNil(t, sctListExtension, "Couldn't find SCTList extension")
748 test.AssertEquals(t, sctListExtension.Critical, false)
749 var rawValue []byte
750 _, err = asn1.Unmarshal(sctListExtension.Value, &rawValue)
751 test.AssertNotError(t, err, "Failed to unmarshal extension value")
752 sctList, err := deserializeSCTList(rawValue)
753 test.AssertNotError(t, err, "Failed to deserialize SCT list")
754 test.Assert(t, len(sctList) == 1, fmt.Sprintf("Wrong number of SCTs, wanted: 1, got: %d", len(sctList)))
755 }
756
757
758
759 func deserializeSCTList(serializedSCTList []byte) ([]ct.SignedCertificateTimestamp, error) {
760 var sctList ctx509.SignedCertificateTimestampList
761 rest, err := cttls.Unmarshal(serializedSCTList, &sctList)
762 if err != nil {
763 return nil, err
764 }
765 if len(rest) != 0 {
766 return nil, errors.New("serialized SCT list contained trailing garbage")
767 }
768 list := make([]ct.SignedCertificateTimestamp, len(sctList.SCTList))
769 for i, serializedSCT := range sctList.SCTList {
770 var sct ct.SignedCertificateTimestamp
771 rest, err := cttls.Unmarshal(serializedSCT.Val, &sct)
772 if err != nil {
773 return nil, err
774 }
775 if len(rest) != 0 {
776 return nil, errors.New("serialized SCT contained trailing garbage")
777 }
778 list[i] = sct
779 }
780 return list, nil
781 }
782
783
784
785 type dupeSA struct {
786 mockSA
787 }
788
789 func (m *dupeSA) GetCertificate(ctx context.Context, req *sapb.Serial, _ ...grpc.CallOption) (*corepb.Certificate, error) {
790 return nil, nil
791 }
792
793
794 type getCertErrorSA struct {
795 mockSA
796 }
797
798 func (m *getCertErrorSA) GetCertificate(ctx context.Context, req *sapb.Serial, _ ...grpc.CallOption) (*corepb.Certificate, error) {
799 return nil, fmt.Errorf("i don't like it")
800 }
801
802 func TestIssueCertificateForPrecertificateDuplicateSerial(t *testing.T) {
803 testCtx := setup(t)
804 sa := &dupeSA{}
805 ca, err := NewCertificateAuthorityImpl(
806 sa,
807 testCtx.pa,
808 testCtx.boulderIssuers,
809 nil,
810 testCtx.certExpiry,
811 testCtx.certBackdate,
812 testCtx.serialPrefix,
813 testCtx.maxNames,
814 testCtx.keyPolicy,
815 testCtx.logger,
816 testCtx.stats,
817 testCtx.signatureCount,
818 testCtx.signErrorCount,
819 testCtx.fc)
820 test.AssertNotError(t, err, "Failed to create CA")
821
822 sctBytes, err := makeSCTs()
823 if err != nil {
824 t.Fatal(err)
825 }
826
827 issueReq := capb.IssueCertificateRequest{Csr: CNandSANCSR, RegistrationID: arbitraryRegID, OrderID: 0}
828 precert, err := ca.IssuePrecertificate(ctx, &issueReq)
829 test.AssertNotError(t, err, "Failed to issue precert")
830 _, err = ca.IssueCertificateForPrecertificate(ctx, &capb.IssueCertificateForPrecertificateRequest{
831 DER: precert.DER,
832 SCTs: sctBytes,
833 RegistrationID: arbitraryRegID,
834 OrderID: 0,
835 })
836 if err == nil {
837 t.Error("Expected error issuing duplicate serial but got none.")
838 }
839 if !strings.Contains(err.Error(), "issuance of duplicate final certificate requested") {
840 t.Errorf("Wrong type of error issuing duplicate serial. Expected 'issuance of duplicate', got '%s'", err)
841 }
842
843
844
845 errorsa := &getCertErrorSA{}
846 errorca, err := NewCertificateAuthorityImpl(
847 errorsa,
848 testCtx.pa,
849 testCtx.boulderIssuers,
850 nil,
851 testCtx.certExpiry,
852 testCtx.certBackdate,
853 testCtx.serialPrefix,
854 testCtx.maxNames,
855 testCtx.keyPolicy,
856 testCtx.logger,
857 testCtx.stats,
858 testCtx.signatureCount,
859 testCtx.signErrorCount,
860 testCtx.fc)
861 test.AssertNotError(t, err, "Failed to create CA")
862
863 _, err = errorca.IssueCertificateForPrecertificate(ctx, &capb.IssueCertificateForPrecertificateRequest{
864 DER: precert.DER,
865 SCTs: sctBytes,
866 RegistrationID: arbitraryRegID,
867 OrderID: 0,
868 })
869 if err == nil {
870 t.Fatal("Expected error issuing duplicate serial but got none.")
871 }
872 if !strings.Contains(err.Error(), "error checking for duplicate") {
873 t.Fatalf("Wrong type of error issuing duplicate serial. Expected 'error checking for duplicate', got '%s'", err)
874 }
875 }
876
View as plain text