Skip to content

Commit ed310ff

Browse files
authored
Merge branch 'main' into drop-tables
2 parents ed87e74 + 635f432 commit ed310ff

File tree

15 files changed

+291
-209
lines changed

15 files changed

+291
-209
lines changed

.github/workflows/release.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ jobs:
1919
runs-on: ubuntu-20.04
2020
permissions:
2121
contents: write
22+
packages: write
2223
steps:
2324
- uses: actions/checkout@v4
2425
with:

cmd/boulder-wfe2/main.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,19 @@ type Config struct {
4242
TLSListenAddress string `validate:"omitempty,hostname_port"`
4343

4444
// Timeout is the per-request overall timeout. This should be slightly
45-
// lower than the upstream's timeout when making requests to the WFE.
45+
// lower than the upstream's timeout when making requests to this service.
4646
Timeout config.Duration `validate:"-"`
4747

48+
// ShutdownStopTimeout determines the maximum amount of time to wait
49+
// for extant request handlers to complete before exiting. It should be
50+
// greater than Timeout.
51+
ShutdownStopTimeout config.Duration
52+
4853
ServerCertificatePath string `validate:"required_with=TLSListenAddress"`
4954
ServerKeyPath string `validate:"required_with=TLSListenAddress"`
5055

5156
AllowOrigins []string
5257

53-
ShutdownStopTimeout config.Duration
54-
5558
SubscriberAgreementURL string
5659

5760
TLS cmd.TLSConfig

cmd/ocsp-responder/main.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,15 @@ type Config struct {
5151
// OCSP requests. This has a default value of ":80".
5252
ListenAddress string `validate:"omitempty,hostname_port"`
5353

54-
// When to timeout a request. This should be slightly lower than the
55-
// upstream's timeout when making request to ocsp-responder.
54+
// Timeout is the per-request overall timeout. This should be slightly
55+
// lower than the upstream's timeout when making requests to this service.
5656
Timeout config.Duration `validate:"-"`
5757

58+
// ShutdownStopTimeout determines the maximum amount of time to wait
59+
// for extant request handlers to complete before exiting. It should be
60+
// greater than Timeout.
61+
ShutdownStopTimeout config.Duration
62+
5863
// How often a response should be signed when using Redis/live-signing
5964
// path. This has a default value of 60h.
6065
LiveSigningPeriod config.Duration `validate:"-"`
@@ -80,8 +85,6 @@ type Config struct {
8085
// 40 * 5 / 0.02 = 10,000 requests before the oldest request times out.
8186
MaxSigningWaiters int `validate:"min=0"`
8287

83-
ShutdownStopTimeout config.Duration
84-
8588
RequiredSerialPrefixes []string `validate:"omitempty,dive,hexadecimal"`
8689

8790
Features features.Config

cmd/sfe/main.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,12 @@ type Config struct {
2525
ListenAddress string `validate:"omitempty,hostname_port"`
2626

2727
// Timeout is the per-request overall timeout. This should be slightly
28-
// lower than the upstream's timeout when making requests to the SFE.
28+
// lower than the upstream's timeout when making requests to this service.
2929
Timeout config.Duration `validate:"-"`
3030

31-
// ShutdownStopTimeout is the duration that the SFE will wait before
32-
// shutting down any listening servers.
31+
// ShutdownStopTimeout determines the maximum amount of time to wait
32+
// for extant request handlers to complete before exiting. It should be
33+
// greater than Timeout.
3334
ShutdownStopTimeout config.Duration
3435

3536
TLS cmd.TLSConfig

ra/ra.go

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -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 {
11191141
func (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

ra/ra_test.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3295,7 +3295,7 @@ func TestIssueCertificateInnerErrs(t *testing.T) {
32953295
// Mock the CA
32963296
ra.CA = tc.Mock
32973297
// Attempt issuance
3298-
_, _, err = ra.issueCertificateInner(ctx, csrOb, order.CertificateProfileName, accountID(Registration.Id), orderID(order.Id))
3298+
_, _, err = ra.issueCertificateInner(ctx, csrOb, false, order.CertificateProfileName, accountID(Registration.Id), orderID(order.Id))
32993299
// We expect all of the testcases to fail because all use mocked CAs that deliberately error
33003300
test.AssertError(t, err, "issueCertificateInner with failing mock CA did not fail")
33013301
// If there is an expected `error` then match the error message
@@ -3338,8 +3338,12 @@ func (sa *mockSAWithFinalize) FinalizeOrder(ctx context.Context, req *sapb.Final
33383338
return &emptypb.Empty{}, nil
33393339
}
33403340

3341-
func (sa *mockSAWithFinalize) FQDNSetExists(ctx context.Context, in *sapb.FQDNSetExistsRequest, opts ...grpc.CallOption) (*sapb.Exists, error) {
3342-
return &sapb.Exists{}, nil
3341+
func (sa *mockSAWithFinalize) FQDNSetTimestampsForWindow(ctx context.Context, in *sapb.CountFQDNSetsRequest, opts ...grpc.CallOption) (*sapb.Timestamps, error) {
3342+
return &sapb.Timestamps{
3343+
Timestamps: []*timestamppb.Timestamp{
3344+
timestamppb.Now(),
3345+
},
3346+
}, nil
33433347
}
33443348

33453349
func TestIssueCertificateInnerWithProfile(t *testing.T) {
@@ -3372,7 +3376,7 @@ func TestIssueCertificateInnerWithProfile(t *testing.T) {
33723376

33733377
// Call issueCertificateInner with the CSR generated above and the profile
33743378
// name "default", which will cause the mockCA to return a specific hash.
3375-
_, cpId, err := ra.issueCertificateInner(context.Background(), csr, "default", 1, 1)
3379+
_, cpId, err := ra.issueCertificateInner(context.Background(), csr, false, "default", 1, 1)
33763380
test.AssertNotError(t, err, "issuing cert with profile name")
33773381
test.AssertEquals(t, mockCA.profileName, cpId.name)
33783382
test.AssertByteEquals(t, mockCA.profileHash, cpId.hash)

sa/db/boulder_sa/20230419000000_CombinedSchema.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ CREATE TABLE `fqdnSets` (
8686
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
8787
`setHash` binary(32) NOT NULL,
8888
`serial` varchar(255) NOT NULL,
89+
-- Note: This should actually be called "notBefore" since it is set
90+
-- based on the certificate's notBefore field, not the issuance time.
8991
`issued` datetime NOT NULL,
9092
`expires` datetime NOT NULL,
9193
PRIMARY KEY (`id`),

sa/model.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,8 @@ type orderModelv1 struct {
392392
BeganProcessing bool
393393
}
394394

395+
// orderModelv2 represents one row in the orders table. The
396+
// CertificateProfileName column is a pointer because the column is NULL-able.
395397
type orderModelv2 struct {
396398
ID int64
397399
RegistrationID int64
@@ -400,7 +402,7 @@ type orderModelv2 struct {
400402
Error []byte
401403
CertificateSerial string
402404
BeganProcessing bool
403-
CertificateProfileName string
405+
CertificateProfileName *string
404406
}
405407

406408
type orderToAuthzModel struct {
@@ -457,14 +459,17 @@ func modelToOrderv1(om *orderModelv1) (*corepb.Order, error) {
457459
}
458460

459461
func orderToModelv2(order *corepb.Order) (*orderModelv2, error) {
462+
// Make a local copy so we can take a reference to it below.
463+
profile := order.CertificateProfileName
464+
460465
om := &orderModelv2{
461466
ID: order.Id,
462467
RegistrationID: order.RegistrationID,
463468
Expires: order.Expires.AsTime(),
464469
Created: order.Created.AsTime(),
465470
BeganProcessing: order.BeganProcessing,
466471
CertificateSerial: order.CertificateSerial,
467-
CertificateProfileName: order.CertificateProfileName,
472+
CertificateProfileName: &profile,
468473
}
469474

470475
if order.Error != nil {
@@ -481,14 +486,18 @@ func orderToModelv2(order *corepb.Order) (*orderModelv2, error) {
481486
}
482487

483488
func modelToOrderv2(om *orderModelv2) (*corepb.Order, error) {
489+
profile := ""
490+
if om.CertificateProfileName != nil {
491+
profile = *om.CertificateProfileName
492+
}
484493
order := &corepb.Order{
485494
Id: om.ID,
486495
RegistrationID: om.RegistrationID,
487496
Expires: timestamppb.New(om.Expires),
488497
Created: timestamppb.New(om.Created),
489498
CertificateSerial: om.CertificateSerial,
490499
BeganProcessing: om.BeganProcessing,
491-
CertificateProfileName: om.CertificateProfileName,
500+
CertificateProfileName: profile,
492501
}
493502
if len(om.Error) > 0 {
494503
var problem corepb.ProblemDetails

sa/sa.go

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,7 @@ func (ssa *SQLStorageAuthority) UpdateRegistrationKey(ctx context.Context, req *
281281

282282
// AddSerial writes a record of a serial number generation to the DB.
283283
func (ssa *SQLStorageAuthority) AddSerial(ctx context.Context, req *sapb.AddSerialRequest) (*emptypb.Empty, error) {
284-
// TODO(#7153): Check each value via core.IsAnyNilOrZero
285-
if req.Serial == "" || req.RegID == 0 || core.IsAnyNilOrZero(req.Created, req.Expires) {
284+
if core.IsAnyNilOrZero(req.Serial, req.RegID, req.Created, req.Expires) {
286285
return nil, errIncompleteRequest
287286
}
288287
err := ssa.dbMap.Insert(ctx, &recordedSerialModel{
@@ -332,8 +331,7 @@ func (ssa *SQLStorageAuthority) SetCertificateStatusReady(ctx context.Context, r
332331
// certificate multiple times. Calling code needs to first insert the cert's
333332
// serial into the Serials table to ensure uniqueness.
334333
func (ssa *SQLStorageAuthority) AddPrecertificate(ctx context.Context, req *sapb.AddCertificateRequest) (*emptypb.Empty, error) {
335-
// TODO(#7153): Check each value via core.IsAnyNilOrZero
336-
if len(req.Der) == 0 || req.RegID == 0 || req.IssuerNameID == 0 || core.IsAnyNilOrZero(req.Issued) {
334+
if core.IsAnyNilOrZero(req.Der, req.RegID, req.IssuerNameID, req.Issued) {
337335
return nil, errIncompleteRequest
338336
}
339337
parsed, err := x509.ParseCertificate(req.Der)
@@ -424,8 +422,7 @@ func (ssa *SQLStorageAuthority) AddPrecertificate(ctx context.Context, req *sapb
424422
// AddCertificate stores an issued certificate, returning an error if it is a
425423
// duplicate or if any other failure occurs.
426424
func (ssa *SQLStorageAuthority) AddCertificate(ctx context.Context, req *sapb.AddCertificateRequest) (*emptypb.Empty, error) {
427-
// TODO(#7153): Check each value via core.IsAnyNilOrZero
428-
if len(req.Der) == 0 || req.RegID == 0 || core.IsAnyNilOrZero(req.Issued) {
425+
if core.IsAnyNilOrZero(req.Der, req.RegID, req.Issued) {
429426
return nil, errIncompleteRequest
430427
}
431428
parsedCertificate, err := x509.ParseCertificate(req.Der)
@@ -619,7 +616,7 @@ func (ssa *SQLStorageAuthority) NewOrderAndAuthzs(ctx context.Context, req *sapb
619616
RegistrationID: req.NewOrder.RegistrationID,
620617
Expires: req.NewOrder.Expires.AsTime(),
621618
Created: created,
622-
CertificateProfileName: req.NewOrder.CertificateProfileName,
619+
CertificateProfileName: &req.NewOrder.CertificateProfileName,
623620
}
624621
err = tx.Insert(ctx, &omv2)
625622
orderID = omv2.ID
@@ -836,8 +833,7 @@ func (ssa *SQLStorageAuthority) FinalizeOrder(ctx context.Context, req *sapb.Fin
836833
// the authorization is being moved to invalid the validationError field must be set. If the
837834
// authorization is being moved to valid the validationRecord and expires fields must be set.
838835
func (ssa *SQLStorageAuthority) FinalizeAuthorization2(ctx context.Context, req *sapb.FinalizeAuthorizationRequest) (*emptypb.Empty, error) {
839-
// TODO(#7153): Check each value via core.IsAnyNilOrZero
840-
if req.Status == "" || req.Attempted == "" || req.Id == 0 || core.IsAnyNilOrZero(req.Expires) {
836+
if core.IsAnyNilOrZero(req.Status, req.Attempted, req.Id, req.Expires) {
841837
return nil, errIncompleteRequest
842838
}
843839

@@ -959,8 +955,7 @@ func addRevokedCertificate(ctx context.Context, tx db.Executor, req *sapb.Revoke
959955
// RevokeCertificate stores revocation information about a certificate. It will only store this
960956
// information if the certificate is not already marked as revoked.
961957
func (ssa *SQLStorageAuthority) RevokeCertificate(ctx context.Context, req *sapb.RevokeCertificateRequest) (*emptypb.Empty, error) {
962-
// TODO(#7153): Check each value via core.IsAnyNilOrZero
963-
if req.Serial == "" || req.IssuerID == 0 || core.IsAnyNilOrZero(req.Date) {
958+
if core.IsAnyNilOrZero(req.Serial, req.IssuerID, req.Date) {
964959
return nil, errIncompleteRequest
965960
}
966961

@@ -1013,8 +1008,7 @@ func (ssa *SQLStorageAuthority) RevokeCertificate(ctx context.Context, req *sapb
10131008
// cert is already revoked, if the new revocation reason is `KeyCompromise`,
10141009
// and if the revokedDate is identical to the current revokedDate.
10151010
func (ssa *SQLStorageAuthority) UpdateRevokedCertificate(ctx context.Context, req *sapb.RevokeCertificateRequest) (*emptypb.Empty, error) {
1016-
// TODO(#7153): Check each value via core.IsAnyNilOrZero
1017-
if req.Serial == "" || req.IssuerID == 0 || core.IsAnyNilOrZero(req.Date, req.Backdate) {
1011+
if core.IsAnyNilOrZero(req.Serial, req.IssuerID, req.Date, req.Backdate) {
10181012
return nil, errIncompleteRequest
10191013
}
10201014
if req.Reason != ocsp.KeyCompromise {

0 commit comments

Comments
 (0)