@@ -108,7 +108,7 @@ func (ssa *SQLStorageAuthority) NewRegistration(ctx context.Context, req *corepb
108108 return nil , err
109109 }
110110
111- reg .CreatedAt = ssa .clk .Now ()
111+ reg .CreatedAt = ssa .clk .Now (). Truncate ( time . Second )
112112
113113 err = ssa .dbMap .Insert (ctx , reg )
114114 if err != nil {
@@ -141,6 +141,10 @@ func (ssa *SQLStorageAuthority) UpdateRegistration(ctx context.Context, req *cor
141141 return nil , err
142142 }
143143
144+ // The CreatedAt field shouldn't change from the original, so we copy it straight through.
145+ // This also ensures that it's already truncated to second (which happened on creation).
146+ update .CreatedAt = curr .CreatedAt
147+
144148 // Copy the existing registration model's LockCol to the new updated
145149 // registration model's LockCol
146150 update .LockCol = curr .LockCol
@@ -169,8 +173,8 @@ func (ssa *SQLStorageAuthority) AddSerial(ctx context.Context, req *sapb.AddSeri
169173 err := ssa .dbMap .Insert (ctx , & recordedSerialModel {
170174 Serial : req .Serial ,
171175 RegistrationID : req .RegID ,
172- Created : req .Created .AsTime (),
173- Expires : req .Expires .AsTime (),
176+ Created : req .Created .AsTime (). Truncate ( time . Second ) ,
177+ Expires : req .Expires .AsTime (). Truncate ( time . Second ) ,
174178 })
175179 if err != nil {
176180 return nil , err
@@ -223,7 +227,7 @@ func (ssa *SQLStorageAuthority) AddPrecertificate(ctx context.Context, req *sapb
223227 Serial : serialHex ,
224228 RegistrationID : req .RegID ,
225229 DER : req .Der ,
226- Issued : req .Issued .AsTime (),
230+ Issued : req .Issued .AsTime (). Truncate ( time . Second ) ,
227231 Expires : parsed .NotAfter ,
228232 }
229233
@@ -252,13 +256,15 @@ func (ssa *SQLStorageAuthority) AddPrecertificate(ctx context.Context, req *sapb
252256 cs := & core.CertificateStatus {
253257 Serial : serialHex ,
254258 Status : status ,
255- OCSPLastUpdated : ssa .clk .Now (),
259+ OCSPLastUpdated : ssa .clk .Now (). Truncate ( time . Second ) ,
256260 RevokedDate : time.Time {},
257261 RevokedReason : 0 ,
258262 LastExpirationNagSent : time.Time {},
259- NotAfter : parsed .NotAfter ,
260- IsExpired : false ,
261- IssuerNameID : req .IssuerNameID ,
263+ // No need to truncate because it's already truncated to encode
264+ // per https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.5.1
265+ NotAfter : parsed .NotAfter ,
266+ IsExpired : false ,
267+ IssuerNameID : req .IssuerNameID ,
262268 }
263269 err = ssa .dbMap .Insert (ctx , cs )
264270 if err != nil {
@@ -317,7 +323,7 @@ func (ssa *SQLStorageAuthority) AddCertificate(ctx context.Context, req *sapb.Ad
317323 Serial : serial ,
318324 Digest : digest ,
319325 DER : req .Der ,
320- Issued : req .Issued .AsTime (),
326+ Issued : req .Issued .AsTime (). Truncate ( time . Second ) ,
321327 Expires : parsedCertificate .NotAfter ,
322328 }
323329
@@ -476,13 +482,15 @@ func (ssa *SQLStorageAuthority) NewOrderAndAuthzs(ctx context.Context, req *sapb
476482 if err != nil {
477483 return nil , err
478484 }
485+ // These parameters correspond to the fields listed in `authzFields`, as used in the
486+ // `db.NewMultiInserter` call above, and occur in the same order.
479487 err = inserter .Add ([]interface {}{
480488 am .ID ,
481489 am .IdentifierType ,
482490 am .IdentifierValue ,
483491 am .RegistrationID ,
484492 statusToUint [core .StatusPending ],
485- am .Expires ,
493+ am .Expires . Truncate ( time . Second ) ,
486494 am .Challenges ,
487495 nil ,
488496 nil ,
@@ -503,11 +511,12 @@ func (ssa *SQLStorageAuthority) NewOrderAndAuthzs(ctx context.Context, req *sapb
503511 // Second, insert the new order.
504512 var orderID int64
505513 var err error
506- created := ssa .clk .Now ()
514+ created := ssa .clk .Now ().Truncate (time .Second )
515+ expires := req .NewOrder .Expires .AsTime ().Truncate (time .Second )
507516 if features .Get ().MultipleCertificateProfiles {
508517 omv2 := orderModelv2 {
509518 RegistrationID : req .NewOrder .RegistrationID ,
510- Expires : req . NewOrder . Expires . AsTime () ,
519+ Expires : expires ,
511520 Created : created ,
512521 CertificateProfileName : req .NewOrder .CertificateProfileName ,
513522 }
@@ -516,7 +525,7 @@ func (ssa *SQLStorageAuthority) NewOrderAndAuthzs(ctx context.Context, req *sapb
516525 } else {
517526 omv1 := orderModelv1 {
518527 RegistrationID : req .NewOrder .RegistrationID ,
519- Expires : req . NewOrder . Expires . AsTime () ,
528+ Expires : expires ,
520529 Created : created ,
521530 }
522531 err = tx .Insert (ctx , & omv1 )
@@ -549,19 +558,25 @@ func (ssa *SQLStorageAuthority) NewOrderAndAuthzs(ctx context.Context, req *sapb
549558 }
550559
551560 // Fourth, insert the FQDNSet entry for the order.
552- err = addOrderFQDNSet (ctx , tx , req .NewOrder .Names , orderID , req .NewOrder .RegistrationID , req .NewOrder .Expires .AsTime ())
561+ err = addOrderFQDNSet (ctx ,
562+ tx ,
563+ req .NewOrder .Names ,
564+ orderID ,
565+ req .NewOrder .RegistrationID ,
566+ expires ,
567+ )
553568 if err != nil {
554569 return nil , err
555570 }
556571
557- // Finally, build the overall Order PB.
572+ // Finally, build the overall Order PB to return .
558573 res := & corepb.Order {
559574 // ID and Created were auto-populated on the order model when it was inserted.
560575 Id : orderID ,
561576 Created : timestamppb .New (created ),
562577 // These are carried over from the original request unchanged.
563578 RegistrationID : req .NewOrder .RegistrationID ,
564- Expires : req . NewOrder . Expires ,
579+ Expires : timestamppb . New ( expires ) ,
565580 Names : req .NewOrder .Names ,
566581 // Have to combine the already-associated and newly-reacted authzs.
567582 V2Authorizations : append (req .NewOrder .V2Authorizations , newAuthzIDs ... ),
@@ -576,7 +591,12 @@ func (ssa *SQLStorageAuthority) NewOrderAndAuthzs(ctx context.Context, req *sapb
576591 if req .NewOrder .ReplacesSerial != "" {
577592 // Update the replacementOrders table to indicate that this order
578593 // replaces the provided certificate serial.
579- err := addReplacementOrder (ctx , tx , req .NewOrder .ReplacesSerial , orderID , req .NewOrder .Expires .AsTime ())
594+ err := addReplacementOrder (ctx ,
595+ tx ,
596+ req .NewOrder .ReplacesSerial ,
597+ orderID ,
598+ req .NewOrder .Expires .AsTime ().Truncate (time .Second ),
599+ )
580600 if err != nil {
581601 return nil , err
582602 }
@@ -789,7 +809,7 @@ func (ssa *SQLStorageAuthority) FinalizeAuthorization2(ctx context.Context, req
789809 // database attemptedAt field Null instead of 1970-01-01 00:00:00.
790810 var attemptedTime * time.Time
791811 if ! core .IsAnyNilOrZero (req .AttemptedAt ) {
792- val := req .AttemptedAt .AsTime ()
812+ val := req .AttemptedAt .AsTime (). Truncate ( time . Second )
793813 attemptedTime = & val
794814 }
795815 params := map [string ]interface {}{
@@ -799,7 +819,7 @@ func (ssa *SQLStorageAuthority) FinalizeAuthorization2(ctx context.Context, req
799819 "validationRecord" : vrJSON ,
800820 "id" : req .Id ,
801821 "pending" : statusUint (core .StatusPending ),
802- "expires" : req .Expires .AsTime (),
822+ "expires" : req .Expires .AsTime (). Truncate ( time . Second ) ,
803823 // if req.ValidationError is nil veJSON should also be nil
804824 // which should result in a NULL field
805825 "validationError" : veJSON ,
@@ -867,7 +887,7 @@ func (ssa *SQLStorageAuthority) RevokeCertificate(ctx context.Context, req *sapb
867887 }
868888
869889 _ , overallError := db .WithTransaction (ctx , ssa .dbMap , func (tx db.Executor ) (interface {}, error ) {
870- revokedDate := req .Date .AsTime ()
890+ revokedDate := req .Date .AsTime (). Truncate ( time . Second )
871891
872892 res , err := tx .ExecContext (ctx ,
873893 `UPDATE certificateStatus SET
@@ -924,8 +944,8 @@ func (ssa *SQLStorageAuthority) UpdateRevokedCertificate(ctx context.Context, re
924944 }
925945
926946 _ , overallError := db .WithTransaction (ctx , ssa .dbMap , func (tx db.Executor ) (interface {}, error ) {
927- thisUpdate := req .Date .AsTime ()
928- revokedDate := req .Backdate .AsTime ()
947+ thisUpdate := req .Date .AsTime (). Truncate ( time . Second )
948+ revokedDate := req .Backdate .AsTime (). Truncate ( time . Second )
929949
930950 res , err := tx .ExecContext (ctx ,
931951 `UPDATE certificateStatus SET
@@ -1007,7 +1027,7 @@ func (ssa *SQLStorageAuthority) AddBlockedKey(ctx context.Context, req *sapb.Add
10071027 cols , qs := blockedKeysColumns , "?, ?, ?, ?"
10081028 vals := []interface {}{
10091029 req .KeyHash ,
1010- req .Added .AsTime (),
1030+ req .Added .AsTime (). Truncate ( time . Second ) ,
10111031 sourceInt ,
10121032 req .Comment ,
10131033 }
@@ -1232,7 +1252,10 @@ func (ssa *SQLStorageAuthority) leaseSpecificCRLShard(ctx context.Context, req *
12321252
12331253// UpdateCRLShard updates the thisUpdate and nextUpdate timestamps of a CRL
12341254// shard. It rejects the update if it would cause the thisUpdate timestamp to
1235- // move backwards. It does *not* reject the update if the shard is no longer
1255+ // move backwards, but if thisUpdate would stay the same (for instance, multiple
1256+ // CRL generations within a single second), it will succeed.
1257+ //
1258+ // It does *not* reject the update if the shard is no longer
12361259// leased: although this would be unexpected (because the lease timestamp should
12371260// be the same as the crl-updater's context expiration), it's not inherently a
12381261// sign of an update that should be skipped. It does reject the update if the
@@ -1247,24 +1270,25 @@ func (ssa *SQLStorageAuthority) UpdateCRLShard(ctx context.Context, req *sapb.Up
12471270 // Only set the nextUpdate if it's actually present in the request message.
12481271 var nextUpdate * time.Time
12491272 if req .NextUpdate != nil {
1250- nut := req .NextUpdate .AsTime ()
1273+ nut := req .NextUpdate .AsTime (). Truncate ( time . Second )
12511274 nextUpdate = & nut
12521275 }
12531276
12541277 _ , err := db .WithTransaction (ctx , ssa .dbMap , func (tx db.Executor ) (interface {}, error ) {
1278+ thisUpdate := req .ThisUpdate .AsTime ().Truncate (time .Second )
12551279 res , err := tx .ExecContext (ctx ,
12561280 `UPDATE crlShards
12571281 SET thisUpdate = ?, nextUpdate = ?, leasedUntil = ?
12581282 WHERE issuerID = ?
12591283 AND idx = ?
1260- AND (thisUpdate is NULL OR thisUpdate < ?)
1284+ AND (thisUpdate is NULL OR thisUpdate <= ?)
12611285 LIMIT 1` ,
1262- req . ThisUpdate . AsTime () ,
1286+ thisUpdate ,
12631287 nextUpdate ,
1264- req . ThisUpdate . AsTime () ,
1288+ thisUpdate ,
12651289 req .IssuerNameID ,
12661290 req .ShardIdx ,
1267- req . ThisUpdate . AsTime () ,
1291+ thisUpdate ,
12681292 )
12691293 if err != nil {
12701294 return nil , err
@@ -1275,7 +1299,7 @@ func (ssa *SQLStorageAuthority) UpdateCRLShard(ctx context.Context, req *sapb.Up
12751299 return nil , err
12761300 }
12771301 if rowsAffected == 0 {
1278- return nil , fmt .Errorf ("unable to update shard %d for issuer %d" , req .ShardIdx , req .IssuerNameID )
1302+ return nil , fmt .Errorf ("unable to update shard %d for issuer %d; possibly because shard exists " , req .ShardIdx , req .IssuerNameID )
12791303 }
12801304 if rowsAffected != 1 {
12811305 return nil , errors .New ("update affected unexpected number of rows" )
0 commit comments