Skip to content

Commit 9ba099e

Browse files
authored
Revert "Use GetRevocationStatus instead of GetCertificateStatus" (#8426)
This reverts #8402 The revokedCertificates table does not have an index on the `serial` column, unlike the certificateStatus table. This means that these highly-targeted, single-certificate lookups are actually very inefficient, and led to performance problems in the database. This revert will be followed by a schema change to add an index to the revokedCertificates table, and then by a reland of the original PR. Part of #8322
1 parent eb56016 commit 9ba099e

File tree

9 files changed

+151
-87
lines changed

9 files changed

+151
-87
lines changed

core/objects.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,6 @@ var OCSPStatusToInt = map[OCSPStatus]int{
8383
OCSPStatusRevoked: ocsp.Revoked,
8484
}
8585

86-
const (
87-
RevocationStatusGood int64 = 0
88-
RevocationStatusRevoked int64 = 1
89-
)
90-
9186
// DNSPrefix is attached to DNS names in DNS challenges
9287
const DNSPrefix = "_acme-challenge"
9388

mocks/sa.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ func (sa *StorageAuthorityReadOnly) GetCertificateStatus(_ context.Context, req
213213

214214
// GetRevocationStatus is a mock
215215
func (sa *StorageAuthorityReadOnly) GetRevocationStatus(_ context.Context, req *sapb.Serial, _ ...grpc.CallOption) (*sapb.RevocationStatus, error) {
216-
return nil, errors.New("no revocation status")
216+
return nil, nil
217217
}
218218

219219
// SerialsForIncident is a mock

ra/ra.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1683,12 +1683,12 @@ func (ra *RegistrationAuthorityImpl) revokeCertificate(ctx context.Context, cert
16831683
// certificates that were previously revoked for a reason other than
16841684
// keyCompromise, and which are now being updated to keyCompromise instead.
16851685
func (ra *RegistrationAuthorityImpl) updateRevocationForKeyCompromise(ctx context.Context, serialString string, issuerID issuance.NameID) error {
1686-
status, err := ra.SA.GetRevocationStatus(ctx, &sapb.Serial{Serial: serialString})
1686+
status, err := ra.SA.GetCertificateStatus(ctx, &sapb.Serial{Serial: serialString})
16871687
if err != nil {
16881688
return berrors.NotFoundError("unable to confirm that serial %q was ever issued: %s", serialString, err)
16891689
}
16901690

1691-
if status.Status != core.RevocationStatusRevoked {
1691+
if status.Status != string(core.OCSPStatusRevoked) {
16921692
// Internal server error, because we shouldn't be in the function at all
16931693
// unless the cert was already revoked.
16941694
return fmt.Errorf("unable to re-revoke serial %q which is not currently revoked", serialString)

ra/ra_test.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3511,20 +3511,20 @@ type mockSARevocation struct {
35113511
sapb.StorageAuthorityClient
35123512

35133513
known map[string]*x509.Certificate
3514-
revoked map[string]*sapb.RevocationStatus
3514+
revoked map[string]*corepb.CertificateStatus
35153515
blocked []*sapb.AddBlockedKeyRequest
35163516
}
35173517

35183518
func newMockSARevocation(known *x509.Certificate) *mockSARevocation {
35193519
return &mockSARevocation{
35203520
known: map[string]*x509.Certificate{core.SerialToString(known.SerialNumber): known},
3521-
revoked: make(map[string]*sapb.RevocationStatus),
3521+
revoked: make(map[string]*corepb.CertificateStatus),
35223522
blocked: make([]*sapb.AddBlockedKeyRequest, 0),
35233523
}
35243524
}
35253525

35263526
func (msar *mockSARevocation) reset() {
3527-
msar.revoked = make(map[string]*sapb.RevocationStatus)
3527+
msar.revoked = make(map[string]*corepb.CertificateStatus)
35283528
msar.blocked = make([]*sapb.AddBlockedKeyRequest, 0)
35293529
}
35303530

@@ -3552,13 +3552,14 @@ func (msar *mockSARevocation) GetLintPrecertificate(_ context.Context, req *sapb
35523552
return nil, berrors.UnknownSerialError()
35533553
}
35543554

3555-
func (msar *mockSARevocation) GetRevocationStatus(_ context.Context, req *sapb.Serial, _ ...grpc.CallOption) (*sapb.RevocationStatus, error) {
3555+
func (msar *mockSARevocation) GetCertificateStatus(_ context.Context, req *sapb.Serial, _ ...grpc.CallOption) (*corepb.CertificateStatus, error) {
35563556
if status, present := msar.revoked[req.Serial]; present {
35573557
return status, nil
35583558
}
3559-
if _, present := msar.known[req.Serial]; present {
3560-
return &sapb.RevocationStatus{
3561-
Status: core.RevocationStatusGood,
3559+
if cert, present := msar.known[req.Serial]; present {
3560+
return &corepb.CertificateStatus{
3561+
Serial: core.SerialToString(cert.SerialNumber),
3562+
IssuerID: int64(issuance.IssuerNameID(cert)),
35623563
}, nil
35633564
}
35643565
return nil, berrors.UnknownSerialError()
@@ -3597,12 +3598,14 @@ func (msar *mockSARevocation) RevokeCertificate(_ context.Context, req *sapb.Rev
35973598
if _, present := msar.revoked[req.Serial]; present {
35983599
return nil, berrors.AlreadyRevokedError("already revoked")
35993600
}
3600-
_, present := msar.known[req.Serial]
3601+
cert, present := msar.known[req.Serial]
36013602
if !present {
36023603
return nil, berrors.UnknownSerialError()
36033604
}
3604-
msar.revoked[req.Serial] = &sapb.RevocationStatus{
3605-
Status: core.RevocationStatusRevoked,
3605+
msar.revoked[req.Serial] = &corepb.CertificateStatus{
3606+
Serial: req.Serial,
3607+
IssuerID: int64(issuance.IssuerNameID(cert)),
3608+
Status: string(core.OCSPStatusRevoked),
36063609
RevokedReason: req.Reason,
36073610
}
36083611
return &emptypb.Empty{}, nil
@@ -3769,7 +3772,7 @@ func TestRevokeCertByKey(t *testing.T) {
37693772

37703773
// Reset and have the Subscriber revoke for a different reason.
37713774
// Then re-revoking using the key should work.
3772-
mockSA.revoked = make(map[string]*sapb.RevocationStatus)
3775+
mockSA.revoked = make(map[string]*corepb.CertificateStatus)
37733776
_, err = ra.RevokeCertByApplicant(context.Background(), &rapb.RevokeCertByApplicantRequest{
37743777
Cert: cert.Raw,
37753778
Code: int64(revocation.Unspecified),

sa/model.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,41 @@ func SelectCertificateStatus(ctx context.Context, s db.OneSelector, serial strin
161161
return model.toPb(), err
162162
}
163163

164+
// RevocationStatusModel represents a small subset of the columns in the
165+
// certificateStatus table, used to determine the authoritative revocation
166+
// status of a certificate.
167+
type RevocationStatusModel struct {
168+
Status core.OCSPStatus `db:"status"`
169+
RevokedDate time.Time `db:"revokedDate"`
170+
RevokedReason revocation.Reason `db:"revokedReason"`
171+
}
172+
173+
// SelectRevocationStatus returns the authoritative revocation information for
174+
// the certificate with the given serial.
175+
func SelectRevocationStatus(ctx context.Context, s db.OneSelector, serial string) (*sapb.RevocationStatus, error) {
176+
var model RevocationStatusModel
177+
err := s.SelectOne(
178+
ctx,
179+
&model,
180+
"SELECT status, revokedDate, revokedReason FROM certificateStatus WHERE serial = ? LIMIT 1",
181+
serial,
182+
)
183+
if err != nil {
184+
return nil, err
185+
}
186+
187+
statusInt, ok := core.OCSPStatusToInt[model.Status]
188+
if !ok {
189+
return nil, fmt.Errorf("got unrecognized status %q", model.Status)
190+
}
191+
192+
return &sapb.RevocationStatus{
193+
Status: int64(statusInt),
194+
RevokedDate: timestamppb.New(model.RevokedDate),
195+
RevokedReason: int64(model.RevokedReason),
196+
}, nil
197+
}
198+
164199
var mediumBlobSize = int(math.Pow(2, 24))
165200

166201
type issuedNameModel struct {

sa/sa_test.go

Lines changed: 80 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -396,19 +396,15 @@ func TestAddPrecertificate(t *testing.T) {
396396
defer cleanUp()
397397

398398
reg := createWorkingRegistration(t, sa)
399-
regID := reg.Id
400399

401-
// Add a cert to the DB to test with.
400+
// Create a throw-away self signed certificate with a random name and
401+
// serial number
402402
serial, testCert := test.ThrowAwayCert(t, clk)
403-
_, err := sa.AddSerial(ctx, &sapb.AddSerialRequest{
404-
RegID: regID,
405-
Serial: serial,
406-
Created: timestamppb.New(testCert.NotBefore),
407-
Expires: timestamppb.New(testCert.NotAfter),
408-
})
409-
test.AssertNotError(t, err, "failed to add test serial")
403+
404+
// Add the cert as a precertificate
405+
regID := reg.Id
410406
issuedTime := mustTimestamp("2018-04-01 07:00")
411-
_, err = sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{
407+
_, err := sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{
412408
Der: testCert.Raw,
413409
RegID: regID,
414410
Issued: issuedTime,
@@ -417,9 +413,11 @@ func TestAddPrecertificate(t *testing.T) {
417413
test.AssertNotError(t, err, "Couldn't add test cert")
418414

419415
// It should have the expected certificate status
420-
certStatus, err := sa.GetRevocationStatus(ctx, &sapb.Serial{Serial: serial})
416+
certStatus, err := sa.GetCertificateStatus(ctx, &sapb.Serial{Serial: serial})
421417
test.AssertNotError(t, err, "Couldn't get status for test cert")
422-
test.AssertEquals(t, certStatus.Status, core.RevocationStatusGood)
418+
test.AssertEquals(t, certStatus.Status, string(core.OCSPStatusGood))
419+
now := clk.Now()
420+
test.AssertEquals(t, now, certStatus.OcspLastUpdated.AsTime())
423421

424422
// It should show up in the issued names table
425423
issuedNamesSerial, err := findIssuedName(ctx, sa.dbMap, reverseFQDN(testCert.DNSNames[0]))
@@ -1789,9 +1787,10 @@ func TestRevokeCertificate(t *testing.T) {
17891787
sa, fc, cleanUp := initSA(t)
17901788
defer cleanUp()
17911789

1792-
// Add a cert to the DB to test with.
17931790
reg := createWorkingRegistration(t, sa)
1791+
// Add a cert to the DB to test with.
17941792
serial, testCert := test.ThrowAwayCert(t, fc)
1793+
issuedTime := sa.clk.Now()
17951794
_, err := sa.AddSerial(ctx, &sapb.AddSerialRequest{
17961795
RegID: reg.Id,
17971796
Serial: core.SerialToString(testCert.SerialNumber),
@@ -1802,14 +1801,14 @@ func TestRevokeCertificate(t *testing.T) {
18021801
_, err = sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{
18031802
Der: testCert.Raw,
18041803
RegID: reg.Id,
1805-
Issued: timestamppb.New(testCert.NotBefore),
1804+
Issued: timestamppb.New(issuedTime),
18061805
IssuerNameID: 1,
18071806
})
18081807
test.AssertNotError(t, err, "Couldn't add test cert")
18091808

1810-
status, err := sa.GetRevocationStatus(ctx, &sapb.Serial{Serial: serial})
1809+
status, err := sa.GetCertificateStatus(ctx, &sapb.Serial{Serial: serial})
18111810
test.AssertNotError(t, err, "GetCertificateStatus failed")
1812-
test.AssertEquals(t, status.Status, core.RevocationStatusGood)
1811+
test.AssertEquals(t, core.OCSPStatus(status.Status), core.OCSPStatusGood)
18131812

18141813
fc.Add(1 * time.Hour)
18151814

@@ -1825,11 +1824,12 @@ func TestRevokeCertificate(t *testing.T) {
18251824
})
18261825
test.AssertNotError(t, err, "RevokeCertificate with no OCSP response should succeed")
18271826

1828-
status, err = sa.GetRevocationStatus(ctx, &sapb.Serial{Serial: serial})
1827+
status, err = sa.GetCertificateStatus(ctx, &sapb.Serial{Serial: serial})
18291828
test.AssertNotError(t, err, "GetCertificateStatus failed")
1830-
test.AssertEquals(t, status.Status, core.RevocationStatusRevoked)
1829+
test.AssertEquals(t, core.OCSPStatus(status.Status), core.OCSPStatusRevoked)
18311830
test.AssertEquals(t, status.RevokedReason, reason)
18321831
test.AssertEquals(t, status.RevokedDate.AsTime(), now)
1832+
test.AssertEquals(t, status.OcspLastUpdated.AsTime(), now)
18331833

18341834
_, err = sa.RevokeCertificate(context.Background(), &sapb.RevokeCertificateRequest{
18351835
IssuerID: 1,
@@ -1840,13 +1840,67 @@ func TestRevokeCertificate(t *testing.T) {
18401840
test.AssertError(t, err, "RevokeCertificate should've failed when certificate already revoked")
18411841
}
18421842

1843+
func TestRevokeCertificateWithShard(t *testing.T) {
1844+
sa, fc, cleanUp := initSA(t)
1845+
defer cleanUp()
1846+
1847+
// Add a cert to the DB to test with.
1848+
reg := createWorkingRegistration(t, sa)
1849+
eeCert, err := core.LoadCert("../test/hierarchy/ee-e1.cert.pem")
1850+
test.AssertNotError(t, err, "failed to load test cert")
1851+
_, err = sa.AddSerial(ctx, &sapb.AddSerialRequest{
1852+
RegID: reg.Id,
1853+
Serial: core.SerialToString(eeCert.SerialNumber),
1854+
Created: timestamppb.New(eeCert.NotBefore),
1855+
Expires: timestamppb.New(eeCert.NotAfter),
1856+
})
1857+
test.AssertNotError(t, err, "failed to add test serial")
1858+
_, err = sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{
1859+
Der: eeCert.Raw,
1860+
RegID: reg.Id,
1861+
Issued: timestamppb.New(eeCert.NotBefore),
1862+
IssuerNameID: 1,
1863+
})
1864+
test.AssertNotError(t, err, "failed to add test cert")
1865+
1866+
serial := core.SerialToString(eeCert.SerialNumber)
1867+
fc.Add(1 * time.Hour)
1868+
now := fc.Now()
1869+
reason := int64(1)
1870+
1871+
_, err = sa.RevokeCertificate(context.Background(), &sapb.RevokeCertificateRequest{
1872+
IssuerID: 1,
1873+
ShardIdx: 9,
1874+
Serial: serial,
1875+
Date: timestamppb.New(now),
1876+
Reason: reason,
1877+
})
1878+
test.AssertNotError(t, err, "RevokeCertificate with no OCSP response should succeed")
1879+
1880+
status, err := sa.GetCertificateStatus(ctx, &sapb.Serial{Serial: serial})
1881+
test.AssertNotError(t, err, "GetCertificateStatus failed")
1882+
test.AssertEquals(t, core.OCSPStatus(status.Status), core.OCSPStatusRevoked)
1883+
test.AssertEquals(t, status.RevokedReason, reason)
1884+
test.AssertEquals(t, status.RevokedDate.AsTime(), now)
1885+
test.AssertEquals(t, status.OcspLastUpdated.AsTime(), now)
1886+
test.AssertEquals(t, status.NotAfter.AsTime(), eeCert.NotAfter)
1887+
1888+
var result revokedCertModel
1889+
err = sa.dbMap.SelectOne(
1890+
ctx, &result, `SELECT * FROM revokedCertificates WHERE serial = ?`, core.SerialToString(eeCert.SerialNumber))
1891+
test.AssertNotError(t, err, "should be exactly one row in revokedCertificates")
1892+
test.AssertEquals(t, result.ShardIdx, int64(9))
1893+
test.AssertEquals(t, result.RevokedReason, revocation.KeyCompromise)
1894+
}
1895+
18431896
func TestUpdateRevokedCertificate(t *testing.T) {
18441897
sa, fc, cleanUp := initSA(t)
18451898
defer cleanUp()
18461899

18471900
// Add a cert to the DB to test with.
18481901
reg := createWorkingRegistration(t, sa)
18491902
serial, testCert := test.ThrowAwayCert(t, fc)
1903+
issuedTime := fc.Now()
18501904
_, err := sa.AddSerial(ctx, &sapb.AddSerialRequest{
18511905
RegID: reg.Id,
18521906
Serial: core.SerialToString(testCert.SerialNumber),
@@ -1857,7 +1911,7 @@ func TestUpdateRevokedCertificate(t *testing.T) {
18571911
_, err = sa.AddPrecertificate(ctx, &sapb.AddCertificateRequest{
18581912
Der: testCert.Raw,
18591913
RegID: reg.Id,
1860-
Issued: timestamppb.New(testCert.NotBefore),
1914+
Issued: timestamppb.New(issuedTime),
18611915
IssuerNameID: 1,
18621916
})
18631917
test.AssertNotError(t, err, "Couldn't add test cert")
@@ -1890,10 +1944,10 @@ func TestUpdateRevokedCertificate(t *testing.T) {
18901944
test.AssertNotError(t, err, "RevokeCertificate failed")
18911945

18921946
// Double check that setup worked.
1893-
status, err := sa.GetRevocationStatus(ctx, &sapb.Serial{Serial: serial})
1947+
status, err := sa.GetCertificateStatus(ctx, &sapb.Serial{Serial: serial})
18941948
test.AssertNotError(t, err, "GetCertificateStatus failed")
1895-
test.AssertEquals(t, status.Status, core.RevocationStatusRevoked)
1896-
test.AssertEquals(t, status.RevokedReason, int64(revocation.CessationOfOperation))
1949+
test.AssertEquals(t, core.OCSPStatus(status.Status), core.OCSPStatusRevoked)
1950+
test.AssertEquals(t, revocation.Reason(status.RevokedReason), revocation.CessationOfOperation)
18971951
fc.Add(1 * time.Hour)
18981952

18991953
// Try to update its revocation info with no backdate
@@ -2946,10 +3000,10 @@ func TestGetRevokedCerts(t *testing.T) {
29463000
test.AssertNotError(t, err, "failed to add test cert")
29473001

29483002
// Check that it worked.
2949-
status, err := sa.GetRevocationStatus(
3003+
status, err := sa.GetCertificateStatus(
29503004
ctx, &sapb.Serial{Serial: core.SerialToString(eeCert.SerialNumber)})
29513005
test.AssertNotError(t, err, "GetCertificateStatus failed")
2952-
test.AssertEquals(t, status.Status, core.RevocationStatusGood)
3006+
test.AssertEquals(t, core.OCSPStatus(status.Status), core.OCSPStatusGood)
29533007

29543008
// Here's a little helper func we'll use to call GetRevokedCerts and count
29553009
// how many results it returned.
@@ -3053,10 +3107,10 @@ func TestGetRevokedCertsByShard(t *testing.T) {
30533107
test.AssertNotError(t, err, "failed to add test cert")
30543108

30553109
// Check that it worked.
3056-
status, err := sa.GetRevocationStatus(
3110+
status, err := sa.GetCertificateStatus(
30573111
ctx, &sapb.Serial{Serial: core.SerialToString(eeCert.SerialNumber)})
30583112
test.AssertNotError(t, err, "GetCertificateStatus failed")
3059-
test.AssertEquals(t, status.Status, core.RevocationStatusGood)
3113+
test.AssertEquals(t, core.OCSPStatus(status.Status), core.OCSPStatusGood)
30603114

30613115
// Here's a little helper func we'll use to call GetRevokedCertsByShard and count
30623116
// how many results it returned.

0 commit comments

Comments
 (0)