github.com/letsencrypt/boulder@v0.20251208.0/ca/ca.go (about) 1 package ca 2 3 import ( 4 "bytes" 5 "context" 6 "crypto" 7 "crypto/rand" 8 "crypto/sha256" 9 "crypto/x509" 10 "crypto/x509/pkix" 11 "encoding/asn1" 12 "encoding/hex" 13 "errors" 14 "fmt" 15 "math/big" 16 mrand "math/rand/v2" 17 "slices" 18 19 ct "github.com/google/certificate-transparency-go" 20 cttls "github.com/google/certificate-transparency-go/tls" 21 "github.com/jmhodges/clock" 22 "github.com/miekg/pkcs11" 23 "github.com/prometheus/client_golang/prometheus" 24 "github.com/prometheus/client_golang/prometheus/promauto" 25 "go.opentelemetry.io/otel" 26 "go.opentelemetry.io/otel/attribute" 27 "go.opentelemetry.io/otel/trace" 28 "golang.org/x/crypto/cryptobyte" 29 cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1" 30 "google.golang.org/protobuf/types/known/timestamppb" 31 32 capb "github.com/letsencrypt/boulder/ca/proto" 33 "github.com/letsencrypt/boulder/core" 34 csrlib "github.com/letsencrypt/boulder/csr" 35 berrors "github.com/letsencrypt/boulder/errors" 36 "github.com/letsencrypt/boulder/goodkey" 37 "github.com/letsencrypt/boulder/identifier" 38 "github.com/letsencrypt/boulder/issuance" 39 "github.com/letsencrypt/boulder/linter" 40 blog "github.com/letsencrypt/boulder/log" 41 rapb "github.com/letsencrypt/boulder/ra/proto" 42 sapb "github.com/letsencrypt/boulder/sa/proto" 43 ) 44 45 type certificateType string 46 47 const ( 48 precertType = certificateType("precertificate") 49 certType = certificateType("certificate") 50 ) 51 52 // issuanceEvent is logged before and after issuance of precertificates and certificates. 53 // The `omitempty` fields are not always present. 54 // CSR, Precertificate, and Certificate are hex-encoded DER bytes to make it easier to 55 // ad-hoc search for sequences or OIDs in logs. Other data, like public key within CSR, 56 // is logged as base64 because it doesn't have interesting DER structure. 57 type issuanceEvent struct { 58 Requester int64 59 OrderID int64 60 Profile string 61 Issuer string 62 IssuanceRequest *issuance.IssuanceRequest 63 CSR string `json:",omitempty"` 64 Result issuanceEventResult 65 } 66 67 // issuanceEventResult exists just to lend some extra structure to the 68 // issuanceEvent struct above. 69 type issuanceEventResult struct { 70 Precertificate string `json:",omitempty"` 71 Certificate string `json:",omitempty"` 72 } 73 74 // caMetrics holds various metrics which are shared between caImpl and crlImpl. 75 type caMetrics struct { 76 signatureCount *prometheus.CounterVec 77 signErrorCount *prometheus.CounterVec 78 lintErrorCount prometheus.Counter 79 certificates *prometheus.CounterVec 80 } 81 82 func NewCAMetrics(stats prometheus.Registerer) *caMetrics { 83 signatureCount := promauto.With(stats).NewCounterVec(prometheus.CounterOpts{ 84 Name: "signatures", 85 Help: "Number of signatures", 86 }, []string{"purpose", "issuer"}) 87 88 signErrorCount := promauto.With(stats).NewCounterVec(prometheus.CounterOpts{ 89 Name: "signature_errors", 90 Help: "A counter of signature errors labelled by error type", 91 }, []string{"type"}) 92 93 lintErrorCount := promauto.With(stats).NewCounter(prometheus.CounterOpts{ 94 Name: "lint_errors", 95 Help: "Number of issuances that were halted by linting errors", 96 }) 97 98 certificates := promauto.With(stats).NewCounterVec(prometheus.CounterOpts{ 99 Name: "certificates", 100 Help: "Number of certificates issued", 101 }, []string{"profile"}) 102 103 return &caMetrics{signatureCount, signErrorCount, lintErrorCount, certificates} 104 } 105 106 func (m *caMetrics) noteSignError(err error) { 107 var pkcs11Error pkcs11.Error 108 if errors.As(err, &pkcs11Error) { 109 m.signErrorCount.WithLabelValues("HSM").Inc() 110 } 111 } 112 113 // certificateAuthorityImpl represents a CA that signs certificates. 114 type certificateAuthorityImpl struct { 115 capb.UnsafeCertificateAuthorityServer 116 sa sapb.StorageAuthorityCertificateClient 117 sctClient rapb.SCTProviderClient 118 pa core.PolicyAuthority 119 issuers []*issuance.Issuer 120 profiles map[string]*issuance.Profile 121 122 // The prefix is prepended to the serial number. 123 prefix byte 124 maxNames int 125 keyPolicy goodkey.KeyPolicy 126 clk clock.Clock 127 log blog.Logger 128 metrics *caMetrics 129 tracer trace.Tracer 130 } 131 132 var _ capb.CertificateAuthorityServer = (*certificateAuthorityImpl)(nil) 133 134 // NewCertificateAuthorityImpl creates a CA instance that can sign certificates 135 // from any number of issuance.Issuers and for any number of profiles. 136 func NewCertificateAuthorityImpl( 137 sa sapb.StorageAuthorityCertificateClient, 138 sctService rapb.SCTProviderClient, 139 pa core.PolicyAuthority, 140 issuers []*issuance.Issuer, 141 profiles map[string]*issuance.Profile, 142 serialPrefix byte, 143 maxNames int, 144 keyPolicy goodkey.KeyPolicy, 145 logger blog.Logger, 146 metrics *caMetrics, 147 clk clock.Clock, 148 ) (*certificateAuthorityImpl, error) { 149 if serialPrefix < 0x01 || serialPrefix > 0x7f { 150 return nil, errors.New("serial prefix must be between 0x01 (1) and 0x7f (127)") 151 } 152 153 if len(issuers) == 0 { 154 return nil, errors.New("must have at least one issuer") 155 } 156 157 if len(profiles) == 0 { 158 return nil, errors.New("must have at least one certificate profile") 159 } 160 161 issuableKeys := make(map[x509.PublicKeyAlgorithm]bool) 162 issuableProfiles := make(map[string]bool) 163 for _, issuer := range issuers { 164 if issuer.IsActive() && len(issuer.Profiles()) == 0 { 165 return nil, fmt.Errorf("issuer %q is active but has no profiles", issuer.Name()) 166 } 167 168 for _, profile := range issuer.Profiles() { 169 _, ok := profiles[profile] 170 if !ok { 171 return nil, fmt.Errorf("issuer %q lists profile %q, which is not configured", issuer.Name(), profile) 172 } 173 issuableProfiles[profile] = true 174 } 175 176 issuableKeys[issuer.KeyType()] = true 177 } 178 179 for profile := range profiles { 180 if !issuableProfiles[profile] { 181 return nil, fmt.Errorf("profile %q configured, but no issuer lists it", profile) 182 } 183 } 184 185 for _, keyAlg := range []x509.PublicKeyAlgorithm{x509.ECDSA, x509.RSA} { 186 if !issuableKeys[keyAlg] { 187 return nil, fmt.Errorf("no %s issuers configured", keyAlg) 188 } 189 } 190 191 return &certificateAuthorityImpl{ 192 sa: sa, 193 sctClient: sctService, 194 pa: pa, 195 issuers: issuers, 196 profiles: profiles, 197 prefix: serialPrefix, 198 maxNames: maxNames, 199 keyPolicy: keyPolicy, 200 log: logger, 201 metrics: metrics, 202 tracer: otel.GetTracerProvider().Tracer("github.com/letsencrypt/boulder/ca"), 203 clk: clk, 204 }, nil 205 } 206 207 // IssueCertificate is the gRPC handler responsible for the entire [issuance 208 // cycle]. It takes as input just a CSR and a profile name. It generates the 209 // unique serial number locally, and uses the profile and the CA's clock to 210 // generate the validity period. It writes the serial to the database to prevent 211 // duplicate use of serials, generates and stores the *linting* precertificate 212 // as a record of what we intended to issue, contacts the SCTService (currently 213 // an RA instance) to retrieve SCTs, and finally generates and saves the final 214 // certificate. 215 // 216 // [issuance cycle]: 217 // https://github.com/letsencrypt/boulder/blob/main/docs/ISSUANCE-CYCLE.md 218 func (ca *certificateAuthorityImpl) IssueCertificate(ctx context.Context, req *capb.IssueCertificateRequest) (*capb.IssueCertificateResponse, error) { 219 // Step 1: Locally process the gRPC request and its embedded CSR to extract 220 // the relevant information, like the pubkey and SANs. Also generate 221 // some metadata from scratch, such as the serial and validity period. 222 if core.IsAnyNilOrZero(req, req.RegistrationID, req.OrderID, req.CertProfileName, req.Csr) { 223 return nil, berrors.InternalServerError("Incomplete issue certificate request") 224 } 225 226 if ca.sctClient == nil { 227 return nil, errors.New("IssueCertificate called with a nil SCT service") 228 } 229 230 profile, ok := ca.profiles[req.CertProfileName] 231 if !ok { 232 return nil, fmt.Errorf("incapable of using a profile named %q", req.CertProfileName) 233 } 234 235 notBefore, notAfter := profile.GenerateValidity(ca.clk.Now()) 236 237 csr, err := x509.ParseCertificateRequest(req.Csr) 238 if err != nil { 239 return nil, err 240 } 241 242 err = csrlib.VerifyCSR(ctx, csr, ca.maxNames, &ca.keyPolicy, ca.pa) 243 if err != nil { 244 return nil, err 245 } 246 247 issuer, err := ca.pickIssuer(req.CertProfileName, csr.PublicKeyAlgorithm) 248 if err != nil { 249 return nil, err 250 } 251 252 if issuer.Cert.NotAfter.Before(notAfter) { 253 err = berrors.InternalServerError("cannot issue a certificate that expires after the issuer certificate") 254 ca.log.AuditErr(err.Error()) 255 return nil, err 256 } 257 258 subjectKeyId, err := generateSKID(csr.PublicKey) 259 if err != nil { 260 return nil, fmt.Errorf("computing subject key ID: %w", err) 261 } 262 263 dnsNames, ipAddresses, err := identifier.FromCSR(csr).ToValues() 264 if err != nil { 265 return nil, err 266 } 267 268 var ipStrings []string 269 for _, ip := range csr.IPAddresses { 270 ipStrings = append(ipStrings, ip.String()) 271 } 272 273 serialBigInt, err := ca.generateSerialNumber() 274 if err != nil { 275 return nil, err 276 } 277 serialHex := core.SerialToString(serialBigInt) 278 279 // Step 2: Persist the serial and minimal metadata, to ensure that we never 280 // duplicate a serial. 281 _, err = ca.sa.AddSerial(ctx, &sapb.AddSerialRequest{ 282 Serial: serialHex, 283 RegID: req.RegistrationID, 284 Created: timestamppb.New(ca.clk.Now()), 285 Expires: timestamppb.New(notAfter), 286 }) 287 if err != nil { 288 return nil, fmt.Errorf("persisting serial to database: %w", err) 289 } 290 291 // Step 3: Issue the linting precert, persist it to the database, and then 292 // issue the real precert. 293 precertReq := &issuance.IssuanceRequest{ 294 PublicKey: issuance.MarshalablePublicKey{PublicKey: csr.PublicKey}, 295 SubjectKeyId: subjectKeyId, 296 Serial: serialBigInt.Bytes(), 297 NotBefore: notBefore, 298 NotAfter: notAfter, 299 CommonName: csrlib.CNFromCSR(csr), 300 DNSNames: dnsNames, 301 IPAddresses: ipAddresses, 302 IncludeCTPoison: true, 303 } 304 305 _, span := ca.tracer.Start(ctx, "issuance", trace.WithAttributes( 306 attribute.String("serial", serialHex), 307 attribute.String("issuer", issuer.Name()), 308 attribute.String("certProfileName", req.CertProfileName), 309 attribute.StringSlice("names", csr.DNSNames), 310 attribute.StringSlice("ipAddresses", ipStrings), 311 )) 312 defer span.End() 313 314 lintPrecertDER, issuanceToken, err := issuer.Prepare(profile, precertReq) 315 if err != nil { 316 ca.log.AuditErrf("Preparing precert failed: serial=[%s] err=[%v]", serialHex, err) 317 if errors.Is(err, linter.ErrLinting) { 318 ca.metrics.lintErrorCount.Inc() 319 } 320 return nil, fmt.Errorf("failed to prepare precertificate signing: %w", err) 321 } 322 323 // Note: we write the linting certificate bytes to this table, rather than the precertificate 324 // (which we audit log but do not put in the database). This is to ensure that even if there is 325 // an error immediately after signing the precertificate, we have a record in the DB of what we 326 // intended to sign, and can do revocations based on that. See #6807. 327 // The name of the SA method ("AddPrecertificate") is a historical artifact. 328 _, err = ca.sa.AddPrecertificate(context.Background(), &sapb.AddCertificateRequest{ 329 Der: lintPrecertDER, 330 RegID: req.RegistrationID, 331 Issued: timestamppb.New(ca.clk.Now()), 332 IssuerNameID: int64(issuer.NameID()), 333 }) 334 if err != nil { 335 return nil, fmt.Errorf("persisting linting precert to database: %w", err) 336 } 337 338 ca.log.AuditObject("Signing precert", issuanceEvent{ 339 Requester: req.RegistrationID, 340 OrderID: req.OrderID, 341 Profile: req.CertProfileName, 342 Issuer: issuer.Name(), 343 IssuanceRequest: precertReq, 344 CSR: hex.EncodeToString(csr.Raw), 345 }) 346 347 precertDER, err := issuer.Issue(issuanceToken) 348 if err != nil { 349 ca.metrics.noteSignError(err) 350 ca.log.AuditErrf("Signing precert failed: serial=[%s] err=[%v]", serialHex, err) 351 return nil, fmt.Errorf("failed to sign precertificate: %w", err) 352 } 353 ca.metrics.signatureCount.With(prometheus.Labels{"purpose": string(precertType), "issuer": issuer.Name()}).Inc() 354 355 ca.log.AuditObject("Signing precert success", issuanceEvent{ 356 Requester: req.RegistrationID, 357 OrderID: req.OrderID, 358 Profile: req.CertProfileName, 359 Issuer: issuer.Name(), 360 IssuanceRequest: precertReq, 361 Result: issuanceEventResult{Precertificate: hex.EncodeToString(precertDER)}, 362 }) 363 364 err = tbsCertIsDeterministic(lintPrecertDER, precertDER) 365 if err != nil { 366 return nil, err 367 } 368 369 precert, err := x509.ParseCertificate(precertDER) 370 if err != nil { 371 return nil, fmt.Errorf("parsing precertificate: %w", err) 372 } 373 374 // Step 4: Get SCTs for inclusion in the final certificate. 375 sctResp, err := ca.sctClient.GetSCTs(ctx, &rapb.SCTRequest{PrecertDER: precertDER}) 376 if err != nil { 377 return nil, fmt.Errorf("getting SCTs: %w", err) 378 } 379 380 var scts []ct.SignedCertificateTimestamp 381 for _, singleSCTBytes := range sctResp.SctDER { 382 var sct ct.SignedCertificateTimestamp 383 _, err = cttls.Unmarshal(singleSCTBytes, &sct) 384 if err != nil { 385 return nil, err 386 } 387 scts = append(scts, sct) 388 } 389 390 // Step 5: Issue and save the final certificate. 391 // 392 // Given a precertificate, a set of SCTs for that precertificate, and the same 393 // issuer and profile which were used to generate that precert, generate a 394 // linting final certificate, then sign a final certificate using a real 395 // issuer. The poison extension is removed from the precertificate and a SCT 396 // list extension is inserted in its place. Except for this and the signature 397 // the final certificate exactly matches the precertificate. 398 // 399 // It's critical not to sign two different final certificates for the same 400 // precertificate. That's why this code is inline: the only way to reach this 401 // point is to already have generated a unique serial and unique precert; if 402 // any of the previous steps returned an error, then the whole certificate 403 // issuance attempt fails and any subsequent attempt to reach this code will 404 // generate a new serial. 405 certReq, err := issuance.RequestFromPrecert(precert, scts) 406 if err != nil { 407 return nil, err 408 } 409 410 lintCertDER, issuanceToken, err := issuer.Prepare(profile, certReq) 411 if err != nil { 412 ca.log.AuditErrf("Preparing cert failed: serial=[%s] err=[%v]", serialHex, err) 413 return nil, fmt.Errorf("failed to prepare certificate signing: %w", err) 414 } 415 416 ca.log.AuditObject("Signing cert", issuanceEvent{ 417 Requester: req.RegistrationID, 418 OrderID: req.OrderID, 419 Profile: req.CertProfileName, 420 Issuer: issuer.Name(), 421 IssuanceRequest: certReq, 422 }) 423 424 certDER, err := issuer.Issue(issuanceToken) 425 if err != nil { 426 ca.metrics.noteSignError(err) 427 ca.log.AuditErrf("Signing cert failed: serial=[%s] err=[%v]", serialHex, err) 428 return nil, fmt.Errorf("failed to sign certificate: %w", err) 429 } 430 ca.metrics.signatureCount.With(prometheus.Labels{"purpose": string(certType), "issuer": issuer.Name()}).Inc() 431 ca.metrics.certificates.With(prometheus.Labels{"profile": req.CertProfileName}).Inc() 432 433 ca.log.AuditObject("Signing cert success", issuanceEvent{ 434 Requester: req.RegistrationID, 435 OrderID: req.OrderID, 436 Profile: req.CertProfileName, 437 Issuer: issuer.Name(), 438 IssuanceRequest: certReq, 439 Result: issuanceEventResult{Certificate: hex.EncodeToString(certDER)}, 440 }) 441 442 err = tbsCertIsDeterministic(lintCertDER, certDER) 443 if err != nil { 444 return nil, err 445 } 446 447 _, err = ca.sa.AddCertificate(ctx, &sapb.AddCertificateRequest{ 448 Der: certDER, 449 RegID: req.RegistrationID, 450 Issued: timestamppb.New(ca.clk.Now()), 451 }) 452 if err != nil { 453 ca.log.AuditErrf("Failed RPC to store at SA: serial=[%s] err=[%v]", serialHex, hex.EncodeToString(certDER)) 454 return nil, fmt.Errorf("persisting cert to database: %w", err) 455 } 456 457 return &capb.IssueCertificateResponse{DER: certDER}, nil 458 } 459 460 // pickIssuer returns an issuer which is willing to issue certificates for the 461 // given profile and public key algorithm. If no such issuer exists, it returns 462 // an error. If multiple such issuers exist, it selects one at random. 463 func (ca *certificateAuthorityImpl) pickIssuer(profileName string, keyAlg x509.PublicKeyAlgorithm) (*issuance.Issuer, error) { 464 var pool []*issuance.Issuer 465 for _, issuer := range ca.issuers { 466 if !issuer.IsActive() { 467 continue 468 } 469 if issuer.KeyType() != keyAlg { 470 continue 471 } 472 if !slices.Contains(issuer.Profiles(), profileName) { 473 continue 474 } 475 pool = append(pool, issuer) 476 } 477 478 if len(pool) == 0 { 479 return nil, fmt.Errorf("no issuer found for profile %q and key algorithm %s", profileName, keyAlg) 480 } 481 482 return pool[mrand.IntN(len(pool))], nil 483 } 484 485 // generateSerialNumber produces a big.Int which has more than 64 bits of 486 // entropy and has the CA's configured one-byte prefix. 487 func (ca *certificateAuthorityImpl) generateSerialNumber() (*big.Int, error) { 488 // We want 136 bits of random number, plus an 8-bit instance id prefix. 489 const randBits = 136 490 serialBytes := make([]byte, randBits/8+1) 491 serialBytes[0] = ca.prefix 492 _, err := rand.Read(serialBytes[1:]) 493 if err != nil { 494 err = berrors.InternalServerError("failed to generate serial: %s", err) 495 ca.log.AuditErrf("Serial randomness failed, err=[%v]", err) 496 return nil, err 497 } 498 serialBigInt := big.NewInt(0) 499 serialBigInt = serialBigInt.SetBytes(serialBytes) 500 501 return serialBigInt, nil 502 } 503 504 // generateSKID computes the Subject Key Identifier using one of the methods in 505 // RFC 7093 Section 2 Additional Methods for Generating Key Identifiers: 506 // The keyIdentifier [may be] composed of the leftmost 160-bits of the 507 // SHA-256 hash of the value of the BIT STRING subjectPublicKey 508 // (excluding the tag, length, and number of unused bits). 509 func generateSKID(pk crypto.PublicKey) ([]byte, error) { 510 pkBytes, err := x509.MarshalPKIXPublicKey(pk) 511 if err != nil { 512 return nil, err 513 } 514 515 var pkixPublicKey struct { 516 Algo pkix.AlgorithmIdentifier 517 BitString asn1.BitString 518 } 519 if _, err := asn1.Unmarshal(pkBytes, &pkixPublicKey); err != nil { 520 return nil, err 521 } 522 523 skid := sha256.Sum256(pkixPublicKey.BitString.Bytes) 524 return skid[0:20:20], nil 525 } 526 527 // verifyTBSCertIsDeterministic verifies that x509.CreateCertificate signing 528 // operation is deterministic and produced identical DER bytes between the given 529 // lint certificate and leaf certificate. If the DER byte equality check fails 530 // it's mississuance, but it's better to know about the problem sooner than 531 // later. The caller is responsible for passing the appropriate valid 532 // certificate bytes in the correct position. 533 func tbsCertIsDeterministic(lintCertBytes []byte, leafCertBytes []byte) error { 534 if core.IsAnyNilOrZero(lintCertBytes, leafCertBytes) { 535 return fmt.Errorf("lintCertBytes of leafCertBytes were nil") 536 } 537 538 // extractTBSCertBytes is a partial copy of //crypto/x509/parser.go to 539 // extract the RawTBSCertificate field from given DER bytes. It the 540 // RawTBSCertificate field bytes or an error if the given bytes cannot be 541 // parsed. This is far more performant than parsing the entire *Certificate 542 // structure with x509.ParseCertificate(). 543 // 544 // RFC 5280, Section 4.1 545 // Certificate ::= SEQUENCE { 546 // tbsCertificate TBSCertificate, 547 // signatureAlgorithm AlgorithmIdentifier, 548 // signatureValue BIT STRING } 549 // 550 // TBSCertificate ::= SEQUENCE { 551 // .. 552 extractTBSCertBytes := func(inputDERBytes *[]byte) ([]byte, error) { 553 input := cryptobyte.String(*inputDERBytes) 554 555 // Extract the Certificate bytes 556 if !input.ReadASN1(&input, cryptobyte_asn1.SEQUENCE) { 557 return nil, errors.New("malformed certificate") 558 } 559 560 var tbs cryptobyte.String 561 // Extract the TBSCertificate bytes from the Certificate bytes 562 if !input.ReadASN1(&tbs, cryptobyte_asn1.SEQUENCE) { 563 return nil, errors.New("malformed tbs certificate") 564 } 565 566 if tbs.Empty() { 567 return nil, errors.New("parsed RawTBSCertificate field was empty") 568 } 569 570 return tbs, nil 571 } 572 573 lintRawTBSCert, err := extractTBSCertBytes(&lintCertBytes) 574 if err != nil { 575 return fmt.Errorf("while extracting lint TBS cert: %w", err) 576 } 577 578 leafRawTBSCert, err := extractTBSCertBytes(&leafCertBytes) 579 if err != nil { 580 return fmt.Errorf("while extracting leaf TBS cert: %w", err) 581 } 582 583 if !bytes.Equal(lintRawTBSCert, leafRawTBSCert) { 584 return fmt.Errorf("mismatch between lintCert and leafCert RawTBSCertificate DER bytes: \"%x\" != \"%x\"", lintRawTBSCert, leafRawTBSCert) 585 } 586 587 return nil 588 }