1 package issuance
2
3 import (
4 "bytes"
5 "crypto"
6 "crypto/ecdsa"
7 "crypto/elliptic"
8 "crypto/rand"
9 "crypto/rsa"
10 "crypto/sha1"
11 "crypto/sha256"
12 "crypto/x509"
13 "crypto/x509/pkix"
14 "encoding/asn1"
15 "encoding/json"
16 "errors"
17 "fmt"
18 "math/big"
19 "os"
20 "sync"
21 "time"
22
23 ct "github.com/google/certificate-transparency-go"
24 cttls "github.com/google/certificate-transparency-go/tls"
25 ctx509 "github.com/google/certificate-transparency-go/x509"
26 "github.com/jmhodges/clock"
27 "golang.org/x/crypto/ocsp"
28
29 "github.com/letsencrypt/boulder/config"
30 "github.com/letsencrypt/boulder/core"
31 "github.com/letsencrypt/boulder/linter"
32 "github.com/letsencrypt/boulder/precert"
33 "github.com/letsencrypt/boulder/privatekey"
34 "github.com/letsencrypt/pkcs11key/v4"
35 )
36
37
38 type ProfileConfig struct {
39 AllowMustStaple bool
40 AllowCTPoison bool
41 AllowSCTList bool
42 AllowCommonName bool
43
44 MaxValidityPeriod config.Duration
45 MaxValidityBackdate config.Duration
46
47
48 Policies []PolicyConfig `validate:"-"`
49 }
50
51
52 type PolicyConfig struct {
53 OID string `validate:"required"`
54 }
55
56
57 type IssuerConfig struct {
58 UseForRSALeaves bool
59 UseForECDSALeaves bool
60
61 IssuerURL string `validate:"required,url"`
62 OCSPURL string `validate:"required,url"`
63 CRLURL string `validate:"omitempty,url"`
64
65 Location IssuerLoc
66 }
67
68
69
70
71 type IssuerLoc struct {
72
73 File string `validate:"required_without_all=ConfigFile PKCS11"`
74
75 ConfigFile string `validate:"required_without_all=PKCS11 File"`
76
77 PKCS11 *pkcs11key.Config `validate:"required_without_all=ConfigFile File"`
78
79 CertFile string `validate:"required"`
80
81
82 NumSessions int
83 }
84
85
86 func LoadIssuer(location IssuerLoc) (*Certificate, crypto.Signer, error) {
87 issuerCert, err := LoadCertificate(location.CertFile)
88 if err != nil {
89 return nil, nil, err
90 }
91
92 signer, err := loadSigner(location, issuerCert)
93 if err != nil {
94 return nil, nil, err
95 }
96
97 if !core.KeyDigestEquals(signer.Public(), issuerCert.PublicKey) {
98 return nil, nil, fmt.Errorf("Issuer key did not match issuer cert %s", location.CertFile)
99 }
100 return issuerCert, signer, err
101 }
102
103 func LoadCertificate(path string) (*Certificate, error) {
104 cert, err := core.LoadCert(path)
105 if err != nil {
106 return nil, err
107 }
108 return NewCertificate(cert)
109 }
110
111 func loadSigner(location IssuerLoc, cert *Certificate) (crypto.Signer, error) {
112 if location.File != "" {
113 signer, _, err := privatekey.Load(location.File)
114 if err != nil {
115 return nil, err
116 }
117 return signer, nil
118 }
119
120 var pkcs11Config *pkcs11key.Config
121 if location.ConfigFile != "" {
122 contents, err := os.ReadFile(location.ConfigFile)
123 if err != nil {
124 return nil, err
125 }
126 pkcs11Config = new(pkcs11key.Config)
127 err = json.Unmarshal(contents, pkcs11Config)
128 if err != nil {
129 return nil, err
130 }
131 } else {
132 pkcs11Config = location.PKCS11
133 }
134
135 if pkcs11Config.Module == "" ||
136 pkcs11Config.TokenLabel == "" ||
137 pkcs11Config.PIN == "" {
138 return nil, fmt.Errorf("missing a field in pkcs11Config %#v", pkcs11Config)
139 }
140
141 numSessions := location.NumSessions
142 if numSessions <= 0 {
143 numSessions = 1
144 }
145
146 return pkcs11key.NewPool(numSessions, pkcs11Config.Module,
147 pkcs11Config.TokenLabel, pkcs11Config.PIN, cert.PublicKey)
148 }
149
150
151 type Profile struct {
152 useForRSALeaves bool
153 useForECDSALeaves bool
154
155 allowMustStaple bool
156 allowCTPoison bool
157 allowSCTList bool
158 allowCommonName bool
159
160 sigAlg x509.SignatureAlgorithm
161 ocspURL string
162 crlURL string
163 issuerURL string
164
165 maxBackdate time.Duration
166 maxValidity time.Duration
167 }
168
169
170
171 func NewProfile(profileConfig ProfileConfig, issuerConfig IssuerConfig) (*Profile, error) {
172 if issuerConfig.IssuerURL == "" {
173 return nil, errors.New("Issuer URL is required")
174 }
175 if issuerConfig.OCSPURL == "" {
176 return nil, errors.New("OCSP URL is required")
177 }
178
179 sp := &Profile{
180 useForRSALeaves: issuerConfig.UseForRSALeaves,
181 useForECDSALeaves: issuerConfig.UseForECDSALeaves,
182 allowMustStaple: profileConfig.AllowMustStaple,
183 allowCTPoison: profileConfig.AllowCTPoison,
184 allowSCTList: profileConfig.AllowSCTList,
185 allowCommonName: profileConfig.AllowCommonName,
186 issuerURL: issuerConfig.IssuerURL,
187 crlURL: issuerConfig.CRLURL,
188 ocspURL: issuerConfig.OCSPURL,
189 maxBackdate: profileConfig.MaxValidityBackdate.Duration,
190 maxValidity: profileConfig.MaxValidityPeriod.Duration,
191 }
192
193 return sp, nil
194 }
195
196
197
198 func (p *Profile) requestValid(clk clock.Clock, req *IssuanceRequest) error {
199 switch req.PublicKey.(type) {
200 case *rsa.PublicKey:
201 if !p.useForRSALeaves {
202 return errors.New("cannot sign RSA public keys")
203 }
204 case *ecdsa.PublicKey:
205 if !p.useForECDSALeaves {
206 return errors.New("cannot sign ECDSA public keys")
207 }
208 default:
209 return errors.New("unsupported public key type")
210 }
211
212 if !p.allowMustStaple && req.IncludeMustStaple {
213 return errors.New("must-staple extension cannot be included")
214 }
215
216 if !p.allowCTPoison && req.IncludeCTPoison {
217 return errors.New("ct poison extension cannot be included")
218 }
219
220 if !p.allowSCTList && req.sctList != nil {
221 return errors.New("sct list extension cannot be included")
222 }
223
224 if req.IncludeCTPoison && req.sctList != nil {
225 return errors.New("cannot include both ct poison and sct list extensions")
226 }
227
228 if !p.allowCommonName && req.CommonName != "" {
229 return errors.New("common name cannot be included")
230 }
231
232
233
234 validity := req.NotAfter.Add(time.Second).Sub(req.NotBefore)
235 if validity <= 0 {
236 return errors.New("NotAfter must be after NotBefore")
237 }
238 if validity > p.maxValidity {
239 return fmt.Errorf("validity period is more than the maximum allowed period (%s>%s)", validity, p.maxValidity)
240 }
241 backdatedBy := clk.Now().Sub(req.NotBefore)
242 if backdatedBy > p.maxBackdate {
243 return fmt.Errorf("NotBefore is backdated more than the maximum allowed period (%s>%s)", backdatedBy, p.maxBackdate)
244 }
245 if backdatedBy < 0 {
246 return errors.New("NotBefore is in the future")
247 }
248
249
250
251
252 if len(req.Serial) > 19 || len(req.Serial) < 9 {
253 return errors.New("serial must be between 9 and 19 bytes")
254 }
255
256 return nil
257 }
258
259 var defaultEKU = []x509.ExtKeyUsage{
260 x509.ExtKeyUsageServerAuth,
261 x509.ExtKeyUsageClientAuth,
262 }
263
264 func (p *Profile) generateTemplate() *x509.Certificate {
265 template := &x509.Certificate{
266 SignatureAlgorithm: p.sigAlg,
267 ExtKeyUsage: defaultEKU,
268 OCSPServer: []string{p.ocspURL},
269 IssuingCertificateURL: []string{p.issuerURL},
270 BasicConstraintsValid: true,
271
272 PolicyIdentifiers: []asn1.ObjectIdentifier{{2, 23, 140, 1, 2, 1}},
273 }
274
275 if p.crlURL != "" {
276 template.CRLDistributionPoints = []string{p.crlURL}
277 }
278
279 return template
280 }
281
282
283
284
285
286
287 type IssuerID int64
288
289
290
291
292
293 type IssuerNameID int64
294
295
296
297 type Certificate struct {
298 *x509.Certificate
299 id IssuerID
300 nameID IssuerNameID
301 nameHash [20]byte
302 keyHash [20]byte
303 }
304
305
306
307
308 func NewCertificate(ic *x509.Certificate) (*Certificate, error) {
309 res := Certificate{Certificate: ic}
310
311
312 h := sha256.Sum256(ic.Raw)
313 res.id = IssuerID(big.NewInt(0).SetBytes(h[:4]).Int64())
314
315
316 res.nameID = truncatedHash(ic.RawSubject)
317
318
319 res.nameHash = sha1.Sum(ic.RawSubject)
320
321
322
323
324
325
326
327 var spki struct {
328 Algorithm pkix.AlgorithmIdentifier
329 PublicKey asn1.BitString
330 }
331 _, err := asn1.Unmarshal(ic.RawSubjectPublicKeyInfo, &spki)
332 if err != nil {
333 return nil, err
334 }
335 res.keyHash = sha1.Sum(spki.PublicKey.RightAlign())
336
337 return &res, nil
338 }
339
340
341
342
343 func (ic *Certificate) ID() IssuerID {
344 return ic.id
345 }
346
347
348
349
350 func (ic *Certificate) NameID() IssuerNameID {
351 return ic.nameID
352 }
353
354
355
356
357 func (ic *Certificate) NameHash() [20]byte {
358 return ic.nameHash
359 }
360
361
362
363
364 func (ic *Certificate) KeyHash() [20]byte {
365 return ic.keyHash
366 }
367
368
369
370
371 func GetIssuerNameID(ee *x509.Certificate) IssuerNameID {
372 return truncatedHash(ee.RawIssuer)
373 }
374
375
376
377
378
379
380 func GetOCSPIssuerNameID(resp *ocsp.Response) IssuerNameID {
381 return truncatedHash(resp.RawResponderName)
382 }
383
384
385
386
387
388 func truncatedHash(name []byte) IssuerNameID {
389 h := crypto.SHA1.New()
390 h.Write(name)
391 s := h.Sum(nil)
392 return IssuerNameID(big.NewInt(0).SetBytes(s[:7]).Int64())
393 }
394
395
396
397 type Issuer struct {
398 Cert *Certificate
399 Signer crypto.Signer
400 Profile *Profile
401 Linter *linter.Linter
402 Clk clock.Clock
403 }
404
405
406
407 func NewIssuer(cert *Certificate, signer crypto.Signer, profile *Profile, linter *linter.Linter, clk clock.Clock) (*Issuer, error) {
408 switch k := cert.PublicKey.(type) {
409 case *rsa.PublicKey:
410 profile.sigAlg = x509.SHA256WithRSA
411 case *ecdsa.PublicKey:
412 switch k.Curve {
413 case elliptic.P256():
414 profile.sigAlg = x509.ECDSAWithSHA256
415 case elliptic.P384():
416 profile.sigAlg = x509.ECDSAWithSHA384
417 default:
418 return nil, fmt.Errorf("unsupported ECDSA curve: %s", k.Curve.Params().Name)
419 }
420 default:
421 return nil, errors.New("unsupported issuer key type")
422 }
423
424 if profile.useForRSALeaves || profile.useForECDSALeaves {
425 if cert.KeyUsage&x509.KeyUsageCertSign == 0 {
426 return nil, errors.New("end-entity signing cert does not have keyUsage certSign")
427 }
428 }
429
430 if cert.KeyUsage&x509.KeyUsageDigitalSignature == 0 {
431 return nil, errors.New("end-entity ocsp signing cert does not have keyUsage digitalSignature")
432 }
433
434 i := &Issuer{
435 Cert: cert,
436 Signer: signer,
437 Profile: profile,
438 Linter: linter,
439 Clk: clk,
440 }
441 return i, nil
442 }
443
444
445
446
447 func (i *Issuer) Algs() []x509.PublicKeyAlgorithm {
448 var algs []x509.PublicKeyAlgorithm
449 if i.Profile.useForRSALeaves {
450 algs = append(algs, x509.RSA)
451 }
452 if i.Profile.useForECDSALeaves {
453 algs = append(algs, x509.ECDSA)
454 }
455 return algs
456 }
457
458
459 func (i *Issuer) Name() string {
460 return i.Cert.Subject.CommonName
461 }
462
463
464
465 func (i *Issuer) ID() IssuerID {
466 return i.Cert.ID()
467 }
468
469 var ctPoisonExt = pkix.Extension{
470
471 Id: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 3},
472 Value: asn1.NullBytes,
473 Critical: true,
474 }
475
476
477 var sctListOID = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 2}
478
479 func generateSCTListExt(scts []ct.SignedCertificateTimestamp) (pkix.Extension, error) {
480 list := ctx509.SignedCertificateTimestampList{}
481 for _, sct := range scts {
482 sctBytes, err := cttls.Marshal(sct)
483 if err != nil {
484 return pkix.Extension{}, err
485 }
486 list.SCTList = append(list.SCTList, ctx509.SerializedSCT{Val: sctBytes})
487 }
488 listBytes, err := cttls.Marshal(list)
489 if err != nil {
490 return pkix.Extension{}, err
491 }
492 extBytes, err := asn1.Marshal(listBytes)
493 if err != nil {
494 return pkix.Extension{}, err
495 }
496 return pkix.Extension{
497 Id: sctListOID,
498 Value: extBytes,
499 }, nil
500 }
501
502 var mustStapleExt = pkix.Extension{
503
504 Id: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 24},
505
506
507
508
509 Value: []byte{0x30, 0x03, 0x02, 0x01, 0x05},
510 }
511
512 func generateSKID(pk crypto.PublicKey) ([]byte, error) {
513 pkBytes, err := x509.MarshalPKIXPublicKey(pk)
514 if err != nil {
515 return nil, err
516 }
517 var pkixPublicKey struct {
518 Algo pkix.AlgorithmIdentifier
519 BitString asn1.BitString
520 }
521 if _, err := asn1.Unmarshal(pkBytes, &pkixPublicKey); err != nil {
522 return nil, err
523 }
524 skid := sha1.Sum(pkixPublicKey.BitString.Bytes)
525 return skid[:], nil
526 }
527
528
529 type IssuanceRequest struct {
530 PublicKey crypto.PublicKey
531
532 Serial []byte
533
534 NotBefore time.Time
535 NotAfter time.Time
536
537 CommonName string
538 DNSNames []string
539
540 IncludeMustStaple bool
541 IncludeCTPoison bool
542
543
544
545 sctList []ct.SignedCertificateTimestamp
546
547
548
549 precertDER []byte
550 }
551
552
553
554
555
556
557 type issuanceToken struct {
558 mu sync.Mutex
559 template *x509.Certificate
560 pubKey any
561
562
563 issuer *Issuer
564 }
565
566
567
568
569
570
571 func (i *Issuer) Prepare(req *IssuanceRequest) ([]byte, *issuanceToken, error) {
572
573 err := i.Profile.requestValid(i.Clk, req)
574 if err != nil {
575 return nil, nil, err
576 }
577
578
579 template := i.Profile.generateTemplate()
580
581
582 template.NotBefore, template.NotAfter = req.NotBefore, req.NotAfter
583 template.SerialNumber = big.NewInt(0).SetBytes(req.Serial)
584 if req.CommonName != "" {
585 template.Subject.CommonName = req.CommonName
586 }
587 template.DNSNames = req.DNSNames
588 template.AuthorityKeyId = i.Cert.SubjectKeyId
589 skid, err := generateSKID(req.PublicKey)
590 if err != nil {
591 return nil, nil, err
592 }
593 template.SubjectKeyId = skid
594 switch req.PublicKey.(type) {
595 case *rsa.PublicKey:
596 template.KeyUsage = x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment
597 case *ecdsa.PublicKey:
598 template.KeyUsage = x509.KeyUsageDigitalSignature
599 }
600
601 if req.IncludeCTPoison {
602 template.ExtraExtensions = append(template.ExtraExtensions, ctPoisonExt)
603 } else if len(req.sctList) > 0 {
604 if len(req.precertDER) == 0 {
605 return nil, nil, errors.New("inconsistent request contains sctList but no precertDER")
606 }
607 sctListExt, err := generateSCTListExt(req.sctList)
608 if err != nil {
609 return nil, nil, err
610 }
611 template.ExtraExtensions = append(template.ExtraExtensions, sctListExt)
612 } else {
613 return nil, nil, errors.New("invalid request contains neither sctList nor precertDER")
614 }
615
616 if req.IncludeMustStaple {
617 template.ExtraExtensions = append(template.ExtraExtensions, mustStapleExt)
618 }
619
620
621
622 lintCertBytes, err := i.Linter.Check(template, req.PublicKey)
623 if err != nil {
624 return nil, nil, fmt.Errorf("tbsCertificate linting failed: %w", err)
625 }
626
627 if len(req.precertDER) > 0 {
628 err = precert.Correspond(req.precertDER, lintCertBytes)
629 if err != nil {
630 return nil, nil, fmt.Errorf("precert does not correspond to linted final cert: %w", err)
631 }
632 }
633
634 token := &issuanceToken{sync.Mutex{}, template, req.PublicKey, i}
635 return lintCertBytes, token, nil
636 }
637
638
639
640
641 func (i *Issuer) Issue(token *issuanceToken) ([]byte, error) {
642 if token == nil {
643 return nil, errors.New("nil issuanceToken")
644 }
645 token.mu.Lock()
646 defer token.mu.Unlock()
647 if token.template == nil {
648 return nil, errors.New("issuance token already redeemed")
649 }
650 template := token.template
651 token.template = nil
652
653 if token.issuer != i {
654 return nil, errors.New("tried to redeem issuance token with the wrong issuer")
655 }
656
657 return x509.CreateCertificate(rand.Reader, template, i.Cert.Certificate, token.pubKey, i.Signer)
658 }
659
660 func ContainsMustStaple(extensions []pkix.Extension) bool {
661 for _, ext := range extensions {
662 if ext.Id.Equal(mustStapleExt.Id) && bytes.Equal(ext.Value, mustStapleExt.Value) {
663 return true
664 }
665 }
666 return false
667 }
668
669 func containsCTPoison(extensions []pkix.Extension) bool {
670 for _, ext := range extensions {
671 if ext.Id.Equal(ctPoisonExt.Id) && bytes.Equal(ext.Value, asn1.NullBytes) {
672 return true
673 }
674 }
675 return false
676 }
677
678
679
680
681 func RequestFromPrecert(precert *x509.Certificate, scts []ct.SignedCertificateTimestamp) (*IssuanceRequest, error) {
682 if !containsCTPoison(precert.Extensions) {
683 return nil, errors.New("provided certificate doesn't contain the CT poison extension")
684 }
685 return &IssuanceRequest{
686 PublicKey: precert.PublicKey,
687 Serial: precert.SerialNumber.Bytes(),
688 NotBefore: precert.NotBefore,
689 NotAfter: precert.NotAfter,
690 CommonName: precert.Subject.CommonName,
691 DNSNames: precert.DNSNames,
692 IncludeMustStaple: ContainsMustStaple(precert.Extensions),
693 sctList: scts,
694 precertDER: precert.Raw,
695 }, nil
696 }
697
698
699
700
701
702
703 func LoadChain(certFiles []string) ([]*Certificate, error) {
704 if len(certFiles) < 2 {
705 return nil, errors.New(
706 "each chain must have at least two certificates: an intermediate and a root")
707 }
708
709
710 certs := make([]*Certificate, len(certFiles))
711 var err error
712 for i := 0; i < len(certFiles); i++ {
713 certs[i], err = LoadCertificate(certFiles[i])
714 if err != nil {
715 return nil, fmt.Errorf("failed to load certificate %q: %w", certFiles[i], err)
716 }
717 }
718
719
720
721 chain := make([]*Certificate, len(certFiles)-1)
722 for i := 0; i < len(certs)-1; i++ {
723 err = certs[i].CheckSignatureFrom(certs[i+1].Certificate)
724 if err != nil {
725 return nil, fmt.Errorf("failed to verify signature from %q to %q (%q to %q): %w",
726 certs[i+1].Subject, certs[i].Subject, certFiles[i+1], certFiles[i], err)
727 }
728 chain[i] = certs[i]
729 }
730
731
732 lastCert := certs[len(certs)-1]
733 err = lastCert.CheckSignatureFrom(lastCert.Certificate)
734 if err != nil {
735 return nil, fmt.Errorf(
736 "final cert in chain (%q; %q) must be self-signed (used only for validation): %w",
737 lastCert.Subject, certFiles[len(certFiles)-1], err)
738 }
739
740 return chain, nil
741 }
742
View as plain text