@@ -786,15 +786,34 @@ func addRevokedCertificate(ctx context.Context, tx db.Executor, req *sapb.Revoke
786786 return errors .New ("cannot add revoked certificate with shard index 0" )
787787 }
788788
789+ // If this serial already exists in the revokedCertificates table, then the
790+ // certificate has already been revoked. The RA has special logic for that
791+ // case, so return the specific error that the RA is looking for.
792+ var row struct {
793+ Count int64
794+ }
795+ err := tx .SelectOne (ctx , & row , "SELECT COUNT(*) as count FROM revokedCertificates WHERE serial = ?" , req .Serial )
796+ if err != nil {
797+ return fmt .Errorf ("checking if certificate is already revoked: %w" , err )
798+ }
799+ if row .Count > 0 {
800+ return berrors .AlreadyRevokedError ("serial %s already in revokedCertificates table" , req .Serial )
801+ }
802+
803+ // The revokedCertificates table includes each cert's notAfter to make it easy
804+ // for crl-updater to stop including entries after they've expired, so we need
805+ // to look up that value.
789806 var serial struct {
790807 Expires time.Time
791808 }
792- err := tx .SelectOne (
793- ctx , & serial , `SELECT expires FROM serials WHERE serial = ?` , req .Serial )
809+ err = tx .SelectOne (ctx , & serial , `SELECT expires FROM serials WHERE serial = ?` , req .Serial )
794810 if err != nil {
795811 return fmt .Errorf ("retrieving revoked certificate expiration: %w" , err )
796812 }
797813
814+ // We're guaranteed that this won't be a duplicate insert because we've
815+ // already checked for existence of a row with the same serial above, in the
816+ // same transaction.
798817 err = tx .Insert (ctx , & revokedCertModel {
799818 IssuerID : req .IssuerID ,
800819 Serial : req .Serial ,
@@ -806,12 +825,6 @@ func addRevokedCertificate(ctx context.Context, tx db.Executor, req *sapb.Revoke
806825 NotAfterHour : serial .Expires .Add (time .Hour ).Truncate (time .Hour ),
807826 })
808827 if err != nil {
809- if db .IsDuplicate (err ) {
810- // An attempted duplicate insert means that this certificate was already
811- // revoked. The RA has special logic for that case, so use the specific
812- // error for it.
813- return berrors .AlreadyRevokedError ("certificate with serial %s already in revokedCertificates table" , req .Serial )
814- }
815828 return fmt .Errorf ("inserting revoked certificate row: %w" , err )
816829 }
817830
0 commit comments