Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions ca/ca_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1016,13 +1016,8 @@ func TestVerifyTBSCertIsDeterministic(t *testing.T) {
errorSubstr: "mismatch between",
},
{
// Take this with a grain of salt since this test is not actually
// creating a linting certificate and performing two
// x509.CreateCertificate() calls like
// ca.IssueCertificateForPrecertificate and
// ca.issuePrecertificateInner do. However, we're still going to
// verify the equality.
name: "Valid",
// If the inputs are identical, return success.
name: "identical inputs succeed",
lintCertBytes: certDer1,
leafCertBytes: certDer1,
},
Expand Down
12 changes: 6 additions & 6 deletions docs/ISSUANCE-CYCLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ At a high level:
1. Check that all authorizations are good.
2. Recheck CAA for hostnames that need it.
3. Allocate and store a serial number.
4. Select a certificate profile.
5. Generate and store linting precertificate.
6. Sign, log (and don't store) precertificate.
7. Submit precertificate to CT.
8. Generate linting final certificate. Not logged or stored.
9. Sign, log, and store final certificate.
4. Generate and store linting precertificate.
5. Sign, log (and don't store) precertificate.
6. Submit precertificate to CT.
7. Generate linting final certificate. Not logged or stored.
8. Sign, log, and store final certificate.
9. Submit final certificate to CT.

Revocation can happen at any time after (5), whether or not step (6) was successful. We do things this way so that even in the event of a power failure or error storing data, we have a record of what we planned to sign (the tbsCertificate bytes of the linting certificate).

Expand Down
39 changes: 8 additions & 31 deletions ra/ra.go
Original file line number Diff line number Diff line change
Expand Up @@ -1098,16 +1098,6 @@ func (ra *RegistrationAuthorityImpl) validateFinalizeRequest(
return csr, authzs, nil
}

func (ra *RegistrationAuthorityImpl) GetSCTs(ctx context.Context, sctRequest *rapb.SCTRequest) (*rapb.SCTResponse, error) {
scts, err := ra.getSCTs(ctx, sctRequest.PrecertDER)
if err != nil {
return nil, err
}
return &rapb.SCTResponse{
SctDER: scts,
}, nil
}

// issueCertificateOuter exists solely to ensure that all calls to
// issueCertificateInner have their result handled uniformly, no matter what
// return path that inner function takes. It takes ownership of the logEvent,
Expand Down Expand Up @@ -1215,23 +1205,8 @@ func (ra *RegistrationAuthorityImpl) countCertificateIssued(ctx context.Context,
}
}

// issueCertificateInner is part of the [issuance cycle].
//
// It gets a precertificate from the CA, submits it to CT logs to get SCTs,
// then sends the precertificate and the SCTs to the CA to get a final certificate.
//
// This function is responsible for ensuring that we never try to issue a final
// certificate twice for the same precertificate, because that has the potential
// to create certificates with duplicate serials. For instance, this could
// happen if final certificates were created with different sets of SCTs. This
// function accomplishes that by bailing on issuance if there is any error in
// IssueCertificateForPrecertificate; there are no retries, and serials are
// generated in IssuePrecertificate, so serials with errors are dropped and
// never have final certificates issued for them (because there is a possibility
// that the certificate was actually issued but there was an error returning
// it).
//
// [issuance cycle]: https://github.com/letsencrypt/boulder/blob/main/docs/ISSUANCE-CYCLE.md
// issueCertificateInner rechecks CAA, gets a certificate from the CA,
// and finalizes the order with the certificate serial.
func (ra *RegistrationAuthorityImpl) issueCertificateInner(
ctx context.Context,
csr *x509.CertificateRequest,
Expand Down Expand Up @@ -1299,14 +1274,14 @@ func (ra *RegistrationAuthorityImpl) issueCertificateInner(
return parsedCertificate, nil
}

func (ra *RegistrationAuthorityImpl) getSCTs(ctx context.Context, precertDER []byte) (core.SCTDERs, error) {
func (ra *RegistrationAuthorityImpl) GetSCTs(ctx context.Context, sctRequest *rapb.SCTRequest) (*rapb.SCTResponse, error) {
started := ra.clk.Now()
precert, err := x509.ParseCertificate(precertDER)
precert, err := x509.ParseCertificate(sctRequest.PrecertDER)
if err != nil {
return nil, fmt.Errorf("parsing precertificate: %w", err)
}

scts, err := ra.ctpolicy.GetSCTs(ctx, precertDER, precert.NotAfter)
scts, err := ra.ctpolicy.GetSCTs(ctx, precert.Raw, precert.NotAfter)
took := ra.clk.Since(started)
if err != nil {
state := "failure"
Expand All @@ -1321,7 +1296,9 @@ func (ra *RegistrationAuthorityImpl) getSCTs(ctx context.Context, precertDER []b
return nil, err
}
ra.ctpolicyResults.With(prometheus.Labels{"result": "success"}).Observe(took.Seconds())
return scts, nil
return &rapb.SCTResponse{
SctDER: scts,
}, nil
}

// UpdateRegistrationKey updates an existing Registration's key.
Expand Down