1 package issuance
2
3 import (
4 "crypto"
5 "crypto/dsa"
6 "crypto/ecdsa"
7 "crypto/ed25519"
8 "crypto/elliptic"
9 "crypto/rand"
10 "crypto/rsa"
11 "crypto/x509"
12 "crypto/x509/pkix"
13 "encoding/asn1"
14 "encoding/base64"
15 "fmt"
16 "math/big"
17 "os"
18 "strings"
19 "testing"
20 "time"
21
22 ct "github.com/google/certificate-transparency-go"
23 "github.com/jmhodges/clock"
24
25 "github.com/letsencrypt/boulder/cmd"
26 "github.com/letsencrypt/boulder/config"
27 "github.com/letsencrypt/boulder/core"
28 "github.com/letsencrypt/boulder/ctpolicy/loglist"
29 "github.com/letsencrypt/boulder/linter"
30 "github.com/letsencrypt/boulder/test"
31 )
32
33 func defaultProfileConfig() ProfileConfig {
34 return ProfileConfig{
35 AllowCommonName: true,
36 AllowCTPoison: true,
37 AllowSCTList: true,
38 AllowMustStaple: true,
39 MaxValidityPeriod: config.Duration{Duration: time.Hour},
40 MaxValidityBackdate: config.Duration{Duration: time.Hour},
41 }
42 }
43
44 func defaultIssuerConfig() IssuerConfig {
45 return IssuerConfig{
46 UseForECDSALeaves: true,
47 UseForRSALeaves: true,
48 IssuerURL: "http://issuer-url",
49 OCSPURL: "http://ocsp-url",
50 }
51 }
52
53 func defaultProfile() *Profile {
54 p, _ := NewProfile(defaultProfileConfig(), defaultIssuerConfig())
55 return p
56 }
57
58 var issuerCert *Certificate
59 var issuerSigner *ecdsa.PrivateKey
60
61 func TestMain(m *testing.M) {
62 tk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
63 cmd.FailOnError(err, "failed to generate test key")
64 issuerSigner = tk
65 template := &x509.Certificate{
66 SerialNumber: big.NewInt(123),
67 BasicConstraintsValid: true,
68 IsCA: true,
69 Subject: pkix.Name{
70 CommonName: "big ca",
71 },
72 KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature,
73 }
74 issuer, err := x509.CreateCertificate(rand.Reader, template, template, tk.Public(), tk)
75 cmd.FailOnError(err, "failed to generate test issuer")
76 cert, err := x509.ParseCertificate(issuer)
77 cmd.FailOnError(err, "failed to parse test issuer")
78 issuerCert = &Certificate{Certificate: cert}
79 os.Exit(m.Run())
80 }
81
82 func TestNewProfileNoIssuerURL(t *testing.T) {
83 _, err := NewProfile(ProfileConfig{}, IssuerConfig{})
84 test.AssertError(t, err, "NewProfile didn't fail with no issuer URL")
85 test.AssertEquals(t, err.Error(), "Issuer URL is required")
86 }
87
88 func TestNewProfileNoOCSPURL(t *testing.T) {
89 _, err := NewProfile(ProfileConfig{}, IssuerConfig{IssuerURL: "issuer-url"})
90 test.AssertError(t, err, "NewProfile didn't fail with no OCSP URL")
91 test.AssertEquals(t, err.Error(), "OCSP URL is required")
92 }
93
94 func TestRequestValid(t *testing.T) {
95 fc := clock.NewFake()
96 fc.Add(time.Hour * 24)
97 tests := []struct {
98 name string
99 profile *Profile
100 request *IssuanceRequest
101 expectedError string
102 }{
103 {
104 name: "unsupported key type",
105 profile: &Profile{},
106 request: &IssuanceRequest{PublicKey: &dsa.PublicKey{}},
107 expectedError: "unsupported public key type",
108 },
109 {
110 name: "cannot sign rsa",
111 profile: &Profile{},
112 request: &IssuanceRequest{PublicKey: &rsa.PublicKey{}},
113 expectedError: "cannot sign RSA public keys",
114 },
115 {
116 name: "cannot sign ecdsa",
117 profile: &Profile{},
118 request: &IssuanceRequest{PublicKey: &ecdsa.PublicKey{}},
119 expectedError: "cannot sign ECDSA public keys",
120 },
121 {
122 name: "must staple not allowed",
123 profile: &Profile{
124 useForECDSALeaves: true,
125 },
126 request: &IssuanceRequest{
127 PublicKey: &ecdsa.PublicKey{},
128 IncludeMustStaple: true,
129 },
130 expectedError: "must-staple extension cannot be included",
131 },
132 {
133 name: "ct poison not allowed",
134 profile: &Profile{
135 useForECDSALeaves: true,
136 },
137 request: &IssuanceRequest{
138 PublicKey: &ecdsa.PublicKey{},
139 IncludeCTPoison: true,
140 },
141 expectedError: "ct poison extension cannot be included",
142 },
143 {
144 name: "sct list not allowed",
145 profile: &Profile{
146 useForECDSALeaves: true,
147 },
148 request: &IssuanceRequest{
149 PublicKey: &ecdsa.PublicKey{},
150 sctList: []ct.SignedCertificateTimestamp{},
151 },
152 expectedError: "sct list extension cannot be included",
153 },
154 {
155 name: "sct list and ct poison not allowed",
156 profile: &Profile{
157 useForECDSALeaves: true,
158 allowCTPoison: true,
159 allowSCTList: true,
160 },
161 request: &IssuanceRequest{
162 PublicKey: &ecdsa.PublicKey{},
163 IncludeCTPoison: true,
164 sctList: []ct.SignedCertificateTimestamp{},
165 },
166 expectedError: "cannot include both ct poison and sct list extensions",
167 },
168 {
169 name: "common name not allowed",
170 profile: &Profile{
171 useForECDSALeaves: true,
172 },
173 request: &IssuanceRequest{
174 PublicKey: &ecdsa.PublicKey{},
175 CommonName: "cn",
176 },
177 expectedError: "common name cannot be included",
178 },
179 {
180 name: "negative validity",
181 profile: &Profile{
182 useForECDSALeaves: true,
183 },
184 request: &IssuanceRequest{
185 PublicKey: &ecdsa.PublicKey{},
186 NotBefore: fc.Now().Add(time.Hour),
187 NotAfter: fc.Now(),
188 },
189 expectedError: "NotAfter must be after NotBefore",
190 },
191 {
192 name: "validity larger than max",
193 profile: &Profile{
194 useForECDSALeaves: true,
195 maxValidity: time.Minute,
196 },
197 request: &IssuanceRequest{
198 PublicKey: &ecdsa.PublicKey{},
199 NotBefore: fc.Now(),
200 NotAfter: fc.Now().Add(time.Hour - time.Second),
201 },
202 expectedError: "validity period is more than the maximum allowed period (1h0m0s>1m0s)",
203 },
204 {
205 name: "validity larger than max due to inclusivity",
206 profile: &Profile{
207 useForECDSALeaves: true,
208 maxValidity: time.Hour,
209 },
210 request: &IssuanceRequest{
211 PublicKey: &ecdsa.PublicKey{},
212 NotBefore: fc.Now(),
213 NotAfter: fc.Now().Add(time.Hour),
214 },
215 expectedError: "validity period is more than the maximum allowed period (1h0m1s>1h0m0s)",
216 },
217 {
218 name: "validity backdated more than max",
219 profile: &Profile{
220 useForECDSALeaves: true,
221 maxValidity: time.Hour * 2,
222 maxBackdate: time.Hour,
223 },
224 request: &IssuanceRequest{
225 PublicKey: &ecdsa.PublicKey{},
226 NotBefore: fc.Now().Add(-time.Hour * 2),
227 NotAfter: fc.Now().Add(-time.Hour),
228 },
229 expectedError: "NotBefore is backdated more than the maximum allowed period (2h0m0s>1h0m0s)",
230 },
231 {
232 name: "validity is forward dated",
233 profile: &Profile{
234 useForECDSALeaves: true,
235 maxValidity: time.Hour * 2,
236 maxBackdate: time.Hour,
237 },
238 request: &IssuanceRequest{
239 PublicKey: &ecdsa.PublicKey{},
240 NotBefore: fc.Now().Add(time.Hour),
241 NotAfter: fc.Now().Add(time.Hour * 2),
242 },
243 expectedError: "NotBefore is in the future",
244 },
245 {
246 name: "serial too short",
247 profile: &Profile{
248 useForECDSALeaves: true,
249 maxValidity: time.Hour * 2,
250 },
251 request: &IssuanceRequest{
252 PublicKey: &ecdsa.PublicKey{},
253 NotBefore: fc.Now(),
254 NotAfter: fc.Now().Add(time.Hour),
255 Serial: []byte{0, 1, 2, 3, 4, 5, 6, 7},
256 },
257 expectedError: "serial must be between 9 and 19 bytes",
258 },
259 {
260 name: "serial too long",
261 profile: &Profile{
262 useForECDSALeaves: true,
263 maxValidity: time.Hour * 2,
264 },
265 request: &IssuanceRequest{
266 PublicKey: &ecdsa.PublicKey{},
267 NotBefore: fc.Now(),
268 NotAfter: fc.Now().Add(time.Hour),
269 Serial: []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
270 },
271 expectedError: "serial must be between 9 and 19 bytes",
272 },
273 {
274 name: "good",
275 profile: &Profile{
276 useForECDSALeaves: true,
277 maxValidity: time.Hour * 2,
278 },
279 request: &IssuanceRequest{
280 PublicKey: &ecdsa.PublicKey{},
281 NotBefore: fc.Now(),
282 NotAfter: fc.Now().Add(time.Hour),
283 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
284 },
285 },
286 }
287 for _, tc := range tests {
288 t.Run(tc.name, func(t *testing.T) {
289 err := tc.profile.requestValid(fc, tc.request)
290 if err != nil {
291 if tc.expectedError == "" {
292 t.Errorf("failed with unexpected error: %s", err)
293 } else if tc.expectedError != err.Error() {
294 t.Errorf("failed with unexpected error, wanted: %q, got: %q", tc.expectedError, err.Error())
295 }
296 return
297 } else if tc.expectedError != "" {
298 t.Errorf("didn't fail, expected %q", tc.expectedError)
299 }
300 })
301 }
302 }
303
304 func TestGenerateTemplate(t *testing.T) {
305 tests := []struct {
306 name string
307 profile *Profile
308 expectedTemplate *x509.Certificate
309 }{
310 {
311 name: "crl url",
312 profile: &Profile{
313 crlURL: "crl-url",
314 sigAlg: x509.SHA256WithRSA,
315 },
316 expectedTemplate: &x509.Certificate{
317 BasicConstraintsValid: true,
318 SignatureAlgorithm: x509.SHA256WithRSA,
319 ExtKeyUsage: defaultEKU,
320 IssuingCertificateURL: []string{""},
321 OCSPServer: []string{""},
322 CRLDistributionPoints: []string{"crl-url"},
323 PolicyIdentifiers: []asn1.ObjectIdentifier{{2, 23, 140, 1, 2, 1}},
324 },
325 },
326 }
327
328 for _, tc := range tests {
329 t.Run(tc.name, func(t *testing.T) {
330 template := tc.profile.generateTemplate()
331 test.AssertDeepEquals(t, *template, *tc.expectedTemplate)
332 })
333 }
334 }
335
336 func TestNewIssuer(t *testing.T) {
337 _, err := NewIssuer(
338 issuerCert,
339 issuerSigner,
340 defaultProfile(),
341 &linter.Linter{},
342 clock.NewFake(),
343 )
344 test.AssertNotError(t, err, "NewIssuer failed")
345 }
346
347 func TestNewIssuerUnsupportedKeyType(t *testing.T) {
348 _, err := NewIssuer(
349 &Certificate{
350 Certificate: &x509.Certificate{
351 PublicKey: &ed25519.PublicKey{},
352 },
353 },
354 &ed25519.PrivateKey{},
355 defaultProfile(),
356 &linter.Linter{},
357 clock.NewFake(),
358 )
359 test.AssertError(t, err, "NewIssuer didn't fail")
360 test.AssertEquals(t, err.Error(), "unsupported issuer key type")
361 }
362
363 func TestNewIssuerNoCertSign(t *testing.T) {
364 _, err := NewIssuer(
365 &Certificate{
366 Certificate: &x509.Certificate{
367 PublicKey: &ecdsa.PublicKey{
368 Curve: elliptic.P256(),
369 },
370 KeyUsage: 0,
371 },
372 },
373 issuerSigner,
374 defaultProfile(),
375 &linter.Linter{},
376 clock.NewFake(),
377 )
378 test.AssertError(t, err, "NewIssuer didn't fail")
379 test.AssertEquals(t, err.Error(), "end-entity signing cert does not have keyUsage certSign")
380 }
381
382 func TestNewIssuerNoDigitalSignature(t *testing.T) {
383 _, err := NewIssuer(
384 &Certificate{
385 Certificate: &x509.Certificate{
386 PublicKey: &ecdsa.PublicKey{
387 Curve: elliptic.P256(),
388 },
389 KeyUsage: x509.KeyUsageCertSign,
390 },
391 },
392 issuerSigner,
393 defaultProfile(),
394 &linter.Linter{},
395 clock.NewFake(),
396 )
397 test.AssertError(t, err, "NewIssuer didn't fail")
398 test.AssertEquals(t, err.Error(), "end-entity ocsp signing cert does not have keyUsage digitalSignature")
399 }
400
401 func TestNewIssuerOCSPOnly(t *testing.T) {
402 p := defaultProfile()
403 p.useForRSALeaves = false
404 p.useForECDSALeaves = false
405 _, err := NewIssuer(
406 &Certificate{
407 Certificate: &x509.Certificate{
408 PublicKey: &ecdsa.PublicKey{
409 Curve: elliptic.P256(),
410 },
411 KeyUsage: x509.KeyUsageDigitalSignature,
412 },
413 },
414 issuerSigner,
415 p,
416 &linter.Linter{},
417 clock.NewFake(),
418 )
419 test.AssertNotError(t, err, "NewIssuer failed")
420 }
421
422 func TestIssue(t *testing.T) {
423 for _, tc := range []struct {
424 name string
425 generateFunc func() (crypto.Signer, error)
426 ku x509.KeyUsage
427 }{
428 {
429 name: "RSA",
430 generateFunc: func() (crypto.Signer, error) {
431 return rsa.GenerateKey(rand.Reader, 2048)
432 },
433 ku: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
434 },
435 {
436 name: "ECDSA",
437 generateFunc: func() (crypto.Signer, error) {
438 return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
439 },
440 ku: x509.KeyUsageDigitalSignature,
441 },
442 } {
443 t.Run(tc.name, func(t *testing.T) {
444 fc := clock.NewFake()
445 fc.Set(time.Now())
446 linter, err := linter.New(
447 issuerCert.Certificate,
448 issuerSigner,
449 []string{
450 "w_ct_sct_policy_count_unsatisfied",
451 "e_scts_from_same_operator",
452 "n_subject_common_name_included",
453 },
454 )
455 test.AssertNotError(t, err, "failed to create linter")
456 signer, err := NewIssuer(issuerCert, issuerSigner, defaultProfile(), linter, fc)
457 test.AssertNotError(t, err, "NewIssuer failed")
458 pk, err := tc.generateFunc()
459 test.AssertNotError(t, err, "failed to generate test key")
460 lintCertBytes, issuanceToken, err := signer.Prepare(&IssuanceRequest{
461 PublicKey: pk.Public(),
462 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
463 CommonName: "example.com",
464 DNSNames: []string{"example.com"},
465 NotBefore: fc.Now(),
466 NotAfter: fc.Now().Add(time.Hour - time.Second),
467 IncludeCTPoison: true,
468 })
469 test.AssertNotError(t, err, "Prepare failed")
470 _, err = x509.ParseCertificate(lintCertBytes)
471 test.AssertNotError(t, err, "failed to parse certificate")
472 certBytes, err := signer.Issue(issuanceToken)
473 test.AssertNotError(t, err, "Issue failed")
474 cert, err := x509.ParseCertificate(certBytes)
475 test.AssertNotError(t, err, "failed to parse certificate")
476 err = cert.CheckSignatureFrom(issuerCert.Certificate)
477 test.AssertNotError(t, err, "signature validation failed")
478 test.AssertDeepEquals(t, cert.DNSNames, []string{"example.com"})
479 test.AssertEquals(t, cert.Subject.CommonName, "example.com")
480 test.AssertByteEquals(t, cert.SerialNumber.Bytes(), []byte{1, 2, 3, 4, 5, 6, 7, 8, 9})
481 test.AssertDeepEquals(t, cert.PublicKey, pk.Public())
482 test.AssertEquals(t, len(cert.Extensions), 9)
483 test.AssertEquals(t, cert.KeyUsage, tc.ku)
484 })
485 }
486 }
487
488 func TestIssueRSA(t *testing.T) {
489 fc := clock.NewFake()
490 fc.Set(time.Now())
491 linter, err := linter.New(
492 issuerCert.Certificate,
493 issuerSigner,
494 []string{
495 "w_ct_sct_policy_count_unsatisfied",
496 "e_scts_from_same_operator",
497 },
498 )
499 test.AssertNotError(t, err, "failed to create linter")
500 signer, err := NewIssuer(issuerCert, issuerSigner, defaultProfile(), linter, fc)
501 test.AssertNotError(t, err, "NewIssuer failed")
502 pk, err := rsa.GenerateKey(rand.Reader, 2048)
503 test.AssertNotError(t, err, "failed to generate test key")
504 _, issuanceToken, err := signer.Prepare(&IssuanceRequest{
505 PublicKey: pk.Public(),
506 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
507 DNSNames: []string{"example.com"},
508 NotBefore: fc.Now(),
509 NotAfter: fc.Now().Add(time.Hour - time.Second),
510 IncludeCTPoison: true,
511 })
512 test.AssertNotError(t, err, "failed to prepare lint certificate")
513 certBytes, err := signer.Issue(issuanceToken)
514 test.AssertNotError(t, err, "failed to parse certificate")
515 cert, err := x509.ParseCertificate(certBytes)
516 test.AssertNotError(t, err, "failed to parse certificate")
517 err = cert.CheckSignatureFrom(issuerCert.Certificate)
518 test.AssertNotError(t, err, "signature validation failed")
519 test.AssertByteEquals(t, cert.SerialNumber.Bytes(), []byte{1, 2, 3, 4, 5, 6, 7, 8, 9})
520 test.AssertDeepEquals(t, cert.PublicKey, pk.Public())
521 test.AssertEquals(t, len(cert.Extensions), 9)
522 test.AssertEquals(t, cert.KeyUsage, x509.KeyUsageDigitalSignature|x509.KeyUsageKeyEncipherment)
523 }
524
525 func TestIssueCommonName(t *testing.T) {
526 fc := clock.NewFake()
527 fc.Set(time.Now())
528 linter, err := linter.New(
529 issuerCert.Certificate,
530 issuerSigner,
531 []string{
532 "w_ct_sct_policy_count_unsatisfied",
533 "e_scts_from_same_operator",
534 "n_subject_common_name_included",
535 },
536 )
537 test.AssertNotError(t, err, "failed to create linter")
538 signer, err := NewIssuer(issuerCert, issuerSigner, defaultProfile(), linter, fc)
539 test.AssertNotError(t, err, "NewIssuer failed")
540 pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
541 test.AssertNotError(t, err, "failed to generate test key")
542 ir := &IssuanceRequest{
543 PublicKey: pk.Public(),
544 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
545 CommonName: "example.com",
546 DNSNames: []string{"example.com", "www.example.com"},
547 NotBefore: fc.Now(),
548 NotAfter: fc.Now().Add(time.Hour - time.Second),
549 IncludeCTPoison: true,
550 }
551
552 _, issuanceToken, err := signer.Prepare(ir)
553 test.AssertNotError(t, err, "Prepare failed")
554 certBytes, err := signer.Issue(issuanceToken)
555 test.AssertNotError(t, err, "Issue failed")
556 cert, err := x509.ParseCertificate(certBytes)
557 test.AssertNotError(t, err, "failed to parse certificate")
558 test.AssertEquals(t, cert.Subject.CommonName, "example.com")
559
560 signer.Profile.allowCommonName = false
561 _, _, err = signer.Prepare(ir)
562 test.AssertError(t, err, "Prepare should have failed")
563
564 ir.CommonName = ""
565 _, issuanceToken, err = signer.Prepare(ir)
566 test.AssertNotError(t, err, "Prepare failed")
567 certBytes, err = signer.Issue(issuanceToken)
568 test.AssertNotError(t, err, "Issue failed")
569 cert, err = x509.ParseCertificate(certBytes)
570 test.AssertNotError(t, err, "failed to parse certificate")
571 test.AssertEquals(t, cert.Subject.CommonName, "")
572 test.AssertDeepEquals(t, cert.DNSNames, []string{"example.com", "www.example.com"})
573 }
574
575 func TestIssueCTPoison(t *testing.T) {
576 fc := clock.NewFake()
577 fc.Set(time.Now())
578 linter, err := linter.New(
579 issuerCert.Certificate,
580 issuerSigner,
581 []string{
582 "w_ct_sct_policy_count_unsatisfied",
583 "e_scts_from_same_operator",
584 },
585 )
586 test.AssertNotError(t, err, "failed to create linter")
587 signer, err := NewIssuer(issuerCert, issuerSigner, defaultProfile(), linter, fc)
588 test.AssertNotError(t, err, "NewIssuer failed")
589 pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
590 test.AssertNotError(t, err, "failed to generate test key")
591 _, issuanceToken, err := signer.Prepare(&IssuanceRequest{
592 PublicKey: pk.Public(),
593 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
594 DNSNames: []string{"example.com"},
595 IncludeCTPoison: true,
596 NotBefore: fc.Now(),
597 NotAfter: fc.Now().Add(time.Hour - time.Second),
598 })
599 test.AssertNotError(t, err, "Prepare failed")
600 certBytes, err := signer.Issue(issuanceToken)
601 test.AssertNotError(t, err, "Issue failed")
602 cert, err := x509.ParseCertificate(certBytes)
603 test.AssertNotError(t, err, "failed to parse certificate")
604 err = cert.CheckSignatureFrom(issuerCert.Certificate)
605 test.AssertNotError(t, err, "signature validation failed")
606 test.AssertByteEquals(t, cert.SerialNumber.Bytes(), []byte{1, 2, 3, 4, 5, 6, 7, 8, 9})
607 test.AssertDeepEquals(t, cert.PublicKey, pk.Public())
608 test.AssertEquals(t, len(cert.Extensions), 9)
609 test.AssertDeepEquals(t, cert.Extensions[8], ctPoisonExt)
610 }
611
612 func mustDecodeB64(b string) []byte {
613 out, err := base64.StdEncoding.DecodeString(b)
614 if err != nil {
615 panic(err)
616 }
617 return out
618 }
619
620 func TestIssueSCTList(t *testing.T) {
621 fc := clock.NewFake()
622 fc.Set(time.Now())
623 err := loglist.InitLintList("../test/ct-test-srv/log_list.json")
624 test.AssertNotError(t, err, "failed to load log list")
625 linter, err := linter.New(
626 issuerCert.Certificate,
627 issuerSigner,
628 []string{},
629 )
630 test.AssertNotError(t, err, "failed to create linter")
631 signer, err := NewIssuer(issuerCert, issuerSigner, defaultProfile(), linter, fc)
632 test.AssertNotError(t, err, "NewIssuer failed")
633 pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
634 test.AssertNotError(t, err, "failed to generate test key")
635 _, issuanceToken, err := signer.Prepare(&IssuanceRequest{
636 PublicKey: pk.Public(),
637 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
638 DNSNames: []string{"example.com"},
639 NotBefore: fc.Now(),
640 NotAfter: fc.Now().Add(time.Hour - time.Second),
641 IncludeCTPoison: true,
642 })
643 test.AssertNotError(t, err, "Prepare failed")
644 precertBytes, err := signer.Issue(issuanceToken)
645 test.AssertNotError(t, err, "Issue failed")
646 precert, err := x509.ParseCertificate(precertBytes)
647 test.AssertNotError(t, err, "failed to parse certificate")
648
649 sctList := []ct.SignedCertificateTimestamp{
650 {
651 SCTVersion: ct.V1,
652 LogID: ct.LogID{KeyID: *(*[32]byte)(mustDecodeB64("OJiMlNA1mMOTLd/pI7q68npCDrlsQeFaqAwasPwEvQM="))},
653 },
654 {
655 SCTVersion: ct.V1,
656 LogID: ct.LogID{KeyID: *(*[32]byte)(mustDecodeB64("UtToynGEyMkkXDMQei8Ll54oMwWHI0IieDEKs12/Td4="))},
657 },
658 }
659
660 request2, err := RequestFromPrecert(precert, sctList)
661 test.AssertNotError(t, err, "generating request from precert")
662
663 _, issuanceToken2, err := signer.Prepare(request2)
664 test.AssertNotError(t, err, "preparing final cert issuance")
665
666 finalCertBytes, err := signer.Issue(issuanceToken2)
667 test.AssertNotError(t, err, "Issue failed")
668
669 finalCert, err := x509.ParseCertificate(finalCertBytes)
670 test.AssertNotError(t, err, "failed to parse certificate")
671
672 err = finalCert.CheckSignatureFrom(issuerCert.Certificate)
673 test.AssertNotError(t, err, "signature validation failed")
674 test.AssertByteEquals(t, finalCert.SerialNumber.Bytes(), []byte{1, 2, 3, 4, 5, 6, 7, 8, 9})
675 test.AssertDeepEquals(t, finalCert.PublicKey, pk.Public())
676 test.AssertEquals(t, len(finalCert.Extensions), 9)
677 test.AssertDeepEquals(t, finalCert.Extensions[8], pkix.Extension{
678 Id: sctListOID,
679 Value: []byte{
680 4, 100, 0, 98, 0, 47, 0, 56, 152, 140, 148, 208, 53, 152, 195, 147, 45,
681 223, 233, 35, 186, 186, 242, 122, 66, 14, 185, 108, 65, 225, 90, 168, 12,
682 26, 176, 252, 4, 189, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47,
683 0, 82, 212, 232, 202, 113, 132, 200, 201, 36, 92, 51, 16, 122, 47, 11,
684 151, 158, 40, 51, 5, 135, 35, 66, 34, 120, 49, 10, 179, 93, 191, 77, 222,
685 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
686 },
687 })
688 }
689
690 func TestIssueMustStaple(t *testing.T) {
691 fc := clock.NewFake()
692 fc.Set(time.Now())
693 linter, err := linter.New(
694 issuerCert.Certificate,
695 issuerSigner,
696 []string{
697 "w_ct_sct_policy_count_unsatisfied",
698 "e_scts_from_same_operator",
699 },
700 )
701 test.AssertNotError(t, err, "failed to create linter")
702 signer, err := NewIssuer(issuerCert, issuerSigner, defaultProfile(), linter, fc)
703 test.AssertNotError(t, err, "NewIssuer failed")
704 pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
705 test.AssertNotError(t, err, "failed to generate test key")
706 _, issuanceToken, err := signer.Prepare(&IssuanceRequest{
707 PublicKey: pk.Public(),
708 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
709 DNSNames: []string{"example.com"},
710 IncludeMustStaple: true,
711 NotBefore: fc.Now(),
712 NotAfter: fc.Now().Add(time.Hour - time.Second),
713 IncludeCTPoison: true,
714 })
715 test.AssertNotError(t, err, "Prepare failed")
716 certBytes, err := signer.Issue(issuanceToken)
717 test.AssertNotError(t, err, "Issue failed")
718 cert, err := x509.ParseCertificate(certBytes)
719 test.AssertNotError(t, err, "failed to parse certificate")
720 err = cert.CheckSignatureFrom(issuerCert.Certificate)
721 test.AssertNotError(t, err, "signature validation failed")
722 test.AssertByteEquals(t, cert.SerialNumber.Bytes(), []byte{1, 2, 3, 4, 5, 6, 7, 8, 9})
723 test.AssertDeepEquals(t, cert.PublicKey, pk.Public())
724 test.AssertEquals(t, len(cert.Extensions), 10)
725 test.AssertDeepEquals(t, cert.Extensions[9], mustStapleExt)
726 }
727
728 func TestIssueBadLint(t *testing.T) {
729 fc := clock.NewFake()
730 fc.Set(time.Now())
731 lint, err := linter.New(issuerCert.Certificate, issuerSigner, []string{})
732 test.AssertNotError(t, err, "failed to create linter")
733 signer, err := NewIssuer(issuerCert, issuerSigner, defaultProfile(), lint, fc)
734 test.AssertNotError(t, err, "NewIssuer failed")
735 pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
736 test.AssertNotError(t, err, "failed to generate test key")
737 _, _, err = signer.Prepare(&IssuanceRequest{
738 PublicKey: pk.Public(),
739 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
740 DNSNames: []string{"example-com"},
741 NotBefore: fc.Now(),
742 NotAfter: fc.Now().Add(time.Hour - time.Second),
743 IncludeCTPoison: true,
744 })
745 test.AssertError(t, err, "Prepare didn't fail")
746 test.AssertErrorIs(t, err, linter.ErrLinting)
747 test.AssertContains(t, err.Error(), "tbsCertificate linting failed: failed lint(s)")
748 }
749
750 func TestLoadChain_Valid(t *testing.T) {
751 chain, err := LoadChain([]string{
752 "../test/test-ca-cross.pem",
753 "../test/test-root2.pem",
754 })
755 test.AssertNotError(t, err, "Should load valid chain")
756
757 expectedIssuer, err := core.LoadCert("../test/test-ca-cross.pem")
758 test.AssertNotError(t, err, "Failed to load test issuer")
759
760 chainIssuer := chain[0]
761 test.AssertNotNil(t, chainIssuer, "Failed to decode chain PEM")
762
763 test.AssertByteEquals(t, chainIssuer.Raw, expectedIssuer.Raw)
764 }
765
766 func TestLoadChain_TooShort(t *testing.T) {
767 _, err := LoadChain([]string{"/path/to/one/cert.pem"})
768 test.AssertError(t, err, "Should reject too-short chain")
769 }
770
771 func TestLoadChain_Unloadable(t *testing.T) {
772 _, err := LoadChain([]string{
773 "does-not-exist.pem",
774 "../test/test-root2.pem",
775 })
776 test.AssertError(t, err, "Should reject unloadable chain")
777
778 _, err = LoadChain([]string{
779 "../test/test-ca-cross.pem",
780 "does-not-exist.pem",
781 })
782 test.AssertError(t, err, "Should reject unloadable chain")
783
784 invalidPEMFile, _ := os.CreateTemp("", "invalid.pem")
785 err = os.WriteFile(invalidPEMFile.Name(), []byte(""), 0640)
786 test.AssertNotError(t, err, "Error writing invalid PEM tmp file")
787 _, err = LoadChain([]string{
788 invalidPEMFile.Name(),
789 "../test/test-root2.pem",
790 })
791 test.AssertError(t, err, "Should reject unloadable chain")
792 }
793
794 func TestLoadChain_InvalidSig(t *testing.T) {
795 _, err := LoadChain([]string{
796 "../test/test-root2.pem",
797 "../test/test-ca-cross.pem",
798 })
799 test.AssertError(t, err, "Should reject invalid signature")
800 test.Assert(t, strings.Contains(err.Error(), "test-ca-cross.pem"),
801 fmt.Sprintf("Expected error to mention filename, got: %s", err))
802 test.Assert(t, strings.Contains(err.Error(), "signature from \"CN=happy hacker fake CA\""),
803 fmt.Sprintf("Expected error to mention subject, got: %s", err))
804 }
805
806 func TestIssuanceToken(t *testing.T) {
807 fc := clock.NewFake()
808 linter, err := linter.New(issuerCert.Certificate, issuerSigner, []string{})
809 test.AssertNotError(t, err, "failed to create linter")
810 signer, err := NewIssuer(issuerCert, issuerSigner, defaultProfile(), linter, fc)
811 test.AssertNotError(t, err, "NewIssuer failed")
812
813 _, err = signer.Issue(&issuanceToken{})
814 test.AssertError(t, err, "expected issuance with a zero token to fail")
815
816 _, err = signer.Issue(nil)
817 test.AssertError(t, err, "expected issuance with a nil token to fail")
818
819 pk, err := rsa.GenerateKey(rand.Reader, 2048)
820 test.AssertNotError(t, err, "failed to generate test key")
821 _, issuanceToken, err := signer.Prepare(&IssuanceRequest{
822 PublicKey: pk.Public(),
823 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
824 DNSNames: []string{"example.com"},
825 NotBefore: fc.Now(),
826 NotAfter: fc.Now().Add(time.Hour - time.Second),
827 IncludeCTPoison: true,
828 })
829 test.AssertNotError(t, err, "expected Prepare to succeed")
830 _, err = signer.Issue(issuanceToken)
831 test.AssertNotError(t, err, "expected first issuance to succeed")
832
833 _, err = signer.Issue(issuanceToken)
834 test.AssertError(t, err, "expected second issuance with the same issuance token to fail")
835 test.AssertContains(t, err.Error(), "issuance token already redeemed")
836
837 _, issuanceToken, err = signer.Prepare(&IssuanceRequest{
838 PublicKey: pk.Public(),
839 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
840 DNSNames: []string{"example.com"},
841 NotBefore: fc.Now(),
842 NotAfter: fc.Now().Add(time.Hour - time.Second),
843 IncludeCTPoison: true,
844 })
845 test.AssertNotError(t, err, "expected Prepare to succeed")
846
847 signer2, err := NewIssuer(issuerCert, issuerSigner, defaultProfile(), linter, fc)
848 test.AssertNotError(t, err, "NewIssuer failed")
849
850 _, err = signer2.Issue(issuanceToken)
851 test.AssertError(t, err, "expected redeeming an issuance token with the wrong issuer to fail")
852 test.AssertContains(t, err.Error(), "wrong issuer")
853 }
854
855 func TestInvalidProfile(t *testing.T) {
856 fc := clock.NewFake()
857 fc.Set(time.Now())
858 err := loglist.InitLintList("../test/ct-test-srv/log_list.json")
859 test.AssertNotError(t, err, "failed to load log list")
860 linter, err := linter.New(
861 issuerCert.Certificate,
862 issuerSigner,
863 []string{},
864 )
865 test.AssertNotError(t, err, "failed to create linter")
866 signer, err := NewIssuer(issuerCert, issuerSigner, defaultProfile(), linter, fc)
867 test.AssertNotError(t, err, "NewIssuer failed")
868 pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
869 test.AssertNotError(t, err, "failed to generate test key")
870 _, _, err = signer.Prepare(&IssuanceRequest{
871 PublicKey: pk.Public(),
872 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
873 DNSNames: []string{"example.com"},
874 NotBefore: fc.Now(),
875 NotAfter: fc.Now().Add(time.Hour - time.Second),
876 IncludeCTPoison: true,
877 precertDER: []byte{6, 6, 6},
878 })
879 test.AssertError(t, err, "Invalid IssuanceRequest")
880
881 _, _, err = signer.Prepare(&IssuanceRequest{
882 PublicKey: pk.Public(),
883 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
884 DNSNames: []string{"example.com"},
885 NotBefore: fc.Now(),
886 NotAfter: fc.Now().Add(time.Hour - time.Second),
887 sctList: []ct.SignedCertificateTimestamp{
888 {
889 SCTVersion: ct.V1,
890 LogID: ct.LogID{KeyID: *(*[32]byte)(mustDecodeB64("OJiMlNA1mMOTLd/pI7q68npCDrlsQeFaqAwasPwEvQM="))},
891 },
892 },
893 precertDER: []byte{},
894 })
895 test.AssertError(t, err, "Invalid IssuanceRequest")
896 }
897
898
899
900
901 func TestMismatchedProfiles(t *testing.T) {
902 fc := clock.NewFake()
903 fc.Set(time.Now())
904 err := loglist.InitLintList("../test/ct-test-srv/log_list.json")
905 test.AssertNotError(t, err, "failed to load log list")
906 linter, err := linter.New(
907 issuerCert.Certificate,
908 issuerSigner,
909 []string{"n_subject_common_name_included"},
910 )
911 test.AssertNotError(t, err, "failed to create linter")
912
913 issuer1, err := NewIssuer(issuerCert, issuerSigner, defaultProfile(), linter, fc)
914 test.AssertNotError(t, err, "NewIssuer failed")
915 pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
916 test.AssertNotError(t, err, "failed to generate test key")
917 _, issuanceToken, err := issuer1.Prepare(&IssuanceRequest{
918 PublicKey: pk.Public(),
919 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
920 CommonName: "example.com",
921 DNSNames: []string{"example.com"},
922 NotBefore: fc.Now(),
923 NotAfter: fc.Now().Add(time.Hour - time.Second),
924 IncludeCTPoison: true,
925 })
926 test.AssertNotError(t, err, "making IssuanceRequest")
927
928 precertDER, err := issuer1.Issue(issuanceToken)
929 test.AssertNotError(t, err, "signing precert")
930
931
932 profileConfig := defaultProfileConfig()
933 profileConfig.AllowCommonName = false
934 p, err := NewProfile(profileConfig, defaultIssuerConfig())
935 test.AssertNotError(t, err, "NewProfile failed")
936 issuer2, err := NewIssuer(issuerCert, issuerSigner, p, linter, fc)
937 test.AssertNotError(t, err, "NewIssuer failed")
938
939 sctList := []ct.SignedCertificateTimestamp{
940 {
941 SCTVersion: ct.V1,
942 LogID: ct.LogID{KeyID: *(*[32]byte)(mustDecodeB64("OJiMlNA1mMOTLd/pI7q68npCDrlsQeFaqAwasPwEvQM="))},
943 },
944 {
945 SCTVersion: ct.V1,
946 LogID: ct.LogID{KeyID: *(*[32]byte)(mustDecodeB64("UtToynGEyMkkXDMQei8Ll54oMwWHI0IieDEKs12/Td4="))},
947 },
948 }
949
950 precert, err := x509.ParseCertificate(precertDER)
951 test.AssertNotError(t, err, "parsing precert")
952
953 request2, err := RequestFromPrecert(precert, sctList)
954 test.AssertNotError(t, err, "RequestFromPrecert")
955 request2.CommonName = ""
956
957 _, _, err = issuer2.Prepare(request2)
958 test.AssertError(t, err, "preparing final cert issuance")
959 test.AssertContains(t, err.Error(), "precert does not correspond to linted final cert")
960 }
961
View as plain text