github.com/letsencrypt/boulder@v0.20251208.0/ra/ra.go (about) 1 package ra 2 3 import ( 4 "bytes" 5 "context" 6 "crypto" 7 "crypto/x509" 8 "crypto/x509/pkix" 9 "encoding/asn1" 10 "encoding/json" 11 "errors" 12 "fmt" 13 "net/url" 14 "os" 15 "slices" 16 "strconv" 17 "strings" 18 "sync" 19 "time" 20 21 "github.com/go-jose/go-jose/v4" 22 "github.com/jmhodges/clock" 23 "github.com/prometheus/client_golang/prometheus" 24 "github.com/prometheus/client_golang/prometheus/promauto" 25 "google.golang.org/protobuf/proto" 26 "google.golang.org/protobuf/types/known/durationpb" 27 "google.golang.org/protobuf/types/known/emptypb" 28 "google.golang.org/protobuf/types/known/timestamppb" 29 30 "github.com/letsencrypt/boulder/allowlist" 31 capb "github.com/letsencrypt/boulder/ca/proto" 32 "github.com/letsencrypt/boulder/config" 33 "github.com/letsencrypt/boulder/core" 34 corepb "github.com/letsencrypt/boulder/core/proto" 35 csrlib "github.com/letsencrypt/boulder/csr" 36 "github.com/letsencrypt/boulder/ctpolicy" 37 berrors "github.com/letsencrypt/boulder/errors" 38 "github.com/letsencrypt/boulder/features" 39 "github.com/letsencrypt/boulder/goodkey" 40 bgrpc "github.com/letsencrypt/boulder/grpc" 41 "github.com/letsencrypt/boulder/identifier" 42 "github.com/letsencrypt/boulder/issuance" 43 blog "github.com/letsencrypt/boulder/log" 44 "github.com/letsencrypt/boulder/metrics" 45 "github.com/letsencrypt/boulder/policy" 46 "github.com/letsencrypt/boulder/probs" 47 pubpb "github.com/letsencrypt/boulder/publisher/proto" 48 rapb "github.com/letsencrypt/boulder/ra/proto" 49 "github.com/letsencrypt/boulder/ratelimits" 50 "github.com/letsencrypt/boulder/revocation" 51 sapb "github.com/letsencrypt/boulder/sa/proto" 52 "github.com/letsencrypt/boulder/va" 53 vapb "github.com/letsencrypt/boulder/va/proto" 54 55 "github.com/letsencrypt/boulder/web" 56 ) 57 58 var ( 59 errIncompleteGRPCRequest = errors.New("incomplete gRPC request message") 60 errIncompleteGRPCResponse = errors.New("incomplete gRPC response message") 61 62 // caaRecheckDuration is the amount of time after a CAA check that we will 63 // recheck the CAA records for a domain. Per Baseline Requirements, we must 64 // recheck CAA records within 8 hours of issuance. We set this to 7 hours to 65 // stay on the safe side. 66 caaRecheckDuration = -7 * time.Hour 67 ) 68 69 // RegistrationAuthorityImpl defines an RA. 70 // 71 // NOTE: All of the fields in RegistrationAuthorityImpl need to be 72 // populated, or there is a risk of panic. 73 type RegistrationAuthorityImpl struct { 74 rapb.UnsafeRegistrationAuthorityServer 75 rapb.UnsafeSCTProviderServer 76 CA capb.CertificateAuthorityClient 77 VA va.RemoteClients 78 SA sapb.StorageAuthorityClient 79 PA core.PolicyAuthority 80 publisher pubpb.PublisherClient 81 82 clk clock.Clock 83 log blog.Logger 84 keyPolicy goodkey.KeyPolicy 85 profiles *validationProfiles 86 maxContactsPerReg int 87 limiter *ratelimits.Limiter 88 txnBuilder *ratelimits.TransactionBuilder 89 finalizeTimeout time.Duration 90 drainWG sync.WaitGroup 91 92 issuersByNameID map[issuance.NameID]*issuance.Certificate 93 94 ctpolicy *ctpolicy.CTPolicy 95 96 ctpolicyResults *prometheus.HistogramVec 97 revocationReasonCounter *prometheus.CounterVec 98 namesPerCert *prometheus.HistogramVec 99 newRegCounter prometheus.Counter 100 recheckCAACounter prometheus.Counter 101 newCertCounter prometheus.Counter 102 authzAges *prometheus.HistogramVec 103 orderAges *prometheus.HistogramVec 104 inflightFinalizes prometheus.Gauge 105 certCSRMismatch prometheus.Counter 106 pauseCounter *prometheus.CounterVec 107 } 108 109 var _ rapb.RegistrationAuthorityServer = (*RegistrationAuthorityImpl)(nil) 110 111 // Health implements our grpc.checker interface. This method will be called 112 // periodically to set the gRPC service's healthpb.Health.Check() status. 113 func (ra *RegistrationAuthorityImpl) Health(ctx context.Context) error { 114 if ra.txnBuilder.Ready() { 115 return nil 116 } 117 return errors.New("waiting for overrides") 118 } 119 120 // NewRegistrationAuthorityImpl constructs a new RA object. 121 func NewRegistrationAuthorityImpl( 122 clk clock.Clock, 123 logger blog.Logger, 124 stats prometheus.Registerer, 125 maxContactsPerReg int, 126 keyPolicy goodkey.KeyPolicy, 127 limiter *ratelimits.Limiter, 128 txnBuilder *ratelimits.TransactionBuilder, 129 maxNames int, 130 profiles *validationProfiles, 131 pubc pubpb.PublisherClient, 132 finalizeTimeout time.Duration, 133 ctp *ctpolicy.CTPolicy, 134 issuers []*issuance.Certificate, 135 ) *RegistrationAuthorityImpl { 136 ctpolicyResults := promauto.With(stats).NewHistogramVec( 137 prometheus.HistogramOpts{ 138 Name: "ctpolicy_results", 139 Help: "Histogram of latencies of ctpolicy.GetSCTs calls with success/failure/deadlineExceeded labels", 140 Buckets: metrics.InternetFacingBuckets, 141 }, 142 []string{"result"}, 143 ) 144 145 namesPerCert := promauto.With(stats).NewHistogramVec(prometheus.HistogramOpts{ 146 Name: "names_per_cert", 147 Help: "Histogram of the number of SANs in requested and issued certificates", 148 // The namesPerCert buckets are chosen based on the current Let's Encrypt 149 // limit of 100 SANs per certificate. 150 Buckets: []float64{1, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100}, 151 }, []string{"type"}) 152 153 newRegCounter := promauto.With(stats).NewCounter(prometheus.CounterOpts{ 154 Name: "new_registrations", 155 Help: "A counter of new registrations", 156 }) 157 158 recheckCAACounter := promauto.With(stats).NewCounter(prometheus.CounterOpts{ 159 Name: "recheck_caa", 160 Help: "A counter of CAA rechecks", 161 }) 162 163 newCertCounter := promauto.With(stats).NewCounter(prometheus.CounterOpts{ 164 Name: "new_certificates", 165 Help: "A counter of issued certificates", 166 }) 167 168 revocationReasonCounter := promauto.With(stats).NewCounterVec(prometheus.CounterOpts{ 169 Name: "revocation_reason", 170 Help: "A counter of certificate revocation reasons", 171 }, []string{"reason"}) 172 173 authzAges := promauto.With(stats).NewHistogramVec(prometheus.HistogramOpts{ 174 Name: "authz_ages", 175 Help: "Histogram of ages, in seconds, of Authorization objects, labelled by method and type", 176 // authzAges keeps track of how old, in seconds, authorizations are when 177 // we attach them to a new order and again when we finalize that order. 178 // We give it a non-standard bucket distribution so that the leftmost 179 // (closest to zero) bucket can be used exclusively for brand-new (i.e. 180 // not reused) authzs. Our buckets are: one nanosecond, one second, one 181 // minute, one hour, 7 hours (our CAA reuse time), 1 day, 2 days, 7 182 // days, 30 days, +inf (should be empty). 183 Buckets: []float64{0.000000001, 1, 60, 3600, 25200, 86400, 172800, 604800, 2592000, 7776000}, 184 }, []string{"method", "type"}) 185 186 orderAges := promauto.With(stats).NewHistogramVec(prometheus.HistogramOpts{ 187 Name: "order_ages", 188 Help: "Histogram of ages, in seconds, of Order objects when they're reused and finalized, labelled by method", 189 // Orders currently have a max age of 7 days (168hrs), so our buckets 190 // are: one nanosecond (new), 1 second, 10 seconds, 1 minute, 10 191 // minutes, 1 hour, 7 hours (our CAA reuse time), 1 day, 2 days, 7 days, +inf. 192 Buckets: []float64{0.000000001, 1, 10, 60, 600, 3600, 25200, 86400, 172800, 604800}, 193 }, []string{"method"}) 194 195 inflightFinalizes := promauto.With(stats).NewGauge(prometheus.GaugeOpts{ 196 Name: "inflight_finalizes", 197 Help: "Gauge of the number of current asynchronous finalize goroutines", 198 }) 199 200 certCSRMismatch := promauto.With(stats).NewCounter(prometheus.CounterOpts{ 201 Name: "cert_csr_mismatch", 202 Help: "Number of issued certificates that have failed ra.matchesCSR for any reason. This is _real bad_ and should be alerted upon.", 203 }) 204 205 pauseCounter := promauto.With(stats).NewCounterVec(prometheus.CounterOpts{ 206 Name: "paused_pairs", 207 Help: "Number of times a pause operation is performed, labeled by paused=[bool], repaused=[bool], grace=[bool]", 208 }, []string{"paused", "repaused", "grace"}) 209 210 issuersByNameID := make(map[issuance.NameID]*issuance.Certificate) 211 for _, issuer := range issuers { 212 issuersByNameID[issuer.NameID()] = issuer 213 } 214 215 ra := &RegistrationAuthorityImpl{ 216 clk: clk, 217 log: logger, 218 profiles: profiles, 219 maxContactsPerReg: maxContactsPerReg, 220 keyPolicy: keyPolicy, 221 limiter: limiter, 222 txnBuilder: txnBuilder, 223 publisher: pubc, 224 finalizeTimeout: finalizeTimeout, 225 ctpolicy: ctp, 226 ctpolicyResults: ctpolicyResults, 227 issuersByNameID: issuersByNameID, 228 namesPerCert: namesPerCert, 229 newRegCounter: newRegCounter, 230 recheckCAACounter: recheckCAACounter, 231 newCertCounter: newCertCounter, 232 revocationReasonCounter: revocationReasonCounter, 233 authzAges: authzAges, 234 orderAges: orderAges, 235 inflightFinalizes: inflightFinalizes, 236 certCSRMismatch: certCSRMismatch, 237 pauseCounter: pauseCounter, 238 } 239 return ra 240 } 241 242 // ValidationProfileConfig is a config struct which can be used to create a 243 // ValidationProfile. 244 type ValidationProfileConfig struct { 245 // PendingAuthzLifetime defines how far in the future an authorization's 246 // "expires" timestamp is set when it is first created, i.e. how much 247 // time the applicant has to attempt the challenge. 248 PendingAuthzLifetime config.Duration `validate:"required"` 249 // ValidAuthzLifetime defines how far in the future an authorization's 250 // "expires" timestamp is set when one of its challenges is fulfilled, 251 // i.e. how long a validated authorization may be reused. 252 ValidAuthzLifetime config.Duration `validate:"required"` 253 // OrderLifetime defines how far in the future an order's "expires" 254 // timestamp is set when it is first created, i.e. how much time the 255 // applicant has to fulfill all challenges and finalize the order. This is 256 // a maximum time: if the order reuses an authorization and that authz 257 // expires earlier than this OrderLifetime would otherwise set, then the 258 // order's expiration is brought in to match that authorization. 259 OrderLifetime config.Duration `validate:"required"` 260 // MaxNames is the maximum number of subjectAltNames in a single cert. 261 // The value supplied MUST be greater than 0 and no more than 100. These 262 // limits are per section 7.1 of our combined CP/CPS, under "DV-SSL 263 // Subscriber Certificate". The value must be less than or equal to the 264 // global (i.e. not per-profile) value configured in the CA. 265 MaxNames int `validate:"omitempty,min=1,max=100"` 266 // AllowList specifies the path to a YAML file containing a list of 267 // account IDs permitted to use this profile. If no path is 268 // specified, the profile is open to all accounts. If the file 269 // exists but is empty, the profile is closed to all accounts. 270 AllowList string `validate:"omitempty"` 271 // IdentifierTypes is a list of identifier types that may be issued under 272 // this profile. 273 IdentifierTypes []identifier.IdentifierType `validate:"required,dive,oneof=dns ip"` 274 } 275 276 // validationProfile holds the attributes of a given validation profile. 277 type validationProfile struct { 278 // pendingAuthzLifetime defines how far in the future an authorization's 279 // "expires" timestamp is set when it is first created, i.e. how much 280 // time the applicant has to attempt the challenge. 281 pendingAuthzLifetime time.Duration 282 // validAuthzLifetime defines how far in the future an authorization's 283 // "expires" timestamp is set when one of its challenges is fulfilled, 284 // i.e. how long a validated authorization may be reused. 285 validAuthzLifetime time.Duration 286 // orderLifetime defines how far in the future an order's "expires" 287 // timestamp is set when it is first created, i.e. how much time the 288 // applicant has to fulfill all challenges and finalize the order. This is 289 // a maximum time: if the order reuses an authorization and that authz 290 // expires earlier than this OrderLifetime would otherwise set, then the 291 // order's expiration is brought in to match that authorization. 292 orderLifetime time.Duration 293 // maxNames is the maximum number of subjectAltNames in a single cert. 294 maxNames int 295 // allowList holds the set of account IDs allowed to use this profile. If 296 // nil, the profile is open to all accounts (everyone is allowed). 297 allowList *allowlist.List[int64] 298 // identifierTypes is a list of identifier types that may be issued under 299 // this profile. 300 identifierTypes []identifier.IdentifierType 301 } 302 303 // validationProfiles provides access to the set of configured profiles, 304 // including the default profile for orders/authzs which do not specify one. 305 type validationProfiles struct { 306 defaultName string 307 byName map[string]*validationProfile 308 } 309 310 // NewValidationProfiles builds a new validationProfiles struct from the given 311 // configs and default name. It enforces that the given authorization lifetimes 312 // are within the bounds mandated by the Baseline Requirements. 313 func NewValidationProfiles(defaultName string, configs map[string]*ValidationProfileConfig) (*validationProfiles, error) { 314 if defaultName == "" { 315 return nil, errors.New("default profile name must be configured") 316 } 317 318 profiles := make(map[string]*validationProfile, len(configs)) 319 320 for name, config := range configs { 321 // The Baseline Requirements v1.8.1 state that validation tokens "MUST 322 // NOT be used for more than 30 days from its creation". If unconfigured 323 // or the configured value pendingAuthorizationLifetimeDays is greater 324 // than 29 days, bail out. 325 if config.PendingAuthzLifetime.Duration <= 0 || config.PendingAuthzLifetime.Duration > 29*(24*time.Hour) { 326 return nil, fmt.Errorf("PendingAuthzLifetime value must be greater than 0 and less than 30d, but got %q", config.PendingAuthzLifetime.Duration) 327 } 328 329 // Baseline Requirements v1.8.1 section 4.2.1: "any reused data, document, 330 // or completed validation MUST be obtained no more than 398 days prior 331 // to issuing the Certificate". If unconfigured or the configured value is 332 // greater than 397 days, bail out. 333 if config.ValidAuthzLifetime.Duration <= 0 || config.ValidAuthzLifetime.Duration > 397*(24*time.Hour) { 334 return nil, fmt.Errorf("ValidAuthzLifetime value must be greater than 0 and less than 398d, but got %q", config.ValidAuthzLifetime.Duration) 335 } 336 337 if config.MaxNames <= 0 || config.MaxNames > 100 { 338 return nil, fmt.Errorf("MaxNames must be greater than 0 and at most 100") 339 } 340 341 var allowList *allowlist.List[int64] 342 if config.AllowList != "" { 343 data, err := os.ReadFile(config.AllowList) 344 if err != nil { 345 return nil, fmt.Errorf("reading allowlist: %w", err) 346 } 347 allowList, err = allowlist.NewFromYAML[int64](data) 348 if err != nil { 349 return nil, fmt.Errorf("parsing allowlist: %w", err) 350 } 351 } 352 353 profiles[name] = &validationProfile{ 354 pendingAuthzLifetime: config.PendingAuthzLifetime.Duration, 355 validAuthzLifetime: config.ValidAuthzLifetime.Duration, 356 orderLifetime: config.OrderLifetime.Duration, 357 maxNames: config.MaxNames, 358 allowList: allowList, 359 identifierTypes: config.IdentifierTypes, 360 } 361 } 362 363 _, ok := profiles[defaultName] 364 if !ok { 365 return nil, fmt.Errorf("no profile configured matching default profile name %q", defaultName) 366 } 367 368 return &validationProfiles{ 369 defaultName: defaultName, 370 byName: profiles, 371 }, nil 372 } 373 374 func (vp *validationProfiles) get(name string) (*validationProfile, error) { 375 if name == "" { 376 name = vp.defaultName 377 } 378 profile, ok := vp.byName[name] 379 if !ok { 380 return nil, berrors.InvalidProfileError("unrecognized profile name %q", name) 381 } 382 return profile, nil 383 } 384 385 // certificateRequestAuthz is a struct for holding information about a valid 386 // authz referenced during a certificateRequestEvent. It holds both the 387 // authorization ID and the challenge type that made the authorization valid. We 388 // specifically include the challenge type that solved the authorization to make 389 // some common analysis easier. 390 type certificateRequestAuthz struct { 391 ID string 392 ChallengeType core.AcmeChallenge 393 } 394 395 // certificateRequestEvent is a struct for holding information that is logged as 396 // JSON to the audit log as the result of an issuance event. 397 type certificateRequestEvent struct { 398 ID string `json:",omitempty"` 399 // Requester is the associated account ID 400 Requester int64 `json:",omitempty"` 401 // OrderID is the associated order ID (may be empty for an ACME v1 issuance) 402 OrderID int64 `json:",omitempty"` 403 // SerialNumber is the string representation of the issued certificate's 404 // serial number 405 SerialNumber string `json:",omitempty"` 406 // VerifiedFields are required by the baseline requirements and are always 407 // a static value for Boulder. 408 VerifiedFields []string `json:",omitempty"` 409 // CommonName is the subject common name from the issued cert 410 CommonName string `json:",omitempty"` 411 // Identifiers are the identifiers from the issued cert 412 Identifiers identifier.ACMEIdentifiers `json:",omitempty"` 413 // NotBefore is the starting timestamp of the issued cert's validity period 414 NotBefore time.Time 415 // NotAfter is the ending timestamp of the issued cert's validity period 416 NotAfter time.Time 417 // RequestTime and ResponseTime are for tracking elapsed time during issuance 418 RequestTime time.Time 419 ResponseTime time.Time 420 // Error contains any encountered errors 421 Error string `json:",omitempty"` 422 // Authorizations is a map of identifier names to certificateRequestAuthz 423 // objects. It can be used to understand how the names in a certificate 424 // request were authorized. 425 Authorizations map[string]certificateRequestAuthz 426 // CertProfileName is a human readable name used to refer to the certificate 427 // profile. 428 CertProfileName string `json:",omitempty"` 429 // CertProfileHash is SHA256 sum over every exported field of an 430 // issuance.ProfileConfig, represented here as a hexadecimal string. 431 CertProfileHash string `json:",omitempty"` 432 // PreviousCertificateIssued is present when this certificate uses the same set 433 // of FQDNs as a previous certificate (from any account) and contains the 434 // notBefore of the most recent such certificate. 435 PreviousCertificateIssued time.Time 436 // UserAgent is the User-Agent header from the ACME client (provided to the 437 // RA via gRPC metadata). 438 UserAgent string 439 } 440 441 // certificateRevocationEvent is a struct for holding information that is logged 442 // as JSON to the audit log as the result of a revocation event. 443 type certificateRevocationEvent struct { 444 ID string `json:",omitempty"` 445 // SerialNumber is the string representation of the revoked certificate's 446 // serial number. 447 SerialNumber string `json:",omitempty"` 448 // Reason is the integer representing the revocation reason used. 449 Reason revocation.Reason `json:"reason"` 450 // Method is the way in which revocation was requested. 451 // It will be one of the strings: "applicant", "subscriber", "control", "key", or "admin". 452 Method string `json:",omitempty"` 453 // RequesterID is the account ID of the requester. 454 // Will be zero for admin revocations. 455 RequesterID int64 `json:",omitempty"` 456 CRLShard int64 457 // AdminName is the name of the admin requester. 458 // Will be zero for subscriber revocations. 459 AdminName string `json:",omitempty"` 460 // Error contains any error encountered during revocation. 461 Error string `json:",omitempty"` 462 } 463 464 // finalizationCAACheckEvent is a struct for holding information logged as JSON 465 // to the info log as the result of an issuance event. It is logged when the RA 466 // performs the final CAA check of a certificate finalization request. 467 type finalizationCAACheckEvent struct { 468 // Requester is the associated account ID. 469 Requester int64 `json:",omitempty"` 470 // Reused is a count of Authz where the original CAA check was performed in 471 // the last 7 hours. 472 Reused int `json:",omitempty"` 473 // Rechecked is a count of Authz where a new CAA check was performed because 474 // the original check was older than 7 hours. 475 Rechecked int `json:",omitempty"` 476 } 477 478 // NewRegistration constructs a new Registration from a request. 479 func (ra *RegistrationAuthorityImpl) NewRegistration(ctx context.Context, request *corepb.Registration) (*corepb.Registration, error) { 480 // Error if the request is nil, there is no account key or IP address 481 if request == nil || len(request.Key) == 0 { 482 return nil, errIncompleteGRPCRequest 483 } 484 485 // Check if account key is acceptable for use. 486 var key jose.JSONWebKey 487 err := key.UnmarshalJSON(request.Key) 488 if err != nil { 489 return nil, berrors.InternalServerError("failed to unmarshal account key: %s", err.Error()) 490 } 491 err = ra.keyPolicy.GoodKey(ctx, key.Key) 492 if err != nil { 493 return nil, berrors.MalformedError("invalid public key: %s", err.Error()) 494 } 495 496 // Don't populate ID or CreatedAt because those will be set by the SA. 497 req := &corepb.Registration{ 498 Key: request.Key, 499 Agreement: request.Agreement, 500 Status: string(core.StatusValid), 501 } 502 503 // Store the registration object, then return the version that got stored. 504 res, err := ra.SA.NewRegistration(ctx, req) 505 if err != nil { 506 return nil, err 507 } 508 509 ra.newRegCounter.Inc() 510 return res, nil 511 } 512 513 // validateContacts checks the provided list of contacts, returning an error if 514 // any are not acceptable. Unacceptable contacts lists include: 515 // * An empty list 516 // * A list has more than maxContactsPerReg contacts 517 // * A list containing an empty contact 518 // * A list containing a contact that does not parse as a URL 519 // * A list containing a contact that has a URL scheme other than mailto 520 // * A list containing a mailto contact that contains hfields 521 // * A list containing a contact that has non-ascii characters 522 // * A list containing a contact that doesn't pass `policy.ValidEmail` 523 func (ra *RegistrationAuthorityImpl) validateContacts(contacts []string) error { 524 if len(contacts) == 0 { 525 return nil // Nothing to validate 526 } 527 if ra.maxContactsPerReg > 0 && len(contacts) > ra.maxContactsPerReg { 528 return berrors.MalformedError( 529 "too many contacts provided: %d > %d", 530 len(contacts), 531 ra.maxContactsPerReg, 532 ) 533 } 534 535 for _, contact := range contacts { 536 if contact == "" { 537 return berrors.InvalidEmailError("empty contact") 538 } 539 parsed, err := url.Parse(contact) 540 if err != nil { 541 return berrors.InvalidEmailError("unparsable contact") 542 } 543 if parsed.Scheme != "mailto" { 544 return berrors.UnsupportedContactError("only contact scheme 'mailto:' is supported") 545 } 546 if parsed.RawQuery != "" || contact[len(contact)-1] == '?' { 547 return berrors.InvalidEmailError("contact email contains a question mark") 548 } 549 if parsed.Fragment != "" || contact[len(contact)-1] == '#' { 550 return berrors.InvalidEmailError("contact email contains a '#'") 551 } 552 if !core.IsASCII(contact) { 553 return berrors.InvalidEmailError("contact email contains non-ASCII characters") 554 } 555 err = policy.ValidEmail(parsed.Opaque) 556 if err != nil { 557 return err 558 } 559 } 560 561 // NOTE(@cpu): For historical reasons (</3) we store ACME account contact 562 // information de-normalized in a fixed size `contact` field on the 563 // `registrations` table. At the time of writing this field is VARCHAR(191) 564 // That means the largest marshalled JSON value we can store is 191 bytes. 565 const maxContactBytes = 191 566 if jsonBytes, err := json.Marshal(contacts); err != nil { 567 return fmt.Errorf("failed to marshal reg.Contact to JSON: %w", err) 568 } else if len(jsonBytes) >= maxContactBytes { 569 return berrors.InvalidEmailError( 570 "too many/too long contact(s). Please use shorter or fewer email addresses") 571 } 572 573 return nil 574 } 575 576 // matchesCSR tests the contents of a generated certificate to make sure 577 // that the PublicKey, CommonName, and identifiers match those provided in 578 // the CSR that was used to generate the certificate. It also checks the 579 // following fields for: 580 // - notBefore is not more than 24 hours ago 581 // - BasicConstraintsValid is true 582 // - IsCA is false 583 // - ExtKeyUsage only contains ExtKeyUsageServerAuth & ExtKeyUsageClientAuth 584 // - Subject only contains CommonName & Names 585 func (ra *RegistrationAuthorityImpl) matchesCSR(parsedCertificate *x509.Certificate, csr *x509.CertificateRequest) error { 586 if !core.KeyDigestEquals(parsedCertificate.PublicKey, csr.PublicKey) { 587 return berrors.InternalServerError("generated certificate public key doesn't match CSR public key") 588 } 589 590 csrIdents := identifier.FromCSR(csr) 591 if parsedCertificate.Subject.CommonName != "" { 592 // Only check that the issued common name matches one of the SANs if there 593 // is an issued CN at all: this allows flexibility on whether we include 594 // the CN. 595 if !slices.Contains(csrIdents, identifier.NewDNS(parsedCertificate.Subject.CommonName)) { 596 return berrors.InternalServerError("generated certificate CommonName doesn't match any CSR name") 597 } 598 } 599 600 parsedIdents := identifier.FromCert(parsedCertificate) 601 if !slices.Equal(csrIdents, parsedIdents) { 602 return berrors.InternalServerError("generated certificate identifiers don't match CSR identifiers") 603 } 604 605 if !slices.Equal(parsedCertificate.EmailAddresses, csr.EmailAddresses) { 606 return berrors.InternalServerError("generated certificate EmailAddresses don't match CSR EmailAddresses") 607 } 608 609 if !slices.Equal(parsedCertificate.URIs, csr.URIs) { 610 return berrors.InternalServerError("generated certificate URIs don't match CSR URIs") 611 } 612 613 if len(parsedCertificate.Subject.Country) > 0 || len(parsedCertificate.Subject.Organization) > 0 || 614 len(parsedCertificate.Subject.OrganizationalUnit) > 0 || len(parsedCertificate.Subject.Locality) > 0 || 615 len(parsedCertificate.Subject.Province) > 0 || len(parsedCertificate.Subject.StreetAddress) > 0 || 616 len(parsedCertificate.Subject.PostalCode) > 0 { 617 return berrors.InternalServerError("generated certificate Subject contains fields other than CommonName, or SerialNumber") 618 } 619 now := ra.clk.Now() 620 if now.Sub(parsedCertificate.NotBefore) > time.Hour*24 { 621 return berrors.InternalServerError("generated certificate is back dated %s", now.Sub(parsedCertificate.NotBefore)) 622 } 623 if !parsedCertificate.BasicConstraintsValid { 624 return berrors.InternalServerError("generated certificate doesn't have basic constraints set") 625 } 626 if parsedCertificate.IsCA { 627 return berrors.InternalServerError("generated certificate can sign other certificates") 628 } 629 for _, eku := range parsedCertificate.ExtKeyUsage { 630 if eku != x509.ExtKeyUsageServerAuth && eku != x509.ExtKeyUsageClientAuth { 631 return berrors.InternalServerError("generated certificate has unacceptable EKU") 632 } 633 } 634 if !slices.Contains(parsedCertificate.ExtKeyUsage, x509.ExtKeyUsageServerAuth) { 635 return berrors.InternalServerError("generated certificate doesn't have serverAuth EKU") 636 } 637 638 return nil 639 } 640 641 // checkOrderAuthorizations verifies that a provided set of names associated 642 // with a specific order and account has all of the required valid, unexpired 643 // authorizations to proceed with issuance. It returns the authorizations that 644 // satisfied the set of names or it returns an error. If it returns an error, it 645 // will be of type BoulderError. 646 func (ra *RegistrationAuthorityImpl) checkOrderAuthorizations( 647 ctx context.Context, 648 orderID orderID, 649 acctID accountID, 650 idents identifier.ACMEIdentifiers, 651 now time.Time) (map[identifier.ACMEIdentifier]*core.Authorization, error) { 652 // Get all of the valid authorizations for this account/order 653 req := &sapb.GetValidOrderAuthorizationsRequest{ 654 Id: int64(orderID), 655 AcctID: int64(acctID), 656 } 657 authzMapPB, err := ra.SA.GetValidOrderAuthorizations2(ctx, req) 658 if err != nil { 659 return nil, berrors.InternalServerError("error in GetValidOrderAuthorizations: %s", err) 660 } 661 authzs, err := bgrpc.PBToAuthzMap(authzMapPB) 662 if err != nil { 663 return nil, err 664 } 665 666 // Ensure that every identifier has a matching authz, and vice-versa. 667 var missing []string 668 var invalid []string 669 var expired []string 670 for _, ident := range idents { 671 authz, ok := authzs[ident] 672 if !ok || authz == nil { 673 missing = append(missing, ident.Value) 674 continue 675 } 676 if authz.Status != core.StatusValid { 677 invalid = append(invalid, ident.Value) 678 continue 679 } 680 if authz.Expires.Before(now) { 681 expired = append(expired, ident.Value) 682 continue 683 } 684 err = ra.PA.CheckAuthzChallenges(authz) 685 if err != nil { 686 invalid = append(invalid, ident.Value) 687 continue 688 } 689 } 690 691 if len(missing) > 0 { 692 return nil, berrors.UnauthorizedError( 693 "authorizations for these identifiers not found: %s", 694 strings.Join(missing, ", "), 695 ) 696 } 697 698 if len(invalid) > 0 { 699 return nil, berrors.UnauthorizedError( 700 "authorizations for these identifiers not valid: %s", 701 strings.Join(invalid, ", "), 702 ) 703 } 704 if len(expired) > 0 { 705 return nil, berrors.UnauthorizedError( 706 "authorizations for these identifiers expired: %s", 707 strings.Join(expired, ", "), 708 ) 709 } 710 711 // Even though this check is cheap, we do it after the more specific checks 712 // so that we can return more specific error messages. 713 if len(idents) != len(authzs) { 714 return nil, berrors.UnauthorizedError("incorrect number of identifiers requested for finalization") 715 } 716 717 // Check that the authzs either don't need CAA rechecking, or do the 718 // necessary CAA rechecks right now. 719 err = ra.checkAuthorizationsCAA(ctx, int64(acctID), authzs, now) 720 if err != nil { 721 return nil, err 722 } 723 724 return authzs, nil 725 } 726 727 // validatedBefore checks if a given authorization's challenge was 728 // validated before a given time. Returns a bool. 729 func validatedBefore(authz *core.Authorization, caaRecheckTime time.Time) (bool, error) { 730 numChallenges := len(authz.Challenges) 731 if numChallenges != 1 { 732 return false, berrors.InternalServerError("authorization has incorrect number of challenges. 1 expected, %d found for: id %s", numChallenges, authz.ID) 733 } 734 if authz.Challenges[0].Validated == nil { 735 return false, berrors.InternalServerError("authorization's challenge has no validated timestamp for: id %s", authz.ID) 736 } 737 return authz.Challenges[0].Validated.Before(caaRecheckTime), nil 738 } 739 740 // checkAuthorizationsCAA ensures that we have sufficiently-recent CAA checks 741 // for every input identifier/authz. If any authz was validated too long ago, it 742 // kicks off a CAA recheck for that identifier If it returns an error, it will 743 // be of type BoulderError. 744 func (ra *RegistrationAuthorityImpl) checkAuthorizationsCAA( 745 ctx context.Context, 746 acctID int64, 747 authzs map[identifier.ACMEIdentifier]*core.Authorization, 748 now time.Time) error { 749 // recheckAuthzs is a list of authorizations that must have their CAA records rechecked 750 var recheckAuthzs []*core.Authorization 751 752 // Per Baseline Requirements, CAA must be checked within 8 hours of 753 // issuance. CAA is checked when an authorization is validated, so as 754 // long as that was less than 8 hours ago, we're fine. We recheck if 755 // that was more than 7 hours ago, to be on the safe side. We can 756 // check to see if the authorized challenge `AttemptedAt` 757 // (`Validated`) value from the database is before our caaRecheckTime. 758 // Set the recheck time to 7 hours ago. 759 caaRecheckAfter := now.Add(caaRecheckDuration) 760 761 for _, authz := range authzs { 762 if staleCAA, err := validatedBefore(authz, caaRecheckAfter); err != nil { 763 return err 764 } else if staleCAA { 765 switch authz.Identifier.Type { 766 case identifier.TypeDNS: 767 // Ensure that CAA is rechecked for this name 768 recheckAuthzs = append(recheckAuthzs, authz) 769 case identifier.TypeIP: 770 default: 771 return berrors.MalformedError("invalid identifier type: %s", authz.Identifier.Type) 772 } 773 } 774 } 775 776 if len(recheckAuthzs) > 0 { 777 err := ra.recheckCAA(ctx, recheckAuthzs) 778 if err != nil { 779 return err 780 } 781 } 782 783 caaEvent := &finalizationCAACheckEvent{ 784 Requester: acctID, 785 Reused: len(authzs) - len(recheckAuthzs), 786 Rechecked: len(recheckAuthzs), 787 } 788 ra.log.InfoObject("FinalizationCaaCheck", caaEvent) 789 790 return nil 791 } 792 793 // recheckCAA accepts a list of names that need to have their CAA records 794 // rechecked because their associated authorizations are sufficiently old and 795 // performs the CAA checks required for each. If any of the rechecks fail an 796 // error is returned. 797 func (ra *RegistrationAuthorityImpl) recheckCAA(ctx context.Context, authzs []*core.Authorization) error { 798 ra.recheckCAACounter.Add(float64(len(authzs))) 799 800 type authzCAAResult struct { 801 authz *core.Authorization 802 err error 803 } 804 ch := make(chan authzCAAResult, len(authzs)) 805 for _, authz := range authzs { 806 go func(authz *core.Authorization) { 807 // If an authorization has multiple valid challenges, 808 // the type of the first valid challenge is used for 809 // the purposes of CAA rechecking. 810 var method string 811 for _, challenge := range authz.Challenges { 812 if challenge.Status == core.StatusValid { 813 method = string(challenge.Type) 814 break 815 } 816 } 817 if method == "" { 818 ch <- authzCAAResult{ 819 authz: authz, 820 err: berrors.InternalServerError( 821 "Internal error determining validation method for authorization ID %v (%v)", 822 authz.ID, authz.Identifier.Value), 823 } 824 return 825 } 826 var resp *vapb.IsCAAValidResponse 827 var err error 828 resp, err = ra.VA.DoCAA(ctx, &vapb.IsCAAValidRequest{ 829 Identifier: authz.Identifier.ToProto(), 830 ValidationMethod: method, 831 AccountURIID: authz.RegistrationID, 832 }) 833 if err != nil { 834 ra.log.AuditErrf("Rechecking CAA: %s", err) 835 err = berrors.InternalServerError( 836 "Internal error rechecking CAA for authorization ID %v (%v)", 837 authz.ID, authz.Identifier.Value, 838 ) 839 } else if resp.Problem != nil { 840 err = berrors.CAAError("rechecking caa: %s", resp.Problem.Detail) 841 } 842 ch <- authzCAAResult{ 843 authz: authz, 844 err: err, 845 } 846 }(authz) 847 } 848 var subErrors []berrors.SubBoulderError 849 // Read a recheckResult for each authz from the results channel 850 for range len(authzs) { 851 recheckResult := <-ch 852 // If the result had a CAA boulder error, construct a suberror with the 853 // identifier from the authorization that was checked. 854 err := recheckResult.err 855 if err != nil { 856 var bErr *berrors.BoulderError 857 if errors.As(err, &bErr) && bErr.Type == berrors.CAA { 858 subErrors = append(subErrors, berrors.SubBoulderError{ 859 Identifier: recheckResult.authz.Identifier, 860 BoulderError: bErr}) 861 } else { 862 return err 863 } 864 } 865 } 866 if len(subErrors) > 0 { 867 var detail string 868 // If there was only one error, then use it as the top level error that is 869 // returned. 870 if len(subErrors) == 1 { 871 return subErrors[0].BoulderError 872 } 873 detail = fmt.Sprintf( 874 "Rechecking CAA for %q and %d more identifiers failed. "+ 875 "Refer to sub-problems for more information", 876 subErrors[0].Identifier.Value, 877 len(subErrors)-1) 878 return (&berrors.BoulderError{ 879 Type: berrors.CAA, 880 Detail: detail, 881 }).WithSubErrors(subErrors) 882 } 883 return nil 884 } 885 886 // failOrder marks an order as failed by setting the problem details field of 887 // the order & persisting it through the SA. If an error occurs doing this we 888 // log it and don't modify the input order. There aren't any alternatives if we 889 // can't add the error to the order. This function MUST only be called when we 890 // are already returning an error for another reason. 891 func (ra *RegistrationAuthorityImpl) failOrder( 892 ctx context.Context, 893 order *corepb.Order, 894 prob *probs.ProblemDetails) { 895 // Use a separate context with its own timeout, since the error we encountered 896 // may have been a context cancellation or timeout, and these operations still 897 // need to succeed. 898 ctx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 1*time.Second) 899 defer cancel() 900 901 // Convert the problem to a protobuf problem for the *corepb.Order field 902 pbProb, err := bgrpc.ProblemDetailsToPB(prob) 903 if err != nil { 904 ra.log.AuditErrf("Could not convert order error problem to PB: %q", err) 905 return 906 } 907 908 // Assign the protobuf problem to the field and save it via the SA 909 order.Error = pbProb 910 _, err = ra.SA.SetOrderError(ctx, &sapb.SetOrderErrorRequest{ 911 Id: order.Id, 912 Error: order.Error, 913 }) 914 if err != nil { 915 ra.log.AuditErrf("Could not persist order error: %q", err) 916 } 917 } 918 919 // To help minimize the chance that an accountID would be used as an order ID 920 // (or vice versa) when calling functions that use both we define internal 921 // `accountID` and `orderID` types so that callers must explicitly cast. 922 type accountID int64 923 type orderID int64 924 925 // FinalizeOrder accepts a request to finalize an order object and, if possible, 926 // issues a certificate to satisfy the order. If an order does not have valid, 927 // unexpired authorizations for all of its associated names an error is 928 // returned. Similarly we vet that all of the names in the order are acceptable 929 // based on current policy and return an error if the order can't be fulfilled. 930 // If successful the order will be returned in processing status for the client 931 // to poll while awaiting finalization to occur. 932 func (ra *RegistrationAuthorityImpl) FinalizeOrder(ctx context.Context, req *rapb.FinalizeOrderRequest) (*corepb.Order, error) { 933 // Step 1: Set up logging/tracing and validate the Order 934 if req == nil || req.Order == nil || len(req.Csr) == 0 { 935 return nil, errIncompleteGRPCRequest 936 } 937 938 logEvent := certificateRequestEvent{ 939 ID: core.NewToken(), 940 OrderID: req.Order.Id, 941 Requester: req.Order.RegistrationID, 942 RequestTime: ra.clk.Now(), 943 UserAgent: web.UserAgent(ctx), 944 } 945 csr, err := ra.validateFinalizeRequest(ctx, req, &logEvent) 946 if err != nil { 947 return nil, err 948 } 949 950 // Observe the age of this order, so we know how quickly most clients complete 951 // issuance flows. 952 ra.orderAges.WithLabelValues("FinalizeOrder").Observe(ra.clk.Since(req.Order.Created.AsTime()).Seconds()) 953 954 // Step 2: Set the Order to Processing status 955 // 956 // We do this separately from the issuance process itself so that, when we 957 // switch to doing issuance asynchronously, we aren't lying to the client 958 // when we say that their order is already Processing. 959 // 960 // NOTE(@cpu): After this point any errors that are encountered must update 961 // the state of the order to invalid by setting the order's error field. 962 // Otherwise the order will be "stuck" in processing state. It can not be 963 // finalized because it isn't pending, but we aren't going to process it 964 // further because we already did and encountered an error. 965 _, err = ra.SA.SetOrderProcessing(ctx, &sapb.OrderRequest{Id: req.Order.Id}) 966 if err != nil { 967 // Fail the order with a server internal error - we weren't able to set the 968 // status to processing and that's unexpected & weird. 969 ra.failOrder(ctx, req.Order, probs.ServerInternal("Error setting order processing")) 970 return nil, err 971 } 972 973 // Update the order status locally since the SA doesn't return the updated 974 // order itself after setting the status 975 order := req.Order 976 order.Status = string(core.StatusProcessing) 977 978 // Steps 3 (issuance) and 4 (cleanup) are done inside a helper function so 979 // that we can control whether or not that work happens asynchronously. 980 if features.Get().AsyncFinalize { 981 // We do this work in a goroutine so that we can better handle latency from 982 // getting SCTs and writing the (pre)certificate to the database. This lets 983 // us return the order in the Processing state to the client immediately, 984 // prompting them to poll the Order object and wait for it to be put into 985 // its final state. 986 // 987 // We track this goroutine's lifetime in a waitgroup global to this RA, so 988 // that it can wait for all goroutines to drain during shutdown. 989 ra.drainWG.Go(func() { 990 // The original context will be canceled in the RPC layer when FinalizeOrder returns, 991 // so split off a context that won't be canceled (and has its own timeout). 992 ctx, cancel := context.WithTimeout(context.WithoutCancel(ctx), ra.finalizeTimeout) 993 defer cancel() 994 _, err := ra.issueCertificateOuter(ctx, proto.Clone(order).(*corepb.Order), csr, logEvent) 995 if err != nil { 996 // We only log here, because this is in a background goroutine with 997 // no parent goroutine waiting for it to receive the error. 998 ra.log.AuditErrf("Asynchronous finalization failed: %s", err.Error()) 999 } 1000 }) 1001 return order, nil 1002 } else { 1003 return ra.issueCertificateOuter(ctx, order, csr, logEvent) 1004 } 1005 } 1006 1007 // containsMustStaple returns true if the provided set of extensions includes 1008 // an entry whose OID and value both match the expected values for the OCSP 1009 // Must-Staple (a.k.a. id-pe-tlsFeature) extension. 1010 func containsMustStaple(extensions []pkix.Extension) bool { 1011 // RFC 7633: id-pe-tlsfeature OBJECT IDENTIFIER ::= { id-pe 24 } 1012 var mustStapleExtId = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 24} 1013 // ASN.1 encoding of: 1014 // SEQUENCE 1015 // INTEGER 5 1016 // where "5" is the status_request feature (RFC 6066) 1017 var mustStapleExtValue = []byte{0x30, 0x03, 0x02, 0x01, 0x05} 1018 1019 for _, ext := range extensions { 1020 if ext.Id.Equal(mustStapleExtId) && bytes.Equal(ext.Value, mustStapleExtValue) { 1021 return true 1022 } 1023 } 1024 return false 1025 } 1026 1027 // validateFinalizeRequest checks that a FinalizeOrder request is fully correct 1028 // and ready for issuance. 1029 func (ra *RegistrationAuthorityImpl) validateFinalizeRequest( 1030 ctx context.Context, 1031 req *rapb.FinalizeOrderRequest, 1032 logEvent *certificateRequestEvent) (*x509.CertificateRequest, error) { 1033 if req.Order.Id <= 0 { 1034 return nil, berrors.MalformedError("invalid order ID: %d", req.Order.Id) 1035 } 1036 1037 if req.Order.RegistrationID <= 0 { 1038 return nil, berrors.MalformedError("invalid account ID: %d", req.Order.RegistrationID) 1039 } 1040 1041 if core.AcmeStatus(req.Order.Status) != core.StatusReady { 1042 return nil, berrors.OrderNotReadyError( 1043 "Order's status (%q) is not acceptable for finalization", 1044 req.Order.Status) 1045 } 1046 1047 profile, err := ra.profiles.get(req.Order.CertificateProfileName) 1048 if err != nil { 1049 return nil, err 1050 } 1051 1052 orderIdents := identifier.Normalize(identifier.FromProtoSlice(req.Order.Identifiers)) 1053 1054 // There should never be an order with 0 identifiers at the stage, but we check to 1055 // be on the safe side, throwing an internal server error if this assumption 1056 // is ever violated. 1057 if len(orderIdents) == 0 { 1058 return nil, berrors.InternalServerError("Order has no associated identifiers") 1059 } 1060 1061 // Parse the CSR from the request 1062 csr, err := x509.ParseCertificateRequest(req.Csr) 1063 if err != nil { 1064 return nil, berrors.BadCSRError("unable to parse CSR: %s", err.Error()) 1065 } 1066 1067 if containsMustStaple(csr.Extensions) { 1068 return nil, berrors.UnauthorizedError( 1069 "OCSP must-staple extension is no longer available: see https://letsencrypt.org/2024/12/05/ending-ocsp", 1070 ) 1071 } 1072 1073 err = csrlib.VerifyCSR(ctx, csr, profile.maxNames, &ra.keyPolicy, ra.PA) 1074 if err != nil { 1075 // VerifyCSR returns berror instances that can be passed through as-is 1076 // without wrapping. 1077 return nil, err 1078 } 1079 1080 // Dedupe, lowercase and sort both the names from the CSR and the names in the 1081 // order. 1082 csrIdents := identifier.FromCSR(csr) 1083 // Check that the order names and the CSR names are an exact match 1084 if !slices.Equal(csrIdents, orderIdents) { 1085 return nil, berrors.UnauthorizedError("CSR does not specify same identifiers as Order") 1086 } 1087 1088 // Get the originating account for use in the next check. 1089 regPB, err := ra.SA.GetRegistration(ctx, &sapb.RegistrationID{Id: req.Order.RegistrationID}) 1090 if err != nil { 1091 return nil, err 1092 } 1093 1094 account, err := bgrpc.PbToRegistration(regPB) 1095 if err != nil { 1096 return nil, err 1097 } 1098 1099 // Make sure they're not using their account key as the certificate key too. 1100 if core.KeyDigestEquals(csr.PublicKey, account.Key) { 1101 return nil, berrors.MalformedError("certificate public key must be different than account key") 1102 } 1103 1104 // Double-check that all authorizations on this order are valid, are also 1105 // associated with the same account as the order itself, and have recent CAA. 1106 authzs, err := ra.checkOrderAuthorizations( 1107 ctx, orderID(req.Order.Id), accountID(req.Order.RegistrationID), csrIdents, ra.clk.Now()) 1108 if err != nil { 1109 // Pass through the error without wrapping it because the called functions 1110 // return BoulderError and we don't want to lose the type. 1111 return nil, err 1112 } 1113 1114 // Collect up a certificateRequestAuthz that stores the ID and challenge type 1115 // of each of the valid authorizations we used for this issuance. 1116 logEventAuthzs := make(map[string]certificateRequestAuthz, len(csrIdents)) 1117 for _, authz := range authzs { 1118 // No need to check for error here because we know this same call just 1119 // succeeded inside ra.checkOrderAuthorizations 1120 solvedByChallengeType, _ := authz.SolvedBy() 1121 logEventAuthzs[authz.Identifier.Value] = certificateRequestAuthz{ 1122 ID: authz.ID, 1123 ChallengeType: solvedByChallengeType, 1124 } 1125 authzAge := (profile.validAuthzLifetime - authz.Expires.Sub(ra.clk.Now())).Seconds() 1126 ra.authzAges.WithLabelValues("FinalizeOrder", string(authz.Status)).Observe(authzAge) 1127 } 1128 logEvent.Authorizations = logEventAuthzs 1129 1130 // Mark that we verified the CN and SANs 1131 logEvent.VerifiedFields = []string{"subject.commonName", "subjectAltName"} 1132 1133 return csr, nil 1134 } 1135 1136 func (ra *RegistrationAuthorityImpl) GetSCTs(ctx context.Context, sctRequest *rapb.SCTRequest) (*rapb.SCTResponse, error) { 1137 scts, err := ra.getSCTs(ctx, sctRequest.PrecertDER) 1138 if err != nil { 1139 return nil, err 1140 } 1141 return &rapb.SCTResponse{ 1142 SctDER: scts, 1143 }, nil 1144 } 1145 1146 // issueCertificateOuter exists solely to ensure that all calls to 1147 // issueCertificateInner have their result handled uniformly, no matter what 1148 // return path that inner function takes. It takes ownership of the logEvent, 1149 // mutates it, and is responsible for outputting its final state. 1150 func (ra *RegistrationAuthorityImpl) issueCertificateOuter( 1151 ctx context.Context, 1152 order *corepb.Order, 1153 csr *x509.CertificateRequest, 1154 logEvent certificateRequestEvent, 1155 ) (*corepb.Order, error) { 1156 ra.inflightFinalizes.Inc() 1157 defer ra.inflightFinalizes.Dec() 1158 1159 idents := identifier.FromProtoSlice(order.Identifiers) 1160 1161 isRenewal := false 1162 timestamps, err := ra.SA.FQDNSetTimestampsForWindow(ctx, &sapb.CountFQDNSetsRequest{ 1163 Identifiers: idents.ToProtoSlice(), 1164 Window: durationpb.New(120 * 24 * time.Hour), 1165 Limit: 1, 1166 }) 1167 if err != nil { 1168 return nil, fmt.Errorf("checking if certificate is a renewal: %w", err) 1169 } 1170 if len(timestamps.Timestamps) > 0 { 1171 isRenewal = true 1172 logEvent.PreviousCertificateIssued = timestamps.Timestamps[0].AsTime() 1173 } 1174 1175 profileName := order.CertificateProfileName 1176 if profileName == "" { 1177 profileName = ra.profiles.defaultName 1178 } 1179 1180 // Step 3: Issue the Certificate 1181 cert, err := ra.issueCertificateInner( 1182 ctx, csr, isRenewal, profileName, accountID(order.RegistrationID), orderID(order.Id)) 1183 1184 // Step 4: Fail the order if necessary, and update metrics and log fields 1185 var result string 1186 if err != nil { 1187 // The problem is computed using `web.ProblemDetailsForError`, the same 1188 // function the WFE uses to convert between `berrors` and problems. This 1189 // will turn normal expected berrors like berrors.UnauthorizedError into the 1190 // correct `urn:ietf:params:acme:error:unauthorized` problem while not 1191 // letting anything like a server internal error through with sensitive 1192 // info. 1193 ra.failOrder(ctx, order, web.ProblemDetailsForError(err, "Error finalizing order")) 1194 order.Status = string(core.StatusInvalid) 1195 1196 logEvent.Error = err.Error() 1197 result = "error" 1198 } else { 1199 order.CertificateSerial = core.SerialToString(cert.SerialNumber) 1200 order.Status = string(core.StatusValid) 1201 1202 ra.namesPerCert.With( 1203 prometheus.Labels{"type": "issued"}, 1204 ).Observe(float64(len(idents))) 1205 1206 ra.newCertCounter.Inc() 1207 1208 logEvent.SerialNumber = core.SerialToString(cert.SerialNumber) 1209 logEvent.CommonName = cert.Subject.CommonName 1210 logEvent.Identifiers = identifier.FromCert(cert) 1211 logEvent.NotBefore = cert.NotBefore 1212 logEvent.NotAfter = cert.NotAfter 1213 logEvent.CertProfileName = profileName 1214 1215 result = "successful" 1216 } 1217 1218 logEvent.ResponseTime = ra.clk.Now() 1219 ra.log.AuditObject(fmt.Sprintf("Certificate request - %s", result), logEvent) 1220 1221 return order, err 1222 } 1223 1224 // countCertificateIssued increments the certificates (per domain and per 1225 // account) and duplicate certificate rate limits. There is no reason to surface 1226 // errors from this function to the Subscriber, spends against these limit are 1227 // best effort. 1228 func (ra *RegistrationAuthorityImpl) countCertificateIssued(ctx context.Context, regId int64, orderIdents identifier.ACMEIdentifiers, isRenewal bool) { 1229 var transactions []ratelimits.Transaction 1230 if !isRenewal { 1231 txns, err := ra.txnBuilder.CertificatesPerDomainSpendOnlyTransactions(regId, orderIdents) 1232 if err != nil { 1233 ra.log.Warningf("building rate limit transactions at finalize: %s", err) 1234 } 1235 transactions = append(transactions, txns...) 1236 } 1237 1238 txn, err := ra.txnBuilder.CertificatesPerFQDNSetSpendOnlyTransaction(orderIdents) 1239 if err != nil { 1240 ra.log.Warningf("building rate limit transaction at finalize: %s", err) 1241 } 1242 transactions = append(transactions, txn) 1243 1244 _, err = ra.limiter.BatchSpend(ctx, transactions) 1245 if err != nil { 1246 if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) { 1247 return 1248 } 1249 ra.log.Warningf("spending against rate limits at finalize: %s", err) 1250 } 1251 } 1252 1253 // issueCertificateInner is part of the [issuance cycle]. 1254 // 1255 // It gets a precertificate from the CA, submits it to CT logs to get SCTs, 1256 // then sends the precertificate and the SCTs to the CA to get a final certificate. 1257 // 1258 // This function is responsible for ensuring that we never try to issue a final 1259 // certificate twice for the same precertificate, because that has the potential 1260 // to create certificates with duplicate serials. For instance, this could 1261 // happen if final certificates were created with different sets of SCTs. This 1262 // function accomplishes that by bailing on issuance if there is any error in 1263 // IssueCertificateForPrecertificate; there are no retries, and serials are 1264 // generated in IssuePrecertificate, so serials with errors are dropped and 1265 // never have final certificates issued for them (because there is a possibility 1266 // that the certificate was actually issued but there was an error returning 1267 // it). 1268 // 1269 // [issuance cycle]: https://github.com/letsencrypt/boulder/blob/main/docs/ISSUANCE-CYCLE.md 1270 func (ra *RegistrationAuthorityImpl) issueCertificateInner( 1271 ctx context.Context, 1272 csr *x509.CertificateRequest, 1273 isRenewal bool, 1274 profileName string, 1275 acctID accountID, 1276 oID orderID) (*x509.Certificate, error) { 1277 // wrapError adds a prefix to an error. If the error is a boulder error then 1278 // the problem detail is updated with the prefix. Otherwise a new error is 1279 // returned with the message prefixed using `fmt.Errorf` 1280 wrapError := func(e error, prefix string) error { 1281 if berr, ok := e.(*berrors.BoulderError); ok { 1282 berr.Detail = fmt.Sprintf("%s: %s", prefix, berr.Detail) 1283 return berr 1284 } 1285 return fmt.Errorf("%s: %s", prefix, e) 1286 } 1287 1288 issueReq := &capb.IssueCertificateRequest{ 1289 Csr: csr.Raw, 1290 RegistrationID: int64(acctID), 1291 OrderID: int64(oID), 1292 CertProfileName: profileName, 1293 } 1294 1295 resp, err := ra.CA.IssueCertificate(ctx, issueReq) 1296 if err != nil { 1297 return nil, err 1298 } 1299 1300 parsedCertificate, err := x509.ParseCertificate(resp.DER) 1301 if err != nil { 1302 return nil, wrapError(err, "parsing final certificate") 1303 } 1304 1305 ra.countCertificateIssued(ctx, int64(acctID), identifier.FromCert(parsedCertificate), isRenewal) 1306 1307 // Asynchronously submit the final certificate to any configured logs 1308 go ra.ctpolicy.SubmitFinalCert(resp.DER, parsedCertificate.NotAfter) 1309 1310 err = ra.matchesCSR(parsedCertificate, csr) 1311 if err != nil { 1312 ra.certCSRMismatch.Inc() 1313 return nil, err 1314 } 1315 1316 _, err = ra.SA.FinalizeOrder(ctx, &sapb.FinalizeOrderRequest{ 1317 Id: int64(oID), 1318 CertificateSerial: core.SerialToString(parsedCertificate.SerialNumber), 1319 }) 1320 if err != nil { 1321 return nil, wrapError(err, "persisting finalized order") 1322 } 1323 1324 return parsedCertificate, nil 1325 } 1326 1327 func (ra *RegistrationAuthorityImpl) getSCTs(ctx context.Context, precertDER []byte) (core.SCTDERs, error) { 1328 started := ra.clk.Now() 1329 precert, err := x509.ParseCertificate(precertDER) 1330 if err != nil { 1331 return nil, fmt.Errorf("parsing precertificate: %w", err) 1332 } 1333 1334 scts, err := ra.ctpolicy.GetSCTs(ctx, precertDER, precert.NotAfter) 1335 took := ra.clk.Since(started) 1336 if err != nil { 1337 state := "failure" 1338 if err == context.DeadlineExceeded { 1339 state = "deadlineExceeded" 1340 // Convert the error to a missingSCTsError to communicate the timeout, 1341 // otherwise it will be a generic serverInternalError 1342 err = berrors.MissingSCTsError("failed to get SCTs: %s", err.Error()) 1343 } 1344 ra.log.Warningf("ctpolicy.GetSCTs failed: %s", err) 1345 ra.ctpolicyResults.With(prometheus.Labels{"result": state}).Observe(took.Seconds()) 1346 return nil, err 1347 } 1348 ra.ctpolicyResults.With(prometheus.Labels{"result": "success"}).Observe(took.Seconds()) 1349 return scts, nil 1350 } 1351 1352 // UpdateRegistrationKey updates an existing Registration's key. 1353 func (ra *RegistrationAuthorityImpl) UpdateRegistrationKey(ctx context.Context, req *rapb.UpdateRegistrationKeyRequest) (*corepb.Registration, error) { 1354 if core.IsAnyNilOrZero(req.RegistrationID, req.Jwk) { 1355 return nil, errIncompleteGRPCRequest 1356 } 1357 1358 update, err := ra.SA.UpdateRegistrationKey(ctx, &sapb.UpdateRegistrationKeyRequest{ 1359 RegistrationID: req.RegistrationID, 1360 Jwk: req.Jwk, 1361 }) 1362 if err != nil { 1363 return nil, fmt.Errorf("failed to update registration key: %w", err) 1364 } 1365 1366 return update, nil 1367 } 1368 1369 // recordValidation records an authorization validation event, 1370 // it should only be used on v2 style authorizations. 1371 func (ra *RegistrationAuthorityImpl) recordValidation(ctx context.Context, authID string, authExpires time.Time, challenge *core.Challenge) error { 1372 authzID, err := strconv.ParseInt(authID, 10, 64) 1373 if err != nil { 1374 return err 1375 } 1376 vr, err := bgrpc.ValidationResultToPB(challenge.ValidationRecord, challenge.Error, "", "") 1377 if err != nil { 1378 return err 1379 } 1380 var validated *timestamppb.Timestamp 1381 if challenge.Validated != nil { 1382 validated = timestamppb.New(*challenge.Validated) 1383 } 1384 _, err = ra.SA.FinalizeAuthorization2(ctx, &sapb.FinalizeAuthorizationRequest{ 1385 Id: authzID, 1386 Status: string(challenge.Status), 1387 Expires: timestamppb.New(authExpires), 1388 Attempted: string(challenge.Type), 1389 AttemptedAt: validated, 1390 ValidationRecords: vr.Records, 1391 ValidationError: vr.Problem, 1392 }) 1393 return err 1394 } 1395 1396 // countFailedValidations increments the FailedAuthorizationsPerDomainPerAccount limit. 1397 // and the FailedAuthorizationsForPausingPerDomainPerAccountTransaction limit. 1398 func (ra *RegistrationAuthorityImpl) countFailedValidations(ctx context.Context, regId int64, ident identifier.ACMEIdentifier) error { 1399 txn, err := ra.txnBuilder.FailedAuthorizationsPerDomainPerAccountSpendOnlyTransaction(regId, ident) 1400 if err != nil { 1401 return fmt.Errorf("building rate limit transaction for the %s rate limit: %w", ratelimits.FailedAuthorizationsPerDomainPerAccount, err) 1402 } 1403 1404 _, err = ra.limiter.Spend(ctx, txn) 1405 if err != nil { 1406 return fmt.Errorf("spending against the %s rate limit: %w", ratelimits.FailedAuthorizationsPerDomainPerAccount, err) 1407 } 1408 1409 if features.Get().AutomaticallyPauseZombieClients { 1410 txn, err = ra.txnBuilder.FailedAuthorizationsForPausingPerDomainPerAccountTransaction(regId, ident) 1411 if err != nil { 1412 return fmt.Errorf("building rate limit transaction for the %s rate limit: %w", ratelimits.FailedAuthorizationsForPausingPerDomainPerAccount, err) 1413 } 1414 1415 decision, err := ra.limiter.Spend(ctx, txn) 1416 if err != nil { 1417 return fmt.Errorf("spending against the %s rate limit: %s", ratelimits.FailedAuthorizationsForPausingPerDomainPerAccount, err) 1418 } 1419 1420 if decision.Result(ra.clk.Now()) != nil { 1421 resp, err := ra.SA.PauseIdentifiers(ctx, &sapb.PauseRequest{ 1422 RegistrationID: regId, 1423 Identifiers: []*corepb.Identifier{ident.ToProto()}, 1424 }) 1425 if err != nil { 1426 return fmt.Errorf("failed to pause %d/%q: %w", regId, ident.Value, err) 1427 } 1428 ra.pauseCounter.With(prometheus.Labels{ 1429 "paused": strconv.FormatBool(resp.Paused > 0), 1430 "repaused": strconv.FormatBool(resp.Repaused > 0), 1431 "grace": strconv.FormatBool(resp.Paused <= 0 && resp.Repaused <= 0), 1432 }).Inc() 1433 } 1434 } 1435 return nil 1436 } 1437 1438 // resetAccountPausingLimit resets bucket to maximum capacity for given account. 1439 // There is no reason to surface errors from this function to the Subscriber. 1440 func (ra *RegistrationAuthorityImpl) resetAccountPausingLimit(ctx context.Context, regId int64, ident identifier.ACMEIdentifier) { 1441 txns, err := ra.txnBuilder.NewPausingResetTransactions(regId, ident) 1442 if err != nil { 1443 ra.log.Warningf("building reset transaction for regID=[%d] identifier=[%s]: %s", regId, ident.Value, err) 1444 return 1445 } 1446 1447 err = ra.limiter.BatchReset(ctx, txns) 1448 if err != nil { 1449 ra.log.Warningf("resetting bucket for regID=[%d] identifier=[%s]: %s", regId, ident.Value, err) 1450 } 1451 } 1452 1453 // doDCVAndCAA performs DCV and CAA checks sequentially: DCV is performed first 1454 // and CAA is only checked if DCV is successful. Validation records from the DCV 1455 // check are returned even if the CAA check fails. 1456 func (ra *RegistrationAuthorityImpl) checkDCVAndCAA(ctx context.Context, dcvReq *vapb.PerformValidationRequest, caaReq *vapb.IsCAAValidRequest) (*corepb.ProblemDetails, []*corepb.ValidationRecord, error) { 1457 doDCVRes, err := ra.VA.DoDCV(ctx, dcvReq) 1458 if err != nil { 1459 return nil, nil, err 1460 } 1461 if doDCVRes.Problem != nil { 1462 return doDCVRes.Problem, doDCVRes.Records, nil 1463 } 1464 1465 switch identifier.FromProto(dcvReq.Identifier).Type { 1466 case identifier.TypeDNS: 1467 doCAAResp, err := ra.VA.DoCAA(ctx, caaReq) 1468 if err != nil { 1469 return nil, nil, err 1470 } 1471 return doCAAResp.Problem, doDCVRes.Records, nil 1472 case identifier.TypeIP: 1473 return nil, doDCVRes.Records, nil 1474 default: 1475 return nil, nil, berrors.MalformedError("invalid identifier type: %s", dcvReq.Identifier.Type) 1476 } 1477 } 1478 1479 // PerformValidation initiates validation for a specific challenge associated 1480 // with the given base authorization. The authorization and challenge are 1481 // updated based on the results. 1482 func (ra *RegistrationAuthorityImpl) PerformValidation( 1483 ctx context.Context, 1484 req *rapb.PerformValidationRequest) (*corepb.Authorization, error) { 1485 // Clock for start of PerformValidation. 1486 vStart := ra.clk.Now() 1487 1488 if core.IsAnyNilOrZero(req.Authz, req.Authz.Id, req.Authz.Identifier, req.Authz.Status, req.Authz.Expires) { 1489 return nil, errIncompleteGRPCRequest 1490 } 1491 1492 authz, err := bgrpc.PBToAuthz(req.Authz) 1493 if err != nil { 1494 return nil, err 1495 } 1496 1497 // Refuse to update expired authorizations 1498 if authz.Expires == nil || authz.Expires.Before(ra.clk.Now()) { 1499 return nil, berrors.MalformedError("expired authorization") 1500 } 1501 1502 profile, err := ra.profiles.get(authz.CertificateProfileName) 1503 if err != nil { 1504 return nil, err 1505 } 1506 1507 challIndex := int(req.ChallengeIndex) 1508 if challIndex >= len(authz.Challenges) { 1509 return nil, 1510 berrors.MalformedError("invalid challenge index '%d'", challIndex) 1511 } 1512 1513 ch := &authz.Challenges[challIndex] 1514 1515 // This challenge type may have been disabled since the challenge was created. 1516 if !ra.PA.ChallengeTypeEnabled(ch.Type) { 1517 return nil, berrors.MalformedError("challenge type %q no longer allowed", ch.Type) 1518 } 1519 1520 // We expect some clients to try and update a challenge for an authorization 1521 // that is already valid. In this case we don't need to process the 1522 // challenge update. It wouldn't be helpful, the overall authorization is 1523 // already good! We return early for the valid authz reuse case. 1524 if authz.Status == core.StatusValid { 1525 return req.Authz, nil 1526 } 1527 1528 if authz.Status != core.StatusPending { 1529 return nil, berrors.MalformedError("authorization must be pending") 1530 } 1531 1532 // Look up the account key for this authorization 1533 regPB, err := ra.SA.GetRegistration(ctx, &sapb.RegistrationID{Id: authz.RegistrationID}) 1534 if err != nil { 1535 return nil, berrors.InternalServerError("getting acct for authorization: %s", err.Error()) 1536 } 1537 reg, err := bgrpc.PbToRegistration(regPB) 1538 if err != nil { 1539 return nil, berrors.InternalServerError("getting acct for authorization: %s", err.Error()) 1540 } 1541 1542 // Compute the key authorization field based on the registration key 1543 expectedKeyAuthorization, err := ch.ExpectedKeyAuthorization(reg.Key) 1544 if err != nil { 1545 return nil, berrors.InternalServerError("could not compute expected key authorization value") 1546 } 1547 1548 // Double check before sending to VA 1549 if cErr := ch.CheckPending(); cErr != nil { 1550 return nil, berrors.MalformedError("cannot validate challenge: %s", cErr.Error()) 1551 } 1552 1553 // Dispatch to the VA for service 1554 ra.drainWG.Add(1) 1555 vaCtx := context.Background() 1556 go func(authz core.Authorization) { 1557 defer ra.drainWG.Done() 1558 1559 // We will mutate challenges later in this goroutine to change status and 1560 // add error, but we also return a copy of authz immediately. To avoid a 1561 // data race, make a copy of the challenges slice here for mutation. 1562 challenges := make([]core.Challenge, len(authz.Challenges)) 1563 copy(challenges, authz.Challenges) 1564 authz.Challenges = challenges 1565 chall, _ := bgrpc.ChallengeToPB(authz.Challenges[challIndex]) 1566 checkProb, checkRecords, err := ra.checkDCVAndCAA( 1567 vaCtx, 1568 &vapb.PerformValidationRequest{ 1569 Identifier: authz.Identifier.ToProto(), 1570 Challenge: chall, 1571 Authz: &vapb.AuthzMeta{Id: authz.ID, RegID: authz.RegistrationID}, 1572 ExpectedKeyAuthorization: expectedKeyAuthorization, 1573 }, 1574 &vapb.IsCAAValidRequest{ 1575 Identifier: authz.Identifier.ToProto(), 1576 ValidationMethod: chall.Type, 1577 AccountURIID: authz.RegistrationID, 1578 AuthzID: authz.ID, 1579 }, 1580 ) 1581 challenge := &authz.Challenges[challIndex] 1582 var prob *probs.ProblemDetails 1583 if err != nil { 1584 prob = probs.ServerInternal("Could not communicate with VA") 1585 ra.log.AuditErrf("Could not communicate with VA: %s", err) 1586 } else { 1587 if checkProb != nil { 1588 prob, err = bgrpc.PBToProblemDetails(checkProb) 1589 if err != nil { 1590 prob = probs.ServerInternal("Could not communicate with VA") 1591 ra.log.AuditErrf("Could not communicate with VA: %s", err) 1592 } 1593 } 1594 // Save the updated records 1595 records := make([]core.ValidationRecord, len(checkRecords)) 1596 for i, r := range checkRecords { 1597 records[i], err = bgrpc.PBToValidationRecord(r) 1598 if err != nil { 1599 prob = probs.ServerInternal("Records for validation corrupt") 1600 } 1601 } 1602 challenge.ValidationRecord = records 1603 } 1604 if !challenge.RecordsSane() && prob == nil { 1605 prob = probs.ServerInternal("Records for validation failed sanity check") 1606 } 1607 1608 expires := *authz.Expires 1609 if prob != nil { 1610 challenge.Status = core.StatusInvalid 1611 challenge.Error = prob 1612 err := ra.countFailedValidations(vaCtx, authz.RegistrationID, authz.Identifier) 1613 if err != nil { 1614 ra.log.Warningf("incrementing failed validations: %s", err) 1615 } 1616 } else { 1617 challenge.Status = core.StatusValid 1618 expires = ra.clk.Now().Add(profile.validAuthzLifetime) 1619 if features.Get().AutomaticallyPauseZombieClients { 1620 ra.resetAccountPausingLimit(vaCtx, authz.RegistrationID, authz.Identifier) 1621 } 1622 } 1623 challenge.Validated = &vStart 1624 authz.Challenges[challIndex] = *challenge 1625 1626 err = ra.recordValidation(vaCtx, authz.ID, expires, challenge) 1627 if err != nil { 1628 if errors.Is(err, berrors.NotFound) { 1629 // We log NotFound at a lower level because this is largely due to a 1630 // parallel-validation race: a different validation attempt has already 1631 // updated this authz, so we failed to find a *pending* authz with the 1632 // given ID to update. 1633 ra.log.Infof("Failed to record validation (likely parallel validation race): regID=[%d] authzID=[%s] err=[%s]", 1634 authz.RegistrationID, authz.ID, err) 1635 } else { 1636 ra.log.AuditErrf("Failed to record validation: regID=[%d] authzID=[%s] err=[%s]", 1637 authz.RegistrationID, authz.ID, err) 1638 } 1639 } 1640 }(authz) 1641 return bgrpc.AuthzToPB(authz) 1642 } 1643 1644 // revokeCertificate updates the database to mark the certificate as revoked, 1645 // with the given reason and current timestamp. 1646 func (ra *RegistrationAuthorityImpl) revokeCertificate(ctx context.Context, cert *x509.Certificate, reason revocation.Reason) error { 1647 serialString := core.SerialToString(cert.SerialNumber) 1648 issuerID := issuance.IssuerNameID(cert) 1649 shardIdx, err := crlShard(cert) 1650 if err != nil { 1651 return err 1652 } 1653 1654 _, err = ra.SA.RevokeCertificate(ctx, &sapb.RevokeCertificateRequest{ 1655 Serial: serialString, 1656 Reason: int64(reason), 1657 Date: timestamppb.New(ra.clk.Now()), 1658 IssuerID: int64(issuerID), 1659 ShardIdx: shardIdx, 1660 }) 1661 if err != nil { 1662 return err 1663 } 1664 1665 ra.revocationReasonCounter.WithLabelValues(reason.String()).Inc() 1666 return nil 1667 } 1668 1669 // updateRevocationForKeyCompromise updates the database to mark the certificate 1670 // as revoked, with the given reason and current timestamp. This only works for 1671 // certificates that were previously revoked for a reason other than 1672 // keyCompromise, and which are now being updated to keyCompromise instead. 1673 func (ra *RegistrationAuthorityImpl) updateRevocationForKeyCompromise(ctx context.Context, serialString string, issuerID issuance.NameID) error { 1674 status, err := ra.SA.GetCertificateStatus(ctx, &sapb.Serial{Serial: serialString}) 1675 if err != nil { 1676 return berrors.NotFoundError("unable to confirm that serial %q was ever issued: %s", serialString, err) 1677 } 1678 1679 if status.Status != string(core.OCSPStatusRevoked) { 1680 // Internal server error, because we shouldn't be in the function at all 1681 // unless the cert was already revoked. 1682 return fmt.Errorf("unable to re-revoke serial %q which is not currently revoked", serialString) 1683 } 1684 if revocation.Reason(status.RevokedReason) == revocation.KeyCompromise { 1685 return berrors.AlreadyRevokedError("unable to re-revoke serial %q which is already revoked for keyCompromise", serialString) 1686 } 1687 1688 cert, err := ra.SA.GetCertificate(ctx, &sapb.Serial{Serial: serialString}) 1689 if err != nil { 1690 return berrors.NotFoundError("unable to confirm that serial %q was ever issued: %s", serialString, err) 1691 } 1692 x509Cert, err := x509.ParseCertificate(cert.Der) 1693 if err != nil { 1694 return err 1695 } 1696 1697 shardIdx, err := crlShard(x509Cert) 1698 if err != nil { 1699 return err 1700 } 1701 1702 _, err = ra.SA.UpdateRevokedCertificate(ctx, &sapb.RevokeCertificateRequest{ 1703 Serial: serialString, 1704 Reason: int64(revocation.KeyCompromise), 1705 Date: timestamppb.New(ra.clk.Now()), 1706 Backdate: status.RevokedDate, 1707 IssuerID: int64(issuerID), 1708 ShardIdx: shardIdx, 1709 }) 1710 if err != nil { 1711 return err 1712 } 1713 1714 ra.revocationReasonCounter.WithLabelValues(revocation.KeyCompromise.String()).Inc() 1715 return nil 1716 } 1717 1718 // RevokeCertByApplicant revokes the certificate in question. It allows any 1719 // revocation reason from (0, 1, 3, 4, 5, 9), because Subscribers are allowed to 1720 // request any revocation reason for their own certificates. However, if the 1721 // requesting RegID is an account which has authorizations for all names in the 1722 // cert but is *not* the original subscriber, it overrides the revocation reason 1723 // to be 5 (cessationOfOperation), because that code is used to cover instances 1724 // where "the certificate subscriber no longer owns the domain names in the 1725 // certificate". It does not add the key to the blocked keys list, even if 1726 // reason 1 (keyCompromise) is requested, as it does not demonstrate said 1727 // compromise. 1728 func (ra *RegistrationAuthorityImpl) RevokeCertByApplicant(ctx context.Context, req *rapb.RevokeCertByApplicantRequest) (*emptypb.Empty, error) { 1729 if req == nil || req.Cert == nil || req.RegID == 0 { 1730 return nil, errIncompleteGRPCRequest 1731 } 1732 1733 reasonCode := revocation.Reason(req.Code) 1734 if !revocation.UserAllowedReason(reasonCode) { 1735 return nil, berrors.BadRevocationReasonError(req.Code) 1736 } 1737 1738 cert, err := x509.ParseCertificate(req.Cert) 1739 if err != nil { 1740 return nil, err 1741 } 1742 1743 serialString := core.SerialToString(cert.SerialNumber) 1744 1745 logEvent := certificateRevocationEvent{ 1746 ID: core.NewToken(), 1747 SerialNumber: serialString, 1748 Reason: reasonCode, 1749 Method: "applicant", 1750 RequesterID: req.RegID, 1751 } 1752 1753 // Below this point, do not re-declare `err` (i.e. type `err :=`) in a 1754 // nested scope. Doing so will create a new `err` variable that is not 1755 // captured by this closure. 1756 defer func() { 1757 if err != nil { 1758 logEvent.Error = err.Error() 1759 } 1760 ra.log.AuditObject("Revocation request:", logEvent) 1761 }() 1762 1763 metadata, err := ra.SA.GetSerialMetadata(ctx, &sapb.Serial{Serial: serialString}) 1764 if err != nil { 1765 return nil, err 1766 } 1767 1768 if req.RegID == metadata.RegistrationID { 1769 // The requester is the original subscriber. They can revoke for any reason. 1770 logEvent.Method = "subscriber" 1771 } else { 1772 // The requester is a different account. We need to confirm that they have 1773 // authorizations for all names in the cert. 1774 logEvent.Method = "control" 1775 1776 idents := identifier.FromCert(cert) 1777 var authzPB *sapb.Authorizations 1778 authzPB, err = ra.SA.GetValidAuthorizations2(ctx, &sapb.GetValidAuthorizationsRequest{ 1779 RegistrationID: req.RegID, 1780 Identifiers: idents.ToProtoSlice(), 1781 ValidUntil: timestamppb.New(ra.clk.Now()), 1782 }) 1783 if err != nil { 1784 return nil, err 1785 } 1786 1787 var authzMap map[identifier.ACMEIdentifier]*core.Authorization 1788 authzMap, err = bgrpc.PBToAuthzMap(authzPB) 1789 if err != nil { 1790 return nil, err 1791 } 1792 1793 for _, ident := range idents { 1794 if _, present := authzMap[ident]; !present { 1795 return nil, berrors.UnauthorizedError("requester does not control all identifiers in cert with serial %q", serialString) 1796 } 1797 } 1798 1799 // Applicants who are not the original Subscriber are not allowed to 1800 // revoke for any reason other than cessationOfOperation, which covers 1801 // circumstances where "the certificate subscriber no longer owns the 1802 // domain names in the certificate". Override the reason code to match. 1803 reasonCode = revocation.CessationOfOperation 1804 logEvent.Reason = reasonCode 1805 } 1806 1807 err = ra.revokeCertificate(ctx, cert, reasonCode) 1808 if err != nil { 1809 return nil, err 1810 } 1811 1812 return &emptypb.Empty{}, nil 1813 } 1814 1815 // crlShard extracts the CRL shard from a certificate's CRLDistributionPoint. 1816 // 1817 // If there is no CRLDistributionPoint, returns 0. 1818 // 1819 // If there is more than one CRLDistributionPoint, returns an error. 1820 // 1821 // Assumes the shard number is represented in the URL as an integer that 1822 // occurs in the last path component, optionally followed by ".crl". 1823 // 1824 // Note: This assumes (a) the CA is generating well-formed, correct 1825 // CRLDistributionPoints and (b) an earlier component has verified the signature 1826 // on this certificate comes from one of our issuers. 1827 func crlShard(cert *x509.Certificate) (int64, error) { 1828 if len(cert.CRLDistributionPoints) == 0 { 1829 return 0, errors.New("no crlDistributionPoints in certificate") 1830 } 1831 if len(cert.CRLDistributionPoints) > 1 { 1832 return 0, errors.New("too many crlDistributionPoints in certificate") 1833 } 1834 1835 url := strings.TrimSuffix(cert.CRLDistributionPoints[0], ".crl") 1836 lastIndex := strings.LastIndex(url, "/") 1837 if lastIndex == -1 { 1838 return 0, fmt.Errorf("malformed CRLDistributionPoint %q", url) 1839 } 1840 shardStr := url[lastIndex+1:] 1841 shardIdx, err := strconv.Atoi(shardStr) 1842 if err != nil { 1843 return 0, fmt.Errorf("parsing CRLDistributionPoint: %s", err) 1844 } 1845 1846 if shardIdx <= 0 { 1847 return 0, fmt.Errorf("invalid shard in CRLDistributionPoint: %d", shardIdx) 1848 } 1849 1850 return int64(shardIdx), nil 1851 } 1852 1853 // addToBlockedKeys initiates a GRPC call to have the Base64-encoded SHA256 1854 // digest of a provided public key added to the blockedKeys table. 1855 func (ra *RegistrationAuthorityImpl) addToBlockedKeys(ctx context.Context, key crypto.PublicKey, src string, comment string) error { 1856 var digest core.Sha256Digest 1857 digest, err := core.KeyDigest(key) 1858 if err != nil { 1859 return err 1860 } 1861 1862 // Add the public key to the blocked keys list. 1863 _, err = ra.SA.AddBlockedKey(ctx, &sapb.AddBlockedKeyRequest{ 1864 KeyHash: digest[:], 1865 Added: timestamppb.New(ra.clk.Now()), 1866 Source: src, 1867 Comment: comment, 1868 }) 1869 if err != nil { 1870 return err 1871 } 1872 1873 return nil 1874 } 1875 1876 // RevokeCertByKey revokes the certificate in question. It always uses 1877 // reason code 1 (keyCompromise). It ensures that they public key is added to 1878 // the blocked keys list, even if revocation otherwise fails. 1879 func (ra *RegistrationAuthorityImpl) RevokeCertByKey(ctx context.Context, req *rapb.RevokeCertByKeyRequest) (*emptypb.Empty, error) { 1880 if req == nil || req.Cert == nil { 1881 return nil, errIncompleteGRPCRequest 1882 } 1883 1884 cert, err := x509.ParseCertificate(req.Cert) 1885 if err != nil { 1886 return nil, err 1887 } 1888 1889 logEvent := certificateRevocationEvent{ 1890 ID: core.NewToken(), 1891 SerialNumber: core.SerialToString(cert.SerialNumber), 1892 Reason: revocation.KeyCompromise, 1893 Method: "key", 1894 RequesterID: 0, 1895 } 1896 1897 // Below this point, do not re-declare `err` (i.e. type `err :=`) in a 1898 // nested scope. Doing so will create a new `err` variable that is not 1899 // captured by this closure. 1900 defer func() { 1901 if err != nil { 1902 logEvent.Error = err.Error() 1903 } 1904 ra.log.AuditObject("Revocation request:", logEvent) 1905 }() 1906 1907 // We revoke the cert before adding it to the blocked keys list, to avoid a 1908 // race between this and the bad-key-revoker. But we don't check the error 1909 // from this operation until after we add the key to the blocked keys list, 1910 // since that addition needs to happen no matter what. 1911 revokeErr := ra.revokeCertificate( 1912 ctx, 1913 cert, 1914 revocation.KeyCompromise, 1915 ) 1916 1917 // Failing to add the key to the blocked keys list is a worse failure than 1918 // failing to revoke in the first place, because it means that 1919 // bad-key-revoker won't revoke the cert anyway. 1920 err = ra.addToBlockedKeys(ctx, cert.PublicKey, "API", "") 1921 if err != nil { 1922 return nil, err 1923 } 1924 1925 issuerID := issuance.IssuerNameID(cert) 1926 1927 // Check the error returned from revokeCertificate itself. 1928 err = revokeErr 1929 if errors.Is(err, berrors.AlreadyRevoked) { 1930 // If it was an AlreadyRevoked error, try to re-revoke the cert in case 1931 // it was revoked for a reason other than keyCompromise. 1932 err = ra.updateRevocationForKeyCompromise(ctx, core.SerialToString(cert.SerialNumber), issuerID) 1933 if err != nil { 1934 return nil, err 1935 } 1936 return &emptypb.Empty{}, nil 1937 } else if err != nil { 1938 // Error out if the error was anything other than AlreadyRevoked. 1939 return nil, err 1940 } 1941 1942 return &emptypb.Empty{}, nil 1943 } 1944 1945 // AdministrativelyRevokeCertificate terminates trust in the certificate 1946 // provided and does not require the registration ID of the requester since this 1947 // method is only called from the `admin` tool. It trusts that the admin 1948 // is doing the right thing, so if the requested reason is keyCompromise, it 1949 // blocks the key from future issuance even though compromise has not been 1950 // demonstrated here. 1951 func (ra *RegistrationAuthorityImpl) AdministrativelyRevokeCertificate(ctx context.Context, req *rapb.AdministrativelyRevokeCertificateRequest) (*emptypb.Empty, error) { 1952 if req == nil || req.AdminName == "" { 1953 return nil, errIncompleteGRPCRequest 1954 } 1955 if req.Serial == "" { 1956 return nil, errIncompleteGRPCRequest 1957 } 1958 if req.CrlShard != 0 && !req.Malformed { 1959 return nil, errors.New("non-zero CRLShard is only allowed for malformed certificates (shard is automatic for well formed certificates)") 1960 } 1961 if req.Malformed && req.CrlShard == 0 { 1962 return nil, errors.New("CRLShard is required for malformed certificates") 1963 } 1964 1965 reasonCode := revocation.Reason(req.Code) 1966 if !revocation.AdminAllowedReason(reasonCode) { 1967 return nil, fmt.Errorf("cannot revoke for reason %d", reasonCode) 1968 } 1969 if req.SkipBlockKey && reasonCode != revocation.KeyCompromise { 1970 return nil, fmt.Errorf("cannot skip key blocking for reasons other than KeyCompromise") 1971 } 1972 if reasonCode == revocation.KeyCompromise && req.Malformed { 1973 return nil, fmt.Errorf("cannot revoke malformed certificate for KeyCompromise") 1974 } 1975 1976 logEvent := certificateRevocationEvent{ 1977 ID: core.NewToken(), 1978 SerialNumber: req.Serial, 1979 Reason: reasonCode, 1980 CRLShard: req.CrlShard, 1981 Method: "admin", 1982 AdminName: req.AdminName, 1983 } 1984 1985 // Below this point, do not re-declare `err` (i.e. type `err :=`) in a 1986 // nested scope. Doing so will create a new `err` variable that is not 1987 // captured by this closure. 1988 var err error 1989 defer func() { 1990 if err != nil { 1991 logEvent.Error = err.Error() 1992 } 1993 ra.log.AuditObject("Revocation request:", logEvent) 1994 }() 1995 1996 var cert *x509.Certificate 1997 var issuerID issuance.NameID 1998 var shard int64 1999 if req.Cert != nil { 2000 // If the incoming request includes a certificate body, just use that and 2001 // avoid doing any database queries. This code path is deprecated and will 2002 // be removed when req.Cert is removed. 2003 cert, err = x509.ParseCertificate(req.Cert) 2004 if err != nil { 2005 return nil, err 2006 } 2007 issuerID = issuance.IssuerNameID(cert) 2008 shard, err = crlShard(cert) 2009 if err != nil { 2010 return nil, err 2011 } 2012 } else if !req.Malformed { 2013 // As long as we don't believe the cert will be malformed, we should 2014 // get the precertificate so we can block its pubkey if necessary. 2015 var certPB *corepb.Certificate 2016 certPB, err = ra.SA.GetLintPrecertificate(ctx, &sapb.Serial{Serial: req.Serial}) 2017 if err != nil { 2018 return nil, err 2019 } 2020 // Note that, although the thing we're parsing here is actually a linting 2021 // precertificate, it has identical issuer info (and therefore an identical 2022 // issuer NameID) to the real thing. 2023 cert, err = x509.ParseCertificate(certPB.Der) 2024 if err != nil { 2025 return nil, err 2026 } 2027 issuerID = issuance.IssuerNameID(cert) 2028 shard, err = crlShard(cert) 2029 if err != nil { 2030 return nil, err 2031 } 2032 } else { 2033 // But if the cert is malformed, we at least still need its IssuerID. 2034 var status *corepb.CertificateStatus 2035 status, err = ra.SA.GetCertificateStatus(ctx, &sapb.Serial{Serial: req.Serial}) 2036 if err != nil { 2037 return nil, fmt.Errorf("unable to confirm that serial %q was ever issued: %w", req.Serial, err) 2038 } 2039 issuerID = issuance.NameID(status.IssuerID) 2040 shard = req.CrlShard 2041 } 2042 2043 _, err = ra.SA.RevokeCertificate(ctx, &sapb.RevokeCertificateRequest{ 2044 Serial: req.Serial, 2045 Reason: int64(reasonCode), 2046 Date: timestamppb.New(ra.clk.Now()), 2047 IssuerID: int64(issuerID), 2048 ShardIdx: shard, 2049 }) 2050 if err != nil { 2051 if reasonCode == revocation.KeyCompromise && errors.Is(err, berrors.AlreadyRevoked) { 2052 err = ra.updateRevocationForKeyCompromise(ctx, req.Serial, issuerID) 2053 if err != nil { 2054 return nil, err 2055 } 2056 } 2057 return nil, err 2058 } 2059 2060 if reasonCode == revocation.KeyCompromise && !req.SkipBlockKey { 2061 if cert == nil { 2062 return nil, errors.New("revoking for key compromise requires providing the certificate's DER") 2063 } 2064 err = ra.addToBlockedKeys(ctx, cert.PublicKey, "admin-revoker", fmt.Sprintf("revoked by %s", req.AdminName)) 2065 if err != nil { 2066 return nil, err 2067 } 2068 } 2069 2070 return &emptypb.Empty{}, nil 2071 } 2072 2073 // DeactivateRegistration deactivates a valid registration 2074 func (ra *RegistrationAuthorityImpl) DeactivateRegistration(ctx context.Context, req *rapb.DeactivateRegistrationRequest) (*corepb.Registration, error) { 2075 if req == nil || req.RegistrationID == 0 { 2076 return nil, errIncompleteGRPCRequest 2077 } 2078 2079 updatedAcct, err := ra.SA.DeactivateRegistration(ctx, &sapb.RegistrationID{Id: req.RegistrationID}) 2080 if err != nil { 2081 return nil, err 2082 } 2083 2084 return updatedAcct, nil 2085 } 2086 2087 // DeactivateAuthorization deactivates a currently valid authorization 2088 func (ra *RegistrationAuthorityImpl) DeactivateAuthorization(ctx context.Context, req *corepb.Authorization) (*emptypb.Empty, error) { 2089 ident := identifier.FromProto(req.Identifier) 2090 2091 if core.IsAnyNilOrZero(req, req.Id, ident, req.Status, req.RegistrationID) { 2092 return nil, errIncompleteGRPCRequest 2093 } 2094 authzID, err := strconv.ParseInt(req.Id, 10, 64) 2095 if err != nil { 2096 return nil, err 2097 } 2098 if _, err := ra.SA.DeactivateAuthorization2(ctx, &sapb.AuthorizationID2{Id: authzID}); err != nil { 2099 return nil, err 2100 } 2101 if req.Status == string(core.StatusPending) { 2102 // Some clients deactivate pending authorizations without attempting them. 2103 // We're not sure exactly when this happens but it's most likely due to 2104 // internal errors in the client. From our perspective this uses storage 2105 // resources similar to how failed authorizations do, so we increment the 2106 // failed authorizations limit. 2107 err = ra.countFailedValidations(ctx, req.RegistrationID, ident) 2108 if err != nil { 2109 return nil, fmt.Errorf("failed to update rate limits: %w", err) 2110 } 2111 } 2112 return &emptypb.Empty{}, nil 2113 } 2114 2115 // NewOrder creates a new order object 2116 func (ra *RegistrationAuthorityImpl) NewOrder(ctx context.Context, req *rapb.NewOrderRequest) (*corepb.Order, error) { 2117 if req == nil || req.RegistrationID == 0 { 2118 return nil, errIncompleteGRPCRequest 2119 } 2120 2121 idents := identifier.Normalize(identifier.FromProtoSlice(req.Identifiers)) 2122 2123 profile, err := ra.profiles.get(req.CertificateProfileName) 2124 if err != nil { 2125 return nil, err 2126 } 2127 2128 if profile.allowList != nil && !profile.allowList.Contains(req.RegistrationID) { 2129 return nil, berrors.UnauthorizedError("account ID %d is not permitted to use certificate profile %q", 2130 req.RegistrationID, 2131 req.CertificateProfileName, 2132 ) 2133 } 2134 2135 if len(idents) > profile.maxNames { 2136 return nil, berrors.MalformedError( 2137 "Order cannot contain more than %d identifiers", profile.maxNames) 2138 } 2139 2140 for _, ident := range idents { 2141 if !slices.Contains(profile.identifierTypes, ident.Type) { 2142 return nil, berrors.RejectedIdentifierError("Profile %q does not permit %s type identifiers", req.CertificateProfileName, ident.Type) 2143 } 2144 } 2145 2146 // Validate that our policy allows issuing for each of the identifiers in 2147 // the order 2148 err = ra.PA.WillingToIssue(idents) 2149 if err != nil { 2150 return nil, err 2151 } 2152 2153 err = wildcardOverlap(idents) 2154 if err != nil { 2155 return nil, err 2156 } 2157 2158 // See if there is an existing unexpired pending (or ready) order that can be reused 2159 // for this account 2160 existingOrder, err := ra.SA.GetOrderForNames(ctx, &sapb.GetOrderForNamesRequest{ 2161 AcctID: req.RegistrationID, 2162 Identifiers: idents.ToProtoSlice(), 2163 }) 2164 // If there was an error and it wasn't an acceptable "NotFound" error, return 2165 // immediately 2166 if err != nil && !errors.Is(err, berrors.NotFound) { 2167 return nil, err 2168 } 2169 2170 // If there was an order, make sure it has expected fields and return it 2171 // Error if an incomplete order is returned. 2172 if existingOrder != nil { 2173 // Check to see if the expected fields of the existing order are set. 2174 if core.IsAnyNilOrZero(existingOrder.Id, existingOrder.Status, existingOrder.RegistrationID, existingOrder.Identifiers, existingOrder.Created, existingOrder.Expires) { 2175 return nil, errIncompleteGRPCResponse 2176 } 2177 2178 // Only re-use the order if the profile (even if it is just the empty 2179 // string, leaving us to choose a default profile) matches. 2180 if existingOrder.CertificateProfileName == req.CertificateProfileName { 2181 // Track how often we reuse an existing order and how old that order is. 2182 ra.orderAges.WithLabelValues("NewOrder").Observe(ra.clk.Since(existingOrder.Created.AsTime()).Seconds()) 2183 return existingOrder, nil 2184 } 2185 } 2186 2187 // An order's lifetime is effectively bound by the shortest remaining lifetime 2188 // of its associated authorizations. For that reason it would be Uncool if 2189 // `sa.GetAuthorizations` returned an authorization that was very close to 2190 // expiry. The resulting pending order that references it would itself end up 2191 // expiring very soon. 2192 // What is considered "very soon" scales with the associated order's lifetime, 2193 // up to a point. 2194 minTimeToExpiry := profile.orderLifetime / 8 2195 if minTimeToExpiry < time.Hour { 2196 minTimeToExpiry = time.Hour 2197 } else if minTimeToExpiry > 24*time.Hour { 2198 minTimeToExpiry = 24 * time.Hour 2199 } 2200 authzExpiryCutoff := ra.clk.Now().Add(minTimeToExpiry) 2201 2202 existingAuthz, err := ra.SA.GetValidAuthorizations2(ctx, &sapb.GetValidAuthorizationsRequest{ 2203 RegistrationID: req.RegistrationID, 2204 ValidUntil: timestamppb.New(authzExpiryCutoff), 2205 Identifiers: idents.ToProtoSlice(), 2206 Profile: req.CertificateProfileName, 2207 }) 2208 if err != nil { 2209 return nil, err 2210 } 2211 2212 identToExistingAuthz, err := bgrpc.PBToAuthzMap(existingAuthz) 2213 if err != nil { 2214 return nil, err 2215 } 2216 2217 // For each of the identifiers in the order, if there is an acceptable 2218 // existing authz, append it to the order to reuse it. Otherwise track that 2219 // there is a missing authz for that identifier. 2220 var newOrderAuthzs []int64 2221 var missingAuthzIdents identifier.ACMEIdentifiers 2222 for _, ident := range idents { 2223 // If there isn't an existing authz, note that its missing and continue 2224 authz, exists := identToExistingAuthz[ident] 2225 if !exists { 2226 // The existing authz was not acceptable for reuse, and we need to 2227 // mark the name as requiring a new pending authz. 2228 missingAuthzIdents = append(missingAuthzIdents, ident) 2229 continue 2230 } 2231 2232 // If the authz is associated with the wrong profile, don't reuse it. 2233 if authz.CertificateProfileName != req.CertificateProfileName { 2234 missingAuthzIdents = append(missingAuthzIdents, ident) 2235 // Delete the authz from the identToExistingAuthz map since we are not reusing it. 2236 delete(identToExistingAuthz, ident) 2237 continue 2238 } 2239 2240 // This is only used for our metrics. 2241 authzAge := (profile.validAuthzLifetime - authz.Expires.Sub(ra.clk.Now())).Seconds() 2242 if authz.Status == core.StatusPending { 2243 authzAge = (profile.pendingAuthzLifetime - authz.Expires.Sub(ra.clk.Now())).Seconds() 2244 } 2245 2246 // If the identifier is a wildcard DNS name, it must have exactly one 2247 // DNS-01 type challenge. The PA guarantees this at order creation time, 2248 // but we verify again to be safe. 2249 if ident.Type == identifier.TypeDNS && strings.HasPrefix(ident.Value, "*.") && 2250 (len(authz.Challenges) != 1 || authz.Challenges[0].Type != core.ChallengeTypeDNS01) { 2251 return nil, berrors.InternalServerError( 2252 "SA.GetAuthorizations returned a DNS wildcard authz (%s) with invalid challenge(s)", 2253 authz.ID) 2254 } 2255 2256 // If we reached this point then the existing authz was acceptable for 2257 // reuse. 2258 authzID, err := strconv.ParseInt(authz.ID, 10, 64) 2259 if err != nil { 2260 return nil, err 2261 } 2262 newOrderAuthzs = append(newOrderAuthzs, authzID) 2263 ra.authzAges.WithLabelValues("NewOrder", string(authz.Status)).Observe(authzAge) 2264 } 2265 2266 // Loop through each of the identifiers missing authzs and create a new 2267 // pending authorization for each. 2268 var newAuthzs []*sapb.NewAuthzRequest 2269 for _, ident := range missingAuthzIdents { 2270 challTypes, err := ra.PA.ChallengeTypesFor(ident) 2271 if err != nil { 2272 return nil, err 2273 } 2274 2275 var challStrs []string 2276 for _, t := range challTypes { 2277 challStrs = append(challStrs, string(t)) 2278 } 2279 2280 newAuthzs = append(newAuthzs, &sapb.NewAuthzRequest{ 2281 Identifier: ident.ToProto(), 2282 RegistrationID: req.RegistrationID, 2283 Expires: timestamppb.New(ra.clk.Now().Add(profile.pendingAuthzLifetime).Truncate(time.Second)), 2284 ChallengeTypes: challStrs, 2285 Token: core.NewToken(), 2286 }) 2287 2288 ra.authzAges.WithLabelValues("NewOrder", string(core.StatusPending)).Observe(0) 2289 } 2290 2291 // Start with the order's own expiry as the minExpiry. We only care 2292 // about authz expiries that are sooner than the order's expiry 2293 minExpiry := ra.clk.Now().Add(profile.orderLifetime) 2294 2295 // Check the reused authorizations to see if any have an expiry before the 2296 // minExpiry (the order's lifetime) 2297 for _, authz := range identToExistingAuthz { 2298 // An authz without an expiry is an unexpected internal server event 2299 if core.IsAnyNilOrZero(authz.Expires) { 2300 return nil, berrors.InternalServerError( 2301 "SA.GetAuthorizations returned an authz (%s) with zero expiry", 2302 authz.ID) 2303 } 2304 // If the reused authorization expires before the minExpiry, it's expiry 2305 // is the new minExpiry. 2306 if authz.Expires.Before(minExpiry) { 2307 minExpiry = *authz.Expires 2308 } 2309 } 2310 // If the newly created pending authz's have an expiry closer than the 2311 // minExpiry the minExpiry is the pending authz expiry. 2312 if len(newAuthzs) > 0 { 2313 newPendingAuthzExpires := ra.clk.Now().Add(profile.pendingAuthzLifetime) 2314 if newPendingAuthzExpires.Before(minExpiry) { 2315 minExpiry = newPendingAuthzExpires 2316 } 2317 } 2318 2319 newOrder := &sapb.NewOrderRequest{ 2320 RegistrationID: req.RegistrationID, 2321 Identifiers: idents.ToProtoSlice(), 2322 CertificateProfileName: req.CertificateProfileName, 2323 Replaces: req.Replaces, 2324 ReplacesSerial: req.ReplacesSerial, 2325 // Set the order's expiry to the minimum expiry. The db doesn't store 2326 // sub-second values, so truncate here. 2327 Expires: timestamppb.New(minExpiry.Truncate(time.Second)), 2328 V2Authorizations: newOrderAuthzs, 2329 } 2330 newOrderAndAuthzsReq := &sapb.NewOrderAndAuthzsRequest{ 2331 NewOrder: newOrder, 2332 NewAuthzs: newAuthzs, 2333 } 2334 storedOrder, err := ra.SA.NewOrderAndAuthzs(ctx, newOrderAndAuthzsReq) 2335 if err != nil { 2336 return nil, err 2337 } 2338 2339 if core.IsAnyNilOrZero(storedOrder.Id, storedOrder.Status, storedOrder.RegistrationID, storedOrder.Identifiers, storedOrder.Created, storedOrder.Expires) { 2340 return nil, errIncompleteGRPCResponse 2341 } 2342 ra.orderAges.WithLabelValues("NewOrder").Observe(0) 2343 2344 // Note how many identifiers are being requested in this certificate order. 2345 ra.namesPerCert.With(prometheus.Labels{"type": "requested"}).Observe(float64(len(storedOrder.Identifiers))) 2346 2347 return storedOrder, nil 2348 } 2349 2350 // wildcardOverlap takes a slice of identifiers and returns an error if any of 2351 // them is a non-wildcard FQDN that overlaps with a wildcard domain in the map. 2352 func wildcardOverlap(idents identifier.ACMEIdentifiers) error { 2353 nameMap := make(map[string]bool, len(idents)) 2354 for _, v := range idents { 2355 if v.Type == identifier.TypeDNS { 2356 nameMap[v.Value] = true 2357 } 2358 } 2359 for name := range nameMap { 2360 if name[0] == '*' { 2361 continue 2362 } 2363 labels := strings.Split(name, ".") 2364 labels[0] = "*" 2365 if nameMap[strings.Join(labels, ".")] { 2366 return berrors.MalformedError( 2367 "Domain name %q is redundant with a wildcard domain in the same request. Remove one or the other from the certificate request.", name) 2368 } 2369 } 2370 return nil 2371 } 2372 2373 // UnpauseAccount receives a validated account unpause request from the SFE and 2374 // instructs the SA to unpause that account. If the account cannot be unpaused, 2375 // an error is returned. 2376 func (ra *RegistrationAuthorityImpl) UnpauseAccount(ctx context.Context, request *rapb.UnpauseAccountRequest) (*rapb.UnpauseAccountResponse, error) { 2377 if core.IsAnyNilOrZero(request.RegistrationID) { 2378 return nil, errIncompleteGRPCRequest 2379 } 2380 2381 count, err := ra.SA.UnpauseAccount(ctx, &sapb.RegistrationID{ 2382 Id: request.RegistrationID, 2383 }) 2384 if err != nil { 2385 return nil, berrors.InternalServerError("failed to unpause account ID %d", request.RegistrationID) 2386 } 2387 2388 return &rapb.UnpauseAccountResponse{Count: count.Count}, nil 2389 } 2390 2391 func (ra *RegistrationAuthorityImpl) GetAuthorization(ctx context.Context, req *rapb.GetAuthorizationRequest) (*corepb.Authorization, error) { 2392 if core.IsAnyNilOrZero(req, req.Id) { 2393 return nil, errIncompleteGRPCRequest 2394 } 2395 2396 authz, err := ra.SA.GetAuthorization2(ctx, &sapb.AuthorizationID2{Id: req.Id}) 2397 if err != nil { 2398 return nil, fmt.Errorf("getting authz from SA: %w", err) 2399 } 2400 2401 // Filter out any challenges which are currently disabled, so that the client 2402 // doesn't attempt them. 2403 challs := []*corepb.Challenge{} 2404 for _, chall := range authz.Challenges { 2405 if ra.PA.ChallengeTypeEnabled(core.AcmeChallenge(chall.Type)) { 2406 challs = append(challs, chall) 2407 } 2408 } 2409 2410 authz.Challenges = challs 2411 return authz, nil 2412 } 2413 2414 // AddRateLimitOverride dispatches an SA RPC to add a rate limit override to the 2415 // database. If the override already exists, it will be updated. If the override 2416 // does not exist, it will be inserted and enabled. If the override exists but 2417 // has been disabled, it will be updated but not be re-enabled. The status of 2418 // the override is returned in Enabled field of the response. To re-enable an 2419 // override, use sa.EnableRateLimitOverride. 2420 func (ra *RegistrationAuthorityImpl) AddRateLimitOverride(ctx context.Context, req *rapb.AddRateLimitOverrideRequest) (*rapb.AddRateLimitOverrideResponse, error) { 2421 if core.IsAnyNilOrZero(req, req.LimitEnum, req.BucketKey, req.Count, req.Burst, req.Period, req.Comment) { 2422 return nil, errIncompleteGRPCRequest 2423 } 2424 2425 resp, err := ra.SA.AddRateLimitOverride(ctx, &sapb.AddRateLimitOverrideRequest{ 2426 Override: &sapb.RateLimitOverride{ 2427 LimitEnum: req.LimitEnum, 2428 BucketKey: req.BucketKey, 2429 Comment: req.Comment, 2430 Period: req.Period, 2431 Count: req.Count, 2432 Burst: req.Burst, 2433 }, 2434 }) 2435 if err != nil { 2436 return nil, fmt.Errorf("adding rate limit override: %w", err) 2437 } 2438 2439 return &rapb.AddRateLimitOverrideResponse{ 2440 Inserted: resp.Inserted, 2441 Enabled: resp.Enabled, 2442 }, nil 2443 } 2444 2445 // Drain blocks until all detached goroutines are done. 2446 // 2447 // The RA runs detached goroutines for challenge validation and finalization, 2448 // so that ACME responses can be returned to the user promptly while work continues. 2449 // 2450 // The main goroutine should call this before exiting to avoid canceling the work 2451 // being done in detached goroutines. 2452 func (ra *RegistrationAuthorityImpl) Drain() { 2453 ra.drainWG.Wait() 2454 }