@@ -319,6 +319,10 @@ type certificateRequestEvent struct {
319319 // CertProfileHash is SHA256 sum over every exported field of an
320320 // issuance.ProfileConfig, represented here as a hexadecimal string.
321321 CertProfileHash string `json:",omitempty"`
322+ // PreviousCertificateIssued is present when this certificate uses the same set
323+ // of FQDNs as a previous certificate (from any account) and contains the
324+ // notBefore of the most recent such certificate.
325+ PreviousCertificateIssued time.Time `json:",omitempty"`
322326}
323327
324328// certificateRevocationEvent is a struct for holding information that is logged
@@ -889,6 +893,10 @@ func (ra *RegistrationAuthorityImpl) FinalizeOrder(ctx context.Context, req *rap
889893 // that it can wait for all goroutines to drain during shutdown.
890894 ra .drainWG .Add (1 )
891895 go func () {
896+ // The original context will be canceled in the RPC layer when FinalizeOrder returns,
897+ // so split off a context that won't be canceled (and has its own timeout).
898+ ctx , cancel := context .WithTimeout (context .WithoutCancel (ctx ), ra .finalizeTimeout )
899+ defer cancel ()
892900 _ , err := ra .issueCertificateOuter (ctx , proto .Clone (order ).(* corepb.Order ), csr , logEvent )
893901 if err != nil {
894902 // We only log here, because this is in a background goroutine with
@@ -1014,9 +1022,23 @@ func (ra *RegistrationAuthorityImpl) issueCertificateOuter(
10141022 ra .inflightFinalizes .Inc ()
10151023 defer ra .inflightFinalizes .Dec ()
10161024
1025+ isRenewal := false
1026+ timestamps , err := ra .SA .FQDNSetTimestampsForWindow (ctx , & sapb.CountFQDNSetsRequest {
1027+ DnsNames : order .DnsNames ,
1028+ Window : durationpb .New (120 * 24 * time .Hour ),
1029+ Limit : 1 ,
1030+ })
1031+ if err != nil {
1032+ return nil , fmt .Errorf ("checking if certificate is a renewal: %w" , err )
1033+ }
1034+ if len (timestamps .Timestamps ) > 0 {
1035+ isRenewal = true
1036+ logEvent .PreviousCertificateIssued = timestamps .Timestamps [0 ].AsTime ()
1037+ }
1038+
10171039 // Step 3: Issue the Certificate
10181040 cert , cpId , err := ra .issueCertificateInner (
1019- ctx , csr , order .CertificateProfileName , accountID (order .RegistrationID ), orderID (order .Id ))
1041+ ctx , csr , isRenewal , order .CertificateProfileName , accountID (order .RegistrationID ), orderID (order .Id ))
10201042
10211043 // Step 4: Fail the order if necessary, and update metrics and log fields
10221044 var result string
@@ -1119,16 +1141,10 @@ type certProfileID struct {
11191141func (ra * RegistrationAuthorityImpl ) issueCertificateInner (
11201142 ctx context.Context ,
11211143 csr * x509.CertificateRequest ,
1144+ isRenewal bool ,
11221145 profileName string ,
11231146 acctID accountID ,
11241147 oID orderID ) (* x509.Certificate , * certProfileID , error ) {
1125- if features .Get ().AsyncFinalize {
1126- // If we're in async mode, use a context with a much longer timeout.
1127- var cancel func ()
1128- ctx , cancel = context .WithTimeout (context .WithoutCancel (ctx ), ra .finalizeTimeout )
1129- defer cancel ()
1130- }
1131-
11321148 // wrapError adds a prefix to an error. If the error is a boulder error then
11331149 // the problem detail is updated with the prefix. Otherwise a new error is
11341150 // returned with the message prefixed using `fmt.Errorf`
@@ -1164,12 +1180,6 @@ func (ra *RegistrationAuthorityImpl) issueCertificateInner(
11641180 return nil , nil , wrapError (err , "getting SCTs" )
11651181 }
11661182
1167- exists , err := ra .SA .FQDNSetExists (ctx , & sapb.FQDNSetExistsRequest {DnsNames : parsedPrecert .DNSNames })
1168- if err != nil {
1169- return nil , nil , wrapError (err , "checking if certificate is a renewal" )
1170- }
1171- isRenewal := exists .Exists
1172-
11731183 cert , err := ra .CA .IssueCertificateForPrecertificate (ctx , & capb.IssueCertificateForPrecertificateRequest {
11741184 DER : precert .DER ,
11751185 SCTs : scts ,
@@ -1518,8 +1528,7 @@ func (ra *RegistrationAuthorityImpl) PerformValidation(
15181528 // Clock for start of PerformValidation.
15191529 vStart := ra .clk .Now ()
15201530
1521- // TODO(#7153): Check each value via core.IsAnyNilOrZero
1522- if req .Authz == nil || req .Authz .Id == "" || req .Authz .DnsName == "" || req .Authz .Status == "" || core .IsAnyNilOrZero (req .Authz .Expires ) {
1531+ if core .IsAnyNilOrZero (req .Authz , req .Authz .Id , req .Authz .DnsName , req .Authz .Status , req .Authz .Expires ) {
15231532 return nil , errIncompleteGRPCRequest
15241533 }
15251534
@@ -2216,8 +2225,7 @@ func (ra *RegistrationAuthorityImpl) NewOrder(ctx context.Context, req *rapb.New
22162225 // Error if an incomplete order is returned.
22172226 if existingOrder != nil {
22182227 // Check to see if the expected fields of the existing order are set.
2219- // TODO(#7153): Check each value via core.IsAnyNilOrZero
2220- if existingOrder .Id == 0 || existingOrder .Status == "" || existingOrder .RegistrationID == 0 || len (existingOrder .DnsNames ) == 0 || core .IsAnyNilOrZero (existingOrder .Created , existingOrder .Expires ) {
2228+ if core .IsAnyNilOrZero (existingOrder .Id , existingOrder .Status , existingOrder .RegistrationID , existingOrder .DnsNames , existingOrder .Created , existingOrder .Expires ) {
22212229 return nil , errIncompleteGRPCResponse
22222230 }
22232231
0 commit comments