@@ -25,6 +25,7 @@ import (
2525 "github.com/letsencrypt/boulder/features"
2626 bgrpc "github.com/letsencrypt/boulder/grpc"
2727 blog "github.com/letsencrypt/boulder/log"
28+ "github.com/letsencrypt/boulder/probs"
2829 "github.com/letsencrypt/boulder/revocation"
2930 sapb "github.com/letsencrypt/boulder/sa/proto"
3031 "github.com/letsencrypt/boulder/unpause"
@@ -947,6 +948,11 @@ func (ssa *SQLStorageAuthority) FinalizeAuthorization2(ctx context.Context, req
947948 if req .Status != string (core .StatusValid ) && req .Status != string (core .StatusInvalid ) {
948949 return nil , berrors .InternalServerError ("authorization must have status valid or invalid" )
949950 }
951+
952+ if features .Get ().WriteNewOrderSchema && looksLikeRandomID (req .Id , ssa .clk .Now ()) {
953+ return ssa .finalizeAuthorization (ctx , req )
954+ }
955+
950956 query := `UPDATE authz2 SET
951957 status = :status,
952958 attempted = :attempted,
@@ -1022,6 +1028,107 @@ func (ssa *SQLStorageAuthority) FinalizeAuthorization2(ctx context.Context, req
10221028 return & emptypb.Empty {}, nil
10231029}
10241030
1031+ // finalizeAuthorization inserts a new validation record into the validations
1032+ // table, and then updates the identified authorizations row to point to the
1033+ // newly-inserted validation.
1034+ func (ssa * SQLStorageAuthority ) finalizeAuthorization (ctx context.Context , req * sapb.FinalizeAuthorizationRequest ) (* emptypb.Empty , error ) {
1035+ // Convert the validation records and error to a json blob for storage in
1036+ // the validations table.
1037+ type recordJSON struct {
1038+ Records []core.ValidationRecord
1039+ Err * probs.ProblemDetails
1040+ }
1041+
1042+ var records []core.ValidationRecord
1043+ for _ , recPB := range req .ValidationRecords {
1044+ rec , err := bgrpc .PBToValidationRecord (recPB )
1045+ if err != nil {
1046+ return nil , err
1047+ }
1048+ records = append (records , rec )
1049+ }
1050+
1051+ var verr * probs.ProblemDetails
1052+ if req .ValidationError != nil {
1053+ verrShadow , err := bgrpc .PBToProblemDetails (req .ValidationError )
1054+ if err != nil {
1055+ return nil , err
1056+ }
1057+ verr = verrShadow
1058+ }
1059+
1060+ record , err := json .Marshal (recordJSON {Records : records , Err : verr })
1061+ if err != nil {
1062+ return nil , fmt .Errorf ("failed to convert validation record to json: %w" , err )
1063+ }
1064+
1065+ id , err := newRandomID (ssa .clk .Now ())
1066+ if err != nil {
1067+ return nil , err
1068+ }
1069+
1070+ vm := validationsModel {
1071+ ID : id ,
1072+ Challenge : challTypeToUint [req .Attempted ],
1073+ AttemptedAt : req .AttemptedAt .AsTime (),
1074+ Status : statusUint (core .AcmeStatus (req .Status )),
1075+ Record : record ,
1076+ }
1077+
1078+ _ , overallError := db .WithTransaction (ctx , ssa .dbMap , func (tx db.Executor ) (interface {}, error ) {
1079+ // Read the authz row to get its current status and list of validation IDs.
1080+ var authz authorizationsModel
1081+ err := tx .SelectOne (ctx , & authz , "SELECT status, validationIDs FROM authorizations WHERE id = ?" , req .Id )
1082+ if err != nil {
1083+ return nil , fmt .Errorf ("retrieving authz: %w" , err )
1084+ }
1085+
1086+ if authz .Status != statusUint (core .StatusPending ) {
1087+ return nil , fmt .Errorf ("cannot finalize authz with status %q" , uintToStatus [authz .Status ])
1088+ }
1089+
1090+ // Insert the validation record.
1091+ err = tx .Insert (ctx , vm )
1092+ if err != nil {
1093+ return nil , fmt .Errorf ("inserting new validation: %w" , err )
1094+ }
1095+
1096+ // Update the authz row.
1097+ res , err := tx .ExecContext (
1098+ ctx , "UPDATE authorizations SET validationIDs = ? WHERE id = ? AND validationIDs = ?" ,
1099+ append (authz .ValidationIDs [:], vm .ID ), req .Id , authz .ValidationIDs )
1100+ if err != nil {
1101+ return nil , fmt .Errorf ("updating authz: %w" , err )
1102+ }
1103+ rows , err := res .RowsAffected ()
1104+ if err != nil {
1105+ return nil , err
1106+ }
1107+ if rows != 1 {
1108+ return nil , fmt .Errorf ("unexpected number of rows affected (%d)" , rows )
1109+ }
1110+
1111+ // Delete the orderFQDNSet row for the order now that it has been finalized.
1112+ // We use this table for order reuse and should not reuse a finalized order.
1113+ err = deleteOrderFQDNSet (ctx , tx , req .Id )
1114+ if err != nil {
1115+ return nil , err
1116+ }
1117+
1118+ err = setReplacementOrderFinalized (ctx , tx , req .Id )
1119+ if err != nil {
1120+ return nil , err
1121+ }
1122+
1123+ return nil , nil
1124+ })
1125+ if overallError != nil {
1126+ return nil , overallError
1127+ }
1128+
1129+ return & emptypb.Empty {}, nil
1130+ }
1131+
10251132// addRevokedCertificate is a helper used by both RevokeCertificate and
10261133// UpdateRevokedCertificate. It inserts a new row into the revokedCertificates
10271134// table based on the contents of the input request. The second argument must be
0 commit comments