github.com/letsencrypt/boulder@v0.20251208.0/issuance/cert_test.go (about) 1 package issuance 2 3 import ( 4 "crypto" 5 "crypto/dsa" 6 "crypto/ecdsa" 7 "crypto/elliptic" 8 "crypto/rand" 9 "crypto/rsa" 10 "crypto/x509" 11 "crypto/x509/pkix" 12 "encoding/base64" 13 "net" 14 "reflect" 15 "strings" 16 "testing" 17 "time" 18 19 ct "github.com/google/certificate-transparency-go" 20 "github.com/jmhodges/clock" 21 22 "github.com/letsencrypt/boulder/config" 23 "github.com/letsencrypt/boulder/ctpolicy/loglist" 24 "github.com/letsencrypt/boulder/linter" 25 "github.com/letsencrypt/boulder/test" 26 ) 27 28 var ( 29 goodSKID = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 30 ) 31 32 func defaultProfile() *Profile { 33 p, _ := NewProfile(defaultProfileConfig()) 34 return p 35 } 36 37 func TestGenerateValidity(t *testing.T) { 38 fc := clock.NewFake() 39 fc.Set(time.Date(2015, time.June, 04, 11, 04, 38, 0, time.UTC)) 40 41 tests := []struct { 42 name string 43 backdate time.Duration 44 validity time.Duration 45 notBefore time.Time 46 notAfter time.Time 47 }{ 48 { 49 name: "normal usage", 50 backdate: time.Hour, // 90% of one hour is 54 minutes 51 validity: 7 * 24 * time.Hour, 52 notBefore: time.Date(2015, time.June, 04, 10, 10, 38, 0, time.UTC), 53 notAfter: time.Date(2015, time.June, 11, 10, 10, 37, 0, time.UTC), 54 }, 55 { 56 name: "zero backdate", 57 backdate: 0, 58 validity: 7 * 24 * time.Hour, 59 notBefore: time.Date(2015, time.June, 04, 11, 04, 38, 0, time.UTC), 60 notAfter: time.Date(2015, time.June, 11, 11, 04, 37, 0, time.UTC), 61 }, 62 } 63 64 for _, tc := range tests { 65 t.Run(tc.name, func(t *testing.T) { 66 p := Profile{maxBackdate: tc.backdate, maxValidity: tc.validity} 67 notBefore, notAfter := p.GenerateValidity(fc.Now()) 68 test.AssertEquals(t, notBefore, tc.notBefore) 69 test.AssertEquals(t, notAfter, tc.notAfter) 70 }) 71 } 72 } 73 74 func TestCRLURL(t *testing.T) { 75 issuer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, clock.NewFake()) 76 if err != nil { 77 t.Fatalf("newIssuer: %s", err) 78 } 79 url := issuer.crlURL(4928) 80 want := "http://crl-url.example.org/4928.crl" 81 if url != want { 82 t.Errorf("crlURL(4928)=%s, want %s", url, want) 83 } 84 } 85 86 func TestRequestValid(t *testing.T) { 87 fc := clock.NewFake() 88 fc.Add(time.Hour * 24) 89 90 tests := []struct { 91 name string 92 issuer *Issuer 93 profile *Profile 94 request *IssuanceRequest 95 expectedError string 96 }{ 97 { 98 name: "unsupported key type", 99 issuer: &Issuer{}, 100 profile: &Profile{}, 101 request: &IssuanceRequest{PublicKey: MarshalablePublicKey{&dsa.PublicKey{}}}, 102 expectedError: "unsupported public key type", 103 }, 104 { 105 name: "inactive (rsa)", 106 issuer: &Issuer{}, 107 profile: &Profile{}, 108 request: &IssuanceRequest{PublicKey: MarshalablePublicKey{&rsa.PublicKey{}}}, 109 expectedError: "inactive issuer cannot issue precert", 110 }, 111 { 112 name: "inactive (ecdsa)", 113 issuer: &Issuer{}, 114 profile: &Profile{}, 115 request: &IssuanceRequest{PublicKey: MarshalablePublicKey{&ecdsa.PublicKey{}}}, 116 expectedError: "inactive issuer cannot issue precert", 117 }, 118 { 119 name: "skid too short", 120 issuer: &Issuer{ 121 active: true, 122 }, 123 profile: &Profile{}, 124 request: &IssuanceRequest{ 125 PublicKey: MarshalablePublicKey{&ecdsa.PublicKey{}}, 126 SubjectKeyId: []byte{0, 1, 2, 3, 4}, 127 }, 128 expectedError: "unexpected subject key ID length", 129 }, 130 { 131 name: "both sct list and ct poison provided", 132 issuer: &Issuer{ 133 active: true, 134 }, 135 profile: &Profile{}, 136 request: &IssuanceRequest{ 137 PublicKey: MarshalablePublicKey{&ecdsa.PublicKey{}}, 138 SubjectKeyId: goodSKID, 139 IncludeCTPoison: true, 140 sctList: []ct.SignedCertificateTimestamp{}, 141 }, 142 expectedError: "cannot include both ct poison and sct list extensions", 143 }, 144 { 145 name: "negative validity", 146 issuer: &Issuer{ 147 active: true, 148 }, 149 profile: &Profile{}, 150 request: &IssuanceRequest{ 151 PublicKey: MarshalablePublicKey{&ecdsa.PublicKey{}}, 152 SubjectKeyId: goodSKID, 153 NotBefore: fc.Now().Add(time.Hour), 154 NotAfter: fc.Now(), 155 }, 156 expectedError: "NotAfter must be after NotBefore", 157 }, 158 { 159 name: "validity larger than max", 160 issuer: &Issuer{ 161 active: true, 162 }, 163 profile: &Profile{ 164 maxValidity: time.Minute, 165 }, 166 request: &IssuanceRequest{ 167 PublicKey: MarshalablePublicKey{&ecdsa.PublicKey{}}, 168 SubjectKeyId: goodSKID, 169 NotBefore: fc.Now(), 170 NotAfter: fc.Now().Add(time.Hour - time.Second), 171 }, 172 expectedError: "validity period is more than the maximum allowed period (1h0m0s>1m0s)", 173 }, 174 { 175 name: "validity larger than max due to inclusivity", 176 issuer: &Issuer{ 177 active: true, 178 }, 179 profile: &Profile{ 180 maxValidity: time.Hour, 181 }, 182 request: &IssuanceRequest{ 183 PublicKey: MarshalablePublicKey{&ecdsa.PublicKey{}}, 184 SubjectKeyId: goodSKID, 185 NotBefore: fc.Now(), 186 NotAfter: fc.Now().Add(time.Hour), 187 }, 188 expectedError: "validity period is more than the maximum allowed period (1h0m1s>1h0m0s)", 189 }, 190 { 191 name: "validity backdated more than max", 192 issuer: &Issuer{ 193 active: true, 194 }, 195 profile: &Profile{ 196 maxValidity: time.Hour * 2, 197 maxBackdate: time.Hour, 198 }, 199 request: &IssuanceRequest{ 200 PublicKey: MarshalablePublicKey{&ecdsa.PublicKey{}}, 201 SubjectKeyId: goodSKID, 202 NotBefore: fc.Now().Add(-time.Hour * 2), 203 NotAfter: fc.Now().Add(-time.Hour), 204 }, 205 expectedError: "NotBefore is backdated more than the maximum allowed period (2h0m0s>1h0m0s)", 206 }, 207 { 208 name: "validity is forward dated", 209 issuer: &Issuer{ 210 active: true, 211 }, 212 profile: &Profile{ 213 maxValidity: time.Hour * 2, 214 maxBackdate: time.Hour, 215 }, 216 request: &IssuanceRequest{ 217 PublicKey: MarshalablePublicKey{&ecdsa.PublicKey{}}, 218 SubjectKeyId: goodSKID, 219 NotBefore: fc.Now().Add(time.Hour), 220 NotAfter: fc.Now().Add(time.Hour * 2), 221 }, 222 expectedError: "NotBefore is in the future", 223 }, 224 { 225 name: "serial too short", 226 issuer: &Issuer{ 227 active: true, 228 }, 229 profile: &Profile{ 230 maxValidity: time.Hour * 2, 231 }, 232 request: &IssuanceRequest{ 233 PublicKey: MarshalablePublicKey{&ecdsa.PublicKey{}}, 234 SubjectKeyId: goodSKID, 235 NotBefore: fc.Now(), 236 NotAfter: fc.Now().Add(time.Hour), 237 Serial: []byte{0, 1, 2, 3, 4, 5, 6, 7}, 238 }, 239 expectedError: "serial must be between 9 and 19 bytes", 240 }, 241 { 242 name: "serial too long", 243 issuer: &Issuer{ 244 active: true, 245 }, 246 profile: &Profile{ 247 maxValidity: time.Hour * 2, 248 }, 249 request: &IssuanceRequest{ 250 PublicKey: MarshalablePublicKey{&ecdsa.PublicKey{}}, 251 SubjectKeyId: goodSKID, 252 NotBefore: fc.Now(), 253 NotAfter: fc.Now().Add(time.Hour), 254 Serial: []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 255 }, 256 expectedError: "serial must be between 9 and 19 bytes", 257 }, 258 { 259 name: "good with poison", 260 issuer: &Issuer{ 261 active: true, 262 }, 263 profile: &Profile{ 264 maxValidity: time.Hour * 2, 265 }, 266 request: &IssuanceRequest{ 267 PublicKey: MarshalablePublicKey{&ecdsa.PublicKey{}}, 268 SubjectKeyId: goodSKID, 269 NotBefore: fc.Now(), 270 NotAfter: fc.Now().Add(time.Hour), 271 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}, 272 IncludeCTPoison: true, 273 }, 274 }, 275 { 276 name: "good with scts", 277 issuer: &Issuer{ 278 active: true, 279 }, 280 profile: &Profile{ 281 maxValidity: time.Hour * 2, 282 }, 283 request: &IssuanceRequest{ 284 PublicKey: MarshalablePublicKey{&ecdsa.PublicKey{}}, 285 SubjectKeyId: goodSKID, 286 NotBefore: fc.Now(), 287 NotAfter: fc.Now().Add(time.Hour), 288 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}, 289 sctList: []ct.SignedCertificateTimestamp{}, 290 }, 291 }, 292 } 293 for _, tc := range tests { 294 t.Run(tc.name, func(t *testing.T) { 295 err := tc.issuer.requestValid(fc, tc.profile, tc.request) 296 if err != nil { 297 if tc.expectedError == "" { 298 t.Errorf("failed with unexpected error: %s", err) 299 } else if tc.expectedError != err.Error() { 300 t.Errorf("failed with unexpected error, wanted: %q, got: %q", tc.expectedError, err.Error()) 301 } 302 return 303 } else if tc.expectedError != "" { 304 t.Errorf("didn't fail, expected %q", tc.expectedError) 305 } 306 }) 307 } 308 } 309 310 func TestGenerateTemplate(t *testing.T) { 311 issuer := &Issuer{ 312 issuerURL: "http://issuer", 313 crlURLBase: "http://crl/", 314 sigAlg: x509.SHA256WithRSA, 315 } 316 317 actual := issuer.generateTemplate() 318 319 expected := &x509.Certificate{ 320 BasicConstraintsValid: true, 321 SignatureAlgorithm: x509.SHA256WithRSA, 322 IssuingCertificateURL: []string{"http://issuer"}, 323 Policies: []x509.OID{domainValidatedOID}, 324 // This field is computed based on the serial, so is not included in the template. 325 CRLDistributionPoints: nil, 326 } 327 328 test.AssertDeepEquals(t, actual, expected) 329 } 330 331 func TestIssue(t *testing.T) { 332 for _, tc := range []struct { 333 name string 334 generateFunc func() (crypto.Signer, error) 335 ku x509.KeyUsage 336 }{ 337 { 338 name: "RSA", 339 generateFunc: func() (crypto.Signer, error) { 340 return rsa.GenerateKey(rand.Reader, 2048) 341 }, 342 ku: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment, 343 }, 344 { 345 name: "ECDSA", 346 generateFunc: func() (crypto.Signer, error) { 347 return ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 348 }, 349 ku: x509.KeyUsageDigitalSignature, 350 }, 351 } { 352 t.Run(tc.name, func(t *testing.T) { 353 fc := clock.NewFake() 354 fc.Set(time.Now()) 355 signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc) 356 test.AssertNotError(t, err, "NewIssuer failed") 357 pk, err := tc.generateFunc() 358 test.AssertNotError(t, err, "failed to generate test key") 359 lintCertBytes, issuanceToken, err := signer.Prepare(defaultProfile(), &IssuanceRequest{ 360 PublicKey: MarshalablePublicKey{pk.Public()}, 361 SubjectKeyId: goodSKID, 362 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}, 363 DNSNames: []string{"example.com"}, 364 IPAddresses: []net.IP{net.ParseIP("128.101.101.101"), net.ParseIP("3fff:aaa:a:c0ff:ee:a:bad:deed")}, 365 NotBefore: fc.Now(), 366 NotAfter: fc.Now().Add(time.Hour - time.Second), 367 IncludeCTPoison: true, 368 }) 369 test.AssertNotError(t, err, "Prepare failed") 370 _, err = x509.ParseCertificate(lintCertBytes) 371 test.AssertNotError(t, err, "failed to parse certificate") 372 certBytes, err := signer.Issue(issuanceToken) 373 test.AssertNotError(t, err, "Issue failed") 374 cert, err := x509.ParseCertificate(certBytes) 375 test.AssertNotError(t, err, "failed to parse certificate") 376 err = cert.CheckSignatureFrom(issuerCert.Certificate) 377 test.AssertNotError(t, err, "signature validation failed") 378 test.AssertDeepEquals(t, cert.DNSNames, []string{"example.com"}) 379 // net.ParseIP always returns a 16-byte address; IPv4 addresses are 380 // returned in IPv4-mapped IPv6 form. But RFC 5280, Sec. 4.2.1.6 381 // requires that IPv4 addresses be encoded as 4 bytes. 382 // 383 // The issuance pipeline calls x509.marshalSANs, which reduces IPv4 384 // addresses back to 4 bytes. Adding .To4() both allows this test to 385 // succeed, and covers this requirement. 386 test.AssertDeepEquals(t, cert.IPAddresses, []net.IP{net.ParseIP("128.101.101.101").To4(), net.ParseIP("3fff:aaa:a:c0ff:ee:a:bad:deed")}) 387 test.AssertByteEquals(t, cert.SerialNumber.Bytes(), []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}) 388 test.AssertDeepEquals(t, cert.PublicKey, pk.Public()) 389 test.AssertEquals(t, len(cert.Extensions), 10) // Constraints, KU, EKU, SKID, AKID, AIA, CRLDP, SAN, Policies, Poison 390 test.AssertEquals(t, cert.KeyUsage, tc.ku) 391 if len(cert.CRLDistributionPoints) != 1 || !strings.HasPrefix(cert.CRLDistributionPoints[0], "http://crl-url.example.org/") { 392 t.Errorf("want CRLDistributionPoints=[http://crl-url.example.org/x.crl], got %v", cert.CRLDistributionPoints) 393 } 394 }) 395 } 396 } 397 398 func TestIssueDNSNamesOnly(t *testing.T) { 399 fc := clock.NewFake() 400 signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc) 401 if err != nil { 402 t.Fatalf("newIssuer: %s", err) 403 } 404 pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 405 if err != nil { 406 t.Fatalf("ecdsa.GenerateKey: %s", err) 407 } 408 _, issuanceToken, err := signer.Prepare(defaultProfile(), &IssuanceRequest{ 409 PublicKey: MarshalablePublicKey{pk.Public()}, 410 SubjectKeyId: goodSKID, 411 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}, 412 DNSNames: []string{"example.com"}, 413 NotBefore: fc.Now(), 414 NotAfter: fc.Now().Add(time.Hour - time.Second), 415 IncludeCTPoison: true, 416 }) 417 if err != nil { 418 t.Fatalf("signer.Prepare: %s", err) 419 } 420 certBytes, err := signer.Issue(issuanceToken) 421 if err != nil { 422 t.Fatalf("signer.Issue: %s", err) 423 } 424 cert, err := x509.ParseCertificate(certBytes) 425 if err != nil { 426 t.Fatalf("x509.ParseCertificate: %s", err) 427 } 428 if !reflect.DeepEqual(cert.DNSNames, []string{"example.com"}) { 429 t.Errorf("got DNSNames %s, wanted example.com", cert.DNSNames) 430 } 431 // BRs 7.1.2.7.12 requires iPAddress, if present, to contain an entry. 432 if cert.IPAddresses != nil { 433 t.Errorf("got IPAddresses %s, wanted nil", cert.IPAddresses) 434 } 435 } 436 437 func TestIssueIPAddressesOnly(t *testing.T) { 438 fc := clock.NewFake() 439 signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc) 440 if err != nil { 441 t.Fatalf("newIssuer: %s", err) 442 } 443 pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 444 if err != nil { 445 t.Fatalf("ecdsa.GenerateKey: %s", err) 446 } 447 _, issuanceToken, err := signer.Prepare(defaultProfile(), &IssuanceRequest{ 448 PublicKey: MarshalablePublicKey{pk.Public()}, 449 SubjectKeyId: goodSKID, 450 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}, 451 IPAddresses: []net.IP{net.ParseIP("128.101.101.101"), net.ParseIP("3fff:aaa:a:c0ff:ee:a:bad:deed")}, 452 NotBefore: fc.Now(), 453 NotAfter: fc.Now().Add(time.Hour - time.Second), 454 IncludeCTPoison: true, 455 }) 456 if err != nil { 457 t.Fatalf("signer.Prepare: %s", err) 458 } 459 certBytes, err := signer.Issue(issuanceToken) 460 if err != nil { 461 t.Fatalf("signer.Issue: %s", err) 462 } 463 cert, err := x509.ParseCertificate(certBytes) 464 if err != nil { 465 t.Fatalf("x509.ParseCertificate: %s", err) 466 } 467 // BRs 7.1.2.7.12 requires dNSName, if present, to contain an entry. 468 if cert.DNSNames != nil { 469 t.Errorf("got DNSNames %s, wanted nil", cert.DNSNames) 470 } 471 if !reflect.DeepEqual(cert.IPAddresses, []net.IP{net.ParseIP("128.101.101.101").To4(), net.ParseIP("3fff:aaa:a:c0ff:ee:a:bad:deed")}) { 472 t.Errorf("got IPAddresses %s, wanted 128.101.101.101 (4-byte) & 3fff:aaa:a:c0ff:ee:a:bad:deed (16-byte)", cert.IPAddresses) 473 } 474 } 475 476 func TestIssueWithCRLDP(t *testing.T) { 477 fc := clock.NewFake() 478 issuerConfig := defaultIssuerConfig() 479 issuerConfig.CRLURLBase = "http://crls.example.net/" 480 issuerConfig.CRLShards = 999 481 signer, err := newIssuer(issuerConfig, issuerCert, issuerSigner, fc) 482 if err != nil { 483 t.Fatalf("newIssuer: %s", err) 484 } 485 pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 486 if err != nil { 487 t.Fatalf("ecdsa.GenerateKey: %s", err) 488 } 489 profile := defaultProfile() 490 _, issuanceToken, err := signer.Prepare(profile, &IssuanceRequest{ 491 PublicKey: MarshalablePublicKey{pk.Public()}, 492 SubjectKeyId: goodSKID, 493 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}, 494 DNSNames: []string{"example.com"}, 495 NotBefore: fc.Now(), 496 NotAfter: fc.Now().Add(time.Hour - time.Second), 497 IncludeCTPoison: true, 498 }) 499 if err != nil { 500 t.Fatalf("signer.Prepare: %s", err) 501 } 502 certBytes, err := signer.Issue(issuanceToken) 503 if err != nil { 504 t.Fatalf("signer.Issue: %s", err) 505 } 506 cert, err := x509.ParseCertificate(certBytes) 507 if err != nil { 508 t.Fatalf("x509.ParseCertificate: %s", err) 509 } 510 // Because CRL shard is calculated deterministically from serial, we know which shard will be chosen. 511 expectedCRLDP := []string{"http://crls.example.net/919.crl"} 512 if !reflect.DeepEqual(cert.CRLDistributionPoints, expectedCRLDP) { 513 t.Errorf("CRLDP=%+v, want %+v", cert.CRLDistributionPoints, expectedCRLDP) 514 } 515 } 516 517 func TestIssueCommonName(t *testing.T) { 518 fc := clock.NewFake() 519 fc.Set(time.Now()) 520 521 prof := defaultProfileConfig() 522 prof.IgnoredLints = append(prof.IgnoredLints, "w_subject_common_name_included") 523 cnProfile, err := NewProfile(prof) 524 test.AssertNotError(t, err, "NewProfile failed") 525 signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc) 526 test.AssertNotError(t, err, "NewIssuer failed") 527 pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 528 test.AssertNotError(t, err, "failed to generate test key") 529 ir := &IssuanceRequest{ 530 PublicKey: MarshalablePublicKey{pk.Public()}, 531 SubjectKeyId: goodSKID, 532 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}, 533 DNSNames: []string{"example.com", "www.example.com"}, 534 NotBefore: fc.Now(), 535 NotAfter: fc.Now().Add(time.Hour - time.Second), 536 IncludeCTPoison: true, 537 } 538 539 // In the default profile, the common name is allowed if requested. 540 ir.CommonName = "example.com" 541 _, issuanceToken, err := signer.Prepare(cnProfile, ir) 542 test.AssertNotError(t, err, "Prepare failed") 543 certBytes, err := signer.Issue(issuanceToken) 544 test.AssertNotError(t, err, "Issue failed") 545 cert, err := x509.ParseCertificate(certBytes) 546 test.AssertNotError(t, err, "failed to parse certificate") 547 test.AssertEquals(t, cert.Subject.CommonName, "example.com") 548 549 // But not including the common name should be acceptable as well. 550 ir.CommonName = "" 551 _, issuanceToken, err = signer.Prepare(cnProfile, ir) 552 test.AssertNotError(t, err, "Prepare failed") 553 certBytes, err = signer.Issue(issuanceToken) 554 test.AssertNotError(t, err, "Issue failed") 555 cert, err = x509.ParseCertificate(certBytes) 556 test.AssertNotError(t, err, "failed to parse certificate") 557 test.AssertEquals(t, cert.Subject.CommonName, "") 558 559 // And the common name should be omitted if the profile is so configured. 560 ir.CommonName = "example.com" 561 cnProfile.omitCommonName = true 562 _, issuanceToken, err = signer.Prepare(cnProfile, ir) 563 test.AssertNotError(t, err, "Prepare failed") 564 certBytes, err = signer.Issue(issuanceToken) 565 test.AssertNotError(t, err, "Issue failed") 566 cert, err = x509.ParseCertificate(certBytes) 567 test.AssertNotError(t, err, "failed to parse certificate") 568 test.AssertEquals(t, cert.Subject.CommonName, "") 569 } 570 571 func TestIssueOmissions(t *testing.T) { 572 fc := clock.NewFake() 573 fc.Set(time.Now()) 574 575 pc := defaultProfileConfig() 576 pc.OmitCommonName = true 577 pc.OmitKeyEncipherment = true 578 pc.OmitClientAuth = true 579 pc.OmitSKID = true 580 pc.IgnoredLints = []string{ 581 // Reduce the lint ignores to just the minimal (SCT-related) set. 582 "w_ct_sct_policy_count_unsatisfied", 583 "e_scts_from_same_operator", 584 // Ignore the warning about *not* including the SubjectKeyIdentifier extension: 585 // zlint has both lints (one enforcing RFC5280, the other the BRs). 586 "w_ext_subject_key_identifier_missing_sub_cert", 587 } 588 prof, err := NewProfile(pc) 589 test.AssertNotError(t, err, "building test profile") 590 591 signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc) 592 test.AssertNotError(t, err, "NewIssuer failed") 593 594 pk, err := rsa.GenerateKey(rand.Reader, 2048) 595 test.AssertNotError(t, err, "failed to generate test key") 596 _, issuanceToken, err := signer.Prepare(prof, &IssuanceRequest{ 597 PublicKey: MarshalablePublicKey{pk.Public()}, 598 SubjectKeyId: goodSKID, 599 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}, 600 DNSNames: []string{"example.com"}, 601 CommonName: "example.com", 602 IncludeCTPoison: true, 603 NotBefore: fc.Now(), 604 NotAfter: fc.Now().Add(time.Hour - time.Second), 605 }) 606 test.AssertNotError(t, err, "Prepare failed") 607 certBytes, err := signer.Issue(issuanceToken) 608 test.AssertNotError(t, err, "Issue failed") 609 cert, err := x509.ParseCertificate(certBytes) 610 test.AssertNotError(t, err, "failed to parse certificate") 611 612 test.AssertEquals(t, cert.Subject.CommonName, "") 613 test.AssertEquals(t, cert.KeyUsage, x509.KeyUsageDigitalSignature) 614 test.AssertDeepEquals(t, cert.ExtKeyUsage, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}) 615 test.AssertEquals(t, len(cert.SubjectKeyId), 0) 616 } 617 618 func TestIssueCTPoison(t *testing.T) { 619 fc := clock.NewFake() 620 fc.Set(time.Now()) 621 signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc) 622 test.AssertNotError(t, err, "NewIssuer failed") 623 pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 624 test.AssertNotError(t, err, "failed to generate test key") 625 _, issuanceToken, err := signer.Prepare(defaultProfile(), &IssuanceRequest{ 626 PublicKey: MarshalablePublicKey{pk.Public()}, 627 SubjectKeyId: goodSKID, 628 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}, 629 DNSNames: []string{"example.com"}, 630 IncludeCTPoison: true, 631 NotBefore: fc.Now(), 632 NotAfter: fc.Now().Add(time.Hour - time.Second), 633 }) 634 test.AssertNotError(t, err, "Prepare failed") 635 certBytes, err := signer.Issue(issuanceToken) 636 test.AssertNotError(t, err, "Issue failed") 637 cert, err := x509.ParseCertificate(certBytes) 638 test.AssertNotError(t, err, "failed to parse certificate") 639 err = cert.CheckSignatureFrom(issuerCert.Certificate) 640 test.AssertNotError(t, err, "signature validation failed") 641 test.AssertByteEquals(t, cert.SerialNumber.Bytes(), []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}) 642 test.AssertDeepEquals(t, cert.PublicKey, pk.Public()) 643 test.AssertEquals(t, len(cert.Extensions), 10) // Constraints, KU, EKU, SKID, AKID, AIA, CRLDP, SAN, Policies, Poison 644 test.AssertDeepEquals(t, cert.Extensions[9], ctPoisonExt) 645 } 646 647 func mustDecodeB64(b string) []byte { 648 out, err := base64.StdEncoding.DecodeString(b) 649 if err != nil { 650 panic(err) 651 } 652 return out 653 } 654 655 func TestIssueSCTList(t *testing.T) { 656 fc := clock.NewFake() 657 fc.Set(time.Now()) 658 659 err := loglist.InitLintList("../test/ct-test-srv/log_list.json") 660 test.AssertNotError(t, err, "failed to load log list") 661 662 pc := defaultProfileConfig() 663 pc.IgnoredLints = []string{ 664 // Only ignore the SKID lint, i.e., don't ignore the "missing SCT" lints. 665 "w_ext_subject_key_identifier_not_recommended_subscriber", 666 } 667 enforceSCTsProfile, err := NewProfile(pc) 668 test.AssertNotError(t, err, "NewProfile failed") 669 signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc) 670 test.AssertNotError(t, err, "NewIssuer failed") 671 pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 672 test.AssertNotError(t, err, "failed to generate test key") 673 _, issuanceToken, err := signer.Prepare(enforceSCTsProfile, &IssuanceRequest{ 674 PublicKey: MarshalablePublicKey{pk.Public()}, 675 SubjectKeyId: goodSKID, 676 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}, 677 DNSNames: []string{"example.com"}, 678 NotBefore: fc.Now(), 679 NotAfter: fc.Now().Add(time.Hour - time.Second), 680 IncludeCTPoison: true, 681 }) 682 test.AssertNotError(t, err, "Prepare failed") 683 precertBytes, err := signer.Issue(issuanceToken) 684 test.AssertNotError(t, err, "Issue failed") 685 precert, err := x509.ParseCertificate(precertBytes) 686 test.AssertNotError(t, err, "failed to parse certificate") 687 688 sctList := []ct.SignedCertificateTimestamp{ 689 { 690 SCTVersion: ct.V1, 691 LogID: ct.LogID{KeyID: *(*[32]byte)(mustDecodeB64("OJiMlNA1mMOTLd/pI7q68npCDrlsQeFaqAwasPwEvQM="))}, 692 }, 693 { 694 SCTVersion: ct.V1, 695 LogID: ct.LogID{KeyID: *(*[32]byte)(mustDecodeB64("UtToynGEyMkkXDMQei8Ll54oMwWHI0IieDEKs12/Td4="))}, 696 }, 697 } 698 699 request2, err := RequestFromPrecert(precert, sctList) 700 test.AssertNotError(t, err, "generating request from precert") 701 702 _, issuanceToken2, err := signer.Prepare(enforceSCTsProfile, request2) 703 test.AssertNotError(t, err, "preparing final cert issuance") 704 705 finalCertBytes, err := signer.Issue(issuanceToken2) 706 test.AssertNotError(t, err, "Issue failed") 707 708 finalCert, err := x509.ParseCertificate(finalCertBytes) 709 test.AssertNotError(t, err, "failed to parse certificate") 710 711 err = finalCert.CheckSignatureFrom(issuerCert.Certificate) 712 test.AssertNotError(t, err, "signature validation failed") 713 test.AssertByteEquals(t, finalCert.SerialNumber.Bytes(), []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}) 714 test.AssertDeepEquals(t, finalCert.PublicKey, pk.Public()) 715 test.AssertEquals(t, len(finalCert.Extensions), 10) // Constraints, KU, EKU, SKID, AKID, AIA, CRLDP, SAN, Policies, Poison 716 test.AssertDeepEquals(t, finalCert.Extensions[9], pkix.Extension{ 717 Id: sctListOID, 718 Value: []byte{ 719 4, 100, 0, 98, 0, 47, 0, 56, 152, 140, 148, 208, 53, 152, 195, 147, 45, 720 223, 233, 35, 186, 186, 242, 122, 66, 14, 185, 108, 65, 225, 90, 168, 12, 721 26, 176, 252, 4, 189, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 722 0, 82, 212, 232, 202, 113, 132, 200, 201, 36, 92, 51, 16, 122, 47, 11, 723 151, 158, 40, 51, 5, 135, 35, 66, 34, 120, 49, 10, 179, 93, 191, 77, 222, 724 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 725 }, 726 }) 727 } 728 729 func TestIssueBadLint(t *testing.T) { 730 fc := clock.NewFake() 731 fc.Set(time.Now()) 732 733 pc := defaultProfileConfig() 734 pc.IgnoredLints = []string{} 735 noSkipLintsProfile, err := NewProfile(pc) 736 test.AssertNotError(t, err, "NewProfile failed") 737 signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc) 738 test.AssertNotError(t, err, "NewIssuer failed") 739 pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 740 test.AssertNotError(t, err, "failed to generate test key") 741 _, _, err = signer.Prepare(noSkipLintsProfile, &IssuanceRequest{ 742 PublicKey: MarshalablePublicKey{pk.Public()}, 743 SubjectKeyId: goodSKID, 744 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}, 745 DNSNames: []string{"example-com"}, 746 NotBefore: fc.Now(), 747 NotAfter: fc.Now().Add(time.Hour - time.Second), 748 IncludeCTPoison: true, 749 }) 750 test.AssertError(t, err, "Prepare didn't fail") 751 test.AssertErrorIs(t, err, linter.ErrLinting) 752 test.AssertContains(t, err.Error(), "tbsCertificate linting failed: failed lint(s)") 753 } 754 755 func TestIssuanceToken(t *testing.T) { 756 fc := clock.NewFake() 757 fc.Set(time.Now()) 758 759 signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc) 760 test.AssertNotError(t, err, "NewIssuer failed") 761 762 _, err = signer.Issue(&issuanceToken{}) 763 test.AssertError(t, err, "expected issuance with a zero token to fail") 764 765 _, err = signer.Issue(nil) 766 test.AssertError(t, err, "expected issuance with a nil token to fail") 767 768 pk, err := rsa.GenerateKey(rand.Reader, 2048) 769 test.AssertNotError(t, err, "failed to generate test key") 770 _, issuanceToken, err := signer.Prepare(defaultProfile(), &IssuanceRequest{ 771 PublicKey: MarshalablePublicKey{pk.Public()}, 772 SubjectKeyId: goodSKID, 773 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}, 774 DNSNames: []string{"example.com"}, 775 NotBefore: fc.Now(), 776 NotAfter: fc.Now().Add(time.Hour - time.Second), 777 IncludeCTPoison: true, 778 }) 779 test.AssertNotError(t, err, "expected Prepare to succeed") 780 _, err = signer.Issue(issuanceToken) 781 test.AssertNotError(t, err, "expected first issuance to succeed") 782 783 _, err = signer.Issue(issuanceToken) 784 test.AssertError(t, err, "expected second issuance with the same issuance token to fail") 785 test.AssertContains(t, err.Error(), "issuance token already redeemed") 786 787 _, issuanceToken, err = signer.Prepare(defaultProfile(), &IssuanceRequest{ 788 PublicKey: MarshalablePublicKey{pk.Public()}, 789 SubjectKeyId: goodSKID, 790 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}, 791 DNSNames: []string{"example.com"}, 792 NotBefore: fc.Now(), 793 NotAfter: fc.Now().Add(time.Hour - time.Second), 794 IncludeCTPoison: true, 795 }) 796 test.AssertNotError(t, err, "expected Prepare to succeed") 797 798 signer2, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc) 799 test.AssertNotError(t, err, "NewIssuer failed") 800 801 _, err = signer2.Issue(issuanceToken) 802 test.AssertError(t, err, "expected redeeming an issuance token with the wrong issuer to fail") 803 test.AssertContains(t, err.Error(), "wrong issuer") 804 } 805 806 func TestInvalidProfile(t *testing.T) { 807 fc := clock.NewFake() 808 fc.Set(time.Now()) 809 810 err := loglist.InitLintList("../test/ct-test-srv/log_list.json") 811 test.AssertNotError(t, err, "failed to load log list") 812 813 signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc) 814 test.AssertNotError(t, err, "NewIssuer failed") 815 pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 816 test.AssertNotError(t, err, "failed to generate test key") 817 _, _, err = signer.Prepare(defaultProfile(), &IssuanceRequest{ 818 PublicKey: MarshalablePublicKey{pk.Public()}, 819 SubjectKeyId: goodSKID, 820 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}, 821 DNSNames: []string{"example.com"}, 822 NotBefore: fc.Now(), 823 NotAfter: fc.Now().Add(time.Hour - time.Second), 824 IncludeCTPoison: true, 825 precertDER: []byte{6, 6, 6}, 826 }) 827 test.AssertError(t, err, "Invalid IssuanceRequest") 828 829 _, _, err = signer.Prepare(defaultProfile(), &IssuanceRequest{ 830 PublicKey: MarshalablePublicKey{pk.Public()}, 831 SubjectKeyId: goodSKID, 832 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}, 833 DNSNames: []string{"example.com"}, 834 NotBefore: fc.Now(), 835 NotAfter: fc.Now().Add(time.Hour - time.Second), 836 sctList: []ct.SignedCertificateTimestamp{ 837 { 838 SCTVersion: ct.V1, 839 LogID: ct.LogID{KeyID: *(*[32]byte)(mustDecodeB64("OJiMlNA1mMOTLd/pI7q68npCDrlsQeFaqAwasPwEvQM="))}, 840 }, 841 }, 842 precertDER: []byte{}, 843 }) 844 test.AssertError(t, err, "Invalid IssuanceRequest") 845 } 846 847 // Generate a precert from one profile and a final cert from another, and verify 848 // that the final cert errors out when linted because the lint cert doesn't 849 // corresponding with the precert. 850 func TestMismatchedProfiles(t *testing.T) { 851 fc := clock.NewFake() 852 fc.Set(time.Now()) 853 err := loglist.InitLintList("../test/ct-test-srv/log_list.json") 854 test.AssertNotError(t, err, "failed to load log list") 855 856 issuer1, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc) 857 test.AssertNotError(t, err, "NewIssuer failed") 858 859 pc := defaultProfileConfig() 860 pc.IgnoredLints = append(pc.IgnoredLints, "w_subject_common_name_included") 861 cnProfile, err := NewProfile(pc) 862 test.AssertNotError(t, err, "NewProfile failed") 863 864 pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 865 test.AssertNotError(t, err, "failed to generate test key") 866 _, issuanceToken, err := issuer1.Prepare(cnProfile, &IssuanceRequest{ 867 PublicKey: MarshalablePublicKey{pk.Public()}, 868 SubjectKeyId: goodSKID, 869 Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}, 870 CommonName: "example.com", 871 DNSNames: []string{"example.com"}, 872 NotBefore: fc.Now(), 873 NotAfter: fc.Now().Add(time.Hour - time.Second), 874 IncludeCTPoison: true, 875 }) 876 test.AssertNotError(t, err, "making IssuanceRequest") 877 878 precertDER, err := issuer1.Issue(issuanceToken) 879 test.AssertNotError(t, err, "signing precert") 880 881 // Create a new profile that differs slightly (no common name) 882 pc = defaultProfileConfig() 883 pc.OmitCommonName = false 884 test.AssertNotError(t, err, "building test lint registry") 885 noCNProfile, err := NewProfile(pc) 886 test.AssertNotError(t, err, "NewProfile failed") 887 888 issuer2, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc) 889 test.AssertNotError(t, err, "NewIssuer failed") 890 891 sctList := []ct.SignedCertificateTimestamp{ 892 { 893 SCTVersion: ct.V1, 894 LogID: ct.LogID{KeyID: *(*[32]byte)(mustDecodeB64("OJiMlNA1mMOTLd/pI7q68npCDrlsQeFaqAwasPwEvQM="))}, 895 }, 896 { 897 SCTVersion: ct.V1, 898 LogID: ct.LogID{KeyID: *(*[32]byte)(mustDecodeB64("UtToynGEyMkkXDMQei8Ll54oMwWHI0IieDEKs12/Td4="))}, 899 }, 900 } 901 902 precert, err := x509.ParseCertificate(precertDER) 903 test.AssertNotError(t, err, "parsing precert") 904 905 request2, err := RequestFromPrecert(precert, sctList) 906 test.AssertNotError(t, err, "RequestFromPrecert") 907 request2.CommonName = "" 908 909 _, _, err = issuer2.Prepare(noCNProfile, request2) 910 test.AssertError(t, err, "preparing final cert issuance") 911 test.AssertContains(t, err.Error(), "precert does not correspond to linted final cert") 912 } 913 914 func TestNewProfile(t *testing.T) { 915 for _, tc := range []struct { 916 name string 917 config ProfileConfig 918 wantErr string 919 }{ 920 { 921 name: "happy path", 922 config: ProfileConfig{ 923 MaxValidityBackdate: config.Duration{Duration: 1 * time.Hour}, 924 MaxValidityPeriod: config.Duration{Duration: 90 * 24 * time.Hour}, 925 }, 926 }, 927 { 928 name: "large backdate", 929 config: ProfileConfig{ 930 MaxValidityBackdate: config.Duration{Duration: 24 * time.Hour}, 931 MaxValidityPeriod: config.Duration{Duration: 90 * 24 * time.Hour}, 932 }, 933 wantErr: "backdate \"24h0m0s\" is too large", 934 }, 935 { 936 name: "large validity", 937 config: ProfileConfig{ 938 MaxValidityBackdate: config.Duration{Duration: 1 * time.Hour}, 939 MaxValidityPeriod: config.Duration{Duration: 397 * 24 * time.Hour}, 940 }, 941 wantErr: "validity period \"9528h0m0s\" is too large", 942 }, 943 } { 944 t.Run(tc.name, func(t *testing.T) { 945 gotProfile, gotErr := NewProfile(tc.config) 946 if tc.wantErr != "" { 947 if gotErr == nil { 948 t.Errorf("NewProfile(%#v) = %#v, but want err %q", tc.config, gotProfile, tc.wantErr) 949 } 950 if !strings.Contains(gotErr.Error(), tc.wantErr) { 951 t.Errorf("NewProfile(%#v) = %q, but want %q", tc.config, gotErr, tc.wantErr) 952 } 953 } else { 954 if gotErr != nil { 955 t.Errorf("NewProfile(%#v) = %q, but want no error", tc.config, gotErr) 956 } 957 } 958 }) 959 } 960 }