From ebdabe693bc5b5c18ef56a8f431ebbdd16ac61c5 Mon Sep 17 00:00:00 2001 From: Aaron Gable Date: Tue, 9 Apr 2024 15:41:46 -0700 Subject: [PATCH] CA: Fix multi-profile deployability bug (#7422) When https://github.com/letsencrypt/boulder/pull/7325 was deployed to staging, the CA threw "Incomplete cert for precertificate request" errors. Even though the RA was forwarding the CertProfileHash in all IssueCertificateForPrecertificate requests to updated CA instances, it can't do that if the IssuePrecertificate request was handled by a non-updated CA instance that didn't yet know to return the hash. This PR should be landed, tagged with a release, and then immediately reverted for inclusion in the next release. Part of https://github.com/letsencrypt/boulder/issues/6966 --- ca/ca.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/ca/ca.go b/ca/ca.go index f1d1fa2d498..cf0876d79ce 100644 --- a/ca/ca.go +++ b/ca/ca.go @@ -346,10 +346,22 @@ func (ca *certificateAuthorityImpl) IssuePrecertificate(ctx context.Context, iss // serial number at the same time. func (ca *certificateAuthorityImpl) IssueCertificateForPrecertificate(ctx context.Context, req *capb.IssueCertificateForPrecertificateRequest) (*corepb.Certificate, error) { // issueReq.orderID may be zero, for ACMEv1 requests. - if core.IsAnyNilOrZero(req, req.DER, req.SCTs, req.RegistrationID, req.CertProfileHash) { + if core.IsAnyNilOrZero(req, req.DER, req.SCTs, req.RegistrationID) { return nil, berrors.InternalServerError("Incomplete cert for precertificate request") } + // The RA already provides the CertProfileHash to all + // IssueCertificateForPrecertificate calls... but it can only do that if the + // CA itself provided the hash in the IssuePrecertificate response. Therefore + // there can be a short period during the deploy where updated CAs which + // expect a profile hash aren't being provided with one. + if len(req.CertProfileHash) == 0 { + // This lookup will succeed because makeCertificateProfilesMap guarantees + // that the default name has a corresponding profile. + profile := ca.certProfiles.profileByName[ca.certProfiles.defaultName] + req.CertProfileHash = profile.hash[:] + } + // The certificate profile hash is checked here instead of the name because // the hash is over the entire contents of a *ProfileConfig giving assurance // that the certificate profile has remained unchanged during the roundtrip