Remove OCSP and MustStaple support from issuance (#8181)

Remove the ability for the issuance package to include the AIA OCSP URI
and the Must Staple (more properly known as the tlsRequest) extension in
certificates. Deprecate the "OmitOCSP" and "AllowMustStaple" profile
config keys, as they no longer have any effect. Similarly deprecate the
"OCSPURL" issuer config key, as it is no longer included in
certificates.

Update the tests to always include to CRLDP extension instead, and
remove some OCSP- or Stapling-specific test cases.

Fixes https://github.com/letsencrypt/boulder/issues/8179
This commit is contained in:
Aaron Gable 2025-05-16 11:51:02 -07:00 committed by GitHub
parent caa29b2937
commit c9e2f98b5d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 92 additions and 180 deletions

View File

@ -549,16 +549,15 @@ func (ca *certificateAuthorityImpl) issuePrecertificateInner(ctx context.Context
}
req := &issuance.IssuanceRequest{
PublicKey: issuance.MarshalablePublicKey{PublicKey: csr.PublicKey},
SubjectKeyId: subjectKeyId,
Serial: serialBigInt.Bytes(),
DNSNames: dnsNames,
IPAddresses: ipAddresses,
CommonName: csrlib.NamesFromCSR(csr).CN,
IncludeCTPoison: true,
IncludeMustStaple: issuance.ContainsMustStaple(csr.Extensions),
NotBefore: notBefore,
NotAfter: notAfter,
PublicKey: issuance.MarshalablePublicKey{PublicKey: csr.PublicKey},
SubjectKeyId: subjectKeyId,
Serial: serialBigInt.Bytes(),
DNSNames: dnsNames,
IPAddresses: ipAddresses,
CommonName: csrlib.NamesFromCSR(csr).CN,
IncludeCTPoison: true,
NotBefore: notBefore,
NotAfter: notAfter,
}
lintCertBytes, issuanceToken, err := issuer.Prepare(certProfile.profile, req)

View File

@ -154,20 +154,20 @@ func setup(t *testing.T) *testCtx {
certProfiles := make(map[string]*issuance.ProfileConfig, 0)
certProfiles["legacy"] = &issuance.ProfileConfig{
AllowMustStaple: true,
MaxValidityPeriod: config.Duration{Duration: time.Hour * 24 * 90},
MaxValidityBackdate: config.Duration{Duration: time.Hour},
IgnoredLints: []string{"w_subject_common_name_included"},
IncludeCRLDistributionPoints: true,
MaxValidityPeriod: config.Duration{Duration: time.Hour * 24 * 90},
MaxValidityBackdate: config.Duration{Duration: time.Hour},
IgnoredLints: []string{"w_subject_common_name_included"},
}
certProfiles["modern"] = &issuance.ProfileConfig{
AllowMustStaple: true,
OmitCommonName: true,
OmitKeyEncipherment: true,
OmitClientAuth: true,
OmitSKID: true,
MaxValidityPeriod: config.Duration{Duration: time.Hour * 24 * 6},
MaxValidityBackdate: config.Duration{Duration: time.Hour},
IgnoredLints: []string{"w_ext_subject_key_identifier_missing_sub_cert"},
OmitCommonName: true,
OmitKeyEncipherment: true,
OmitClientAuth: true,
OmitSKID: true,
IncludeCRLDistributionPoints: true,
MaxValidityPeriod: config.Duration{Duration: time.Hour * 24 * 6},
MaxValidityBackdate: config.Duration{Duration: time.Hour},
IgnoredLints: []string{"w_ext_subject_key_identifier_missing_sub_cert"},
}
test.AssertEquals(t, len(certProfiles), 2)
@ -178,6 +178,7 @@ func setup(t *testing.T) *testCtx {
IssuerURL: fmt.Sprintf("http://not-example.com/i/%s", name),
OCSPURL: "http://not-example.com/o",
CRLURLBase: fmt.Sprintf("http://not-example.com/c/%s/", name),
CRLShards: 10,
Location: issuance.IssuerLoc{
File: fmt.Sprintf("../test/hierarchy/%s.key.pem", name),
CertFile: fmt.Sprintf("../test/hierarchy/%s.cert.pem", name),
@ -314,7 +315,6 @@ func TestIssuePrecertificate(t *testing.T) {
{"IssuePrecertificate", CNandSANCSR, issueCertificateSubTestIssuePrecertificate},
{"ProfileSelectionRSA", CNandSANCSR, issueCertificateSubTestProfileSelectionRSA},
{"ProfileSelectionECDSA", ECDSACSR, issueCertificateSubTestProfileSelectionECDSA},
{"MustStaple", MustStapleCSR, issueCertificateSubTestMustStaple},
{"UnknownExtension", UnsupportedExtensionCSR, issueCertificateSubTestUnknownExtension},
{"CTPoisonExtension", CTPoisonExtensionCSR, issueCertificateSubTestCTPoisonExtension},
{"CTPoisonExtensionEmpty", CTPoisonExtensionEmptyCSR, issueCertificateSubTestCTPoisonExtension},
@ -492,6 +492,7 @@ func TestUnpredictableIssuance(t *testing.T) {
IssuerURL: fmt.Sprintf("http://not-example.com/i/%s", name),
OCSPURL: "http://not-example.com/o",
CRLURLBase: fmt.Sprintf("http://not-example.com/c/%s/", name),
CRLShards: 10,
Location: issuance.IssuerLoc{
File: fmt.Sprintf("../test/hierarchy/%s.key.pem", name),
CertFile: fmt.Sprintf("../test/hierarchy/%s.cert.pem", name),
@ -573,6 +574,13 @@ func TestMakeCertificateProfilesMap(t *testing.T) {
profileConfigs: map[string]*issuance.ProfileConfig{
"empty": {},
},
expectedErrSubstr: "at least one revocation mechanism must be included",
},
{
name: "minimal profile config",
profileConfigs: map[string]*issuance.ProfileConfig{
"empty": {IncludeCRLDistributionPoints: true},
},
expectedProfiles: []string{"empty"},
},
{
@ -733,30 +741,12 @@ func issueCertificateSubTestProfileSelectionECDSA(t *testing.T, i *TestCertifica
test.AssertEquals(t, i.cert.KeyUsage, expectedKeyUsage)
}
func countMustStaple(t *testing.T, cert *x509.Certificate) (count int) {
oidTLSFeature := asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 24}
mustStapleFeatureValue := []byte{0x30, 0x03, 0x02, 0x01, 0x05}
for _, ext := range cert.Extensions {
if ext.Id.Equal(oidTLSFeature) {
test.Assert(t, !ext.Critical, "Extension was marked critical")
test.AssertByteEquals(t, ext.Value, mustStapleFeatureValue)
count++
}
}
return count
}
func issueCertificateSubTestMustStaple(t *testing.T, i *TestCertificateIssuance) {
test.AssertMetricWithLabelsEquals(t, i.ca.metrics.signatureCount, prometheus.Labels{"purpose": "precertificate"}, 1)
test.AssertEquals(t, countMustStaple(t, i.cert), 1)
}
func issueCertificateSubTestUnknownExtension(t *testing.T, i *TestCertificateIssuance) {
test.AssertMetricWithLabelsEquals(t, i.ca.metrics.signatureCount, prometheus.Labels{"purpose": "precertificate"}, 1)
// NOTE: The hard-coded value here will have to change over time as Boulder
// adds or removes (unrequested/default) extensions in certificates.
expectedExtensionCount := 9
expectedExtensionCount := 10
test.AssertEquals(t, len(i.cert.Extensions), expectedExtensionCount)
}

View File

@ -33,6 +33,9 @@ import (
type ProfileConfig struct {
// AllowMustStaple, when false, causes all IssuanceRequests which specify the
// OCSP Must Staple extension to be rejected.
//
// Deprecated: This has no effect, Must Staple is always omitted.
// TODO(#8177): Remove this.
AllowMustStaple bool
// OmitCommonName causes the CN field to be excluded from the resulting
@ -50,6 +53,9 @@ type ProfileConfig struct {
// Information Access extension. This cannot be true unless
// IncludeCRLDistributionPoints is also true, to ensure that every
// certificate has at least one revocation mechanism included.
//
// Deprecated: This has no effect; OCSP is always omitted.
// TODO(#8177): Remove this.
OmitOCSP bool
// IncludeCRLDistributionPoints causes the CRLDistributionPoints extension to
// be added to all certificates issued by this profile.
@ -73,12 +79,10 @@ type PolicyConfig struct {
// Profile is the validated structure created by reading in ProfileConfigs and IssuerConfigs
type Profile struct {
allowMustStaple bool
omitCommonName bool
omitKeyEncipherment bool
omitClientAuth bool
omitSKID bool
omitOCSP bool
includeCRLDistributionPoints bool
@ -105,7 +109,8 @@ func NewProfile(profileConfig *ProfileConfig) (*Profile, error) {
// Although the Baseline Requirements say that revocation information may be
// omitted entirely *for short-lived certs*, the Microsoft root program still
// requires that at least one revocation mechanism be included in all certs.
if profileConfig.OmitOCSP && !profileConfig.IncludeCRLDistributionPoints {
// TODO(#7673): Remove this restriction.
if !profileConfig.IncludeCRLDistributionPoints {
return nil, fmt.Errorf("at least one revocation mechanism must be included")
}
@ -118,12 +123,10 @@ func NewProfile(profileConfig *ProfileConfig) (*Profile, error) {
}
sp := &Profile{
allowMustStaple: profileConfig.AllowMustStaple,
omitCommonName: profileConfig.OmitCommonName,
omitKeyEncipherment: profileConfig.OmitKeyEncipherment,
omitClientAuth: profileConfig.OmitClientAuth,
omitSKID: profileConfig.OmitSKID,
omitOCSP: profileConfig.OmitOCSP,
includeCRLDistributionPoints: profileConfig.IncludeCRLDistributionPoints,
maxBackdate: profileConfig.MaxValidityBackdate.Duration,
maxValidity: profileConfig.MaxValidityPeriod.Duration,
@ -163,10 +166,6 @@ func (i *Issuer) requestValid(clk clock.Clock, prof *Profile, req *IssuanceReque
return errors.New("unexpected subject key ID length")
}
if !prof.allowMustStaple && req.IncludeMustStaple {
return errors.New("must-staple extension cannot be included")
}
if req.IncludeCTPoison && req.sctList != nil {
return errors.New("cannot include both ct poison and sct list extensions")
}
@ -253,16 +252,6 @@ func generateSCTListExt(scts []ct.SignedCertificateTimestamp) (pkix.Extension, e
}, nil
}
var mustStapleExt = pkix.Extension{
// RFC 7633: id-pe-tlsfeature OBJECT IDENTIFIER ::= { id-pe 24 }
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 24},
// ASN.1 encoding of:
// SEQUENCE
// INTEGER 5
// where "5" is the status_request feature (RFC 6066)
Value: []byte{0x30, 0x03, 0x02, 0x01, 0x05},
}
// MarshalablePublicKey is a wrapper for crypto.PublicKey with a custom JSON
// marshaller that encodes the public key as a DER-encoded SubjectPublicKeyInfo.
type MarshalablePublicKey struct {
@ -301,8 +290,7 @@ type IssuanceRequest struct {
DNSNames []string
IPAddresses []net.IP
IncludeMustStaple bool
IncludeCTPoison bool
IncludeCTPoison bool
// sctList is a list of SCTs to include in a final certificate.
// If it is non-empty, PrecertDER must also be non-empty.
@ -393,10 +381,6 @@ func (i *Issuer) Prepare(prof *Profile, req *IssuanceRequest) ([]byte, *issuance
return nil, nil, errors.New("invalid request contains neither sctList nor precertDER")
}
if !prof.omitOCSP {
template.OCSPServer = []string{i.ocspURL}
}
// If explicit CRL sharding is enabled, pick a shard based on the serial number
// modulus the number of shards. This gives us random distribution that is
// nonetheless consistent between precert and cert.
@ -410,10 +394,6 @@ func (i *Issuer) Prepare(prof *Profile, req *IssuanceRequest) ([]byte, *issuance
template.CRLDistributionPoints = []string{url}
}
if req.IncludeMustStaple {
template.ExtraExtensions = append(template.ExtraExtensions, mustStapleExt)
}
// check that the tbsCertificate is properly formed by signing it
// with a throwaway key and then linting it using zlint
lintCertBytes, err := i.Linter.Check(template, req.PublicKey.PublicKey, prof.lints)
@ -454,18 +434,6 @@ func (i *Issuer) Issue(token *issuanceToken) ([]byte, error) {
return x509.CreateCertificate(rand.Reader, template, i.Cert.Certificate, token.pubKey.PublicKey, i.Signer)
}
// ContainsMustStaple returns true if the provided set of extensions includes
// an entry whose OID and value both match the expected values for the OCSP
// Must-Staple (a.k.a. id-pe-tlsFeature) extension.
func ContainsMustStaple(extensions []pkix.Extension) bool {
for _, ext := range extensions {
if ext.Id.Equal(mustStapleExt.Id) && bytes.Equal(ext.Value, mustStapleExt.Value) {
return true
}
}
return false
}
// containsCTPoison returns true if the provided set of extensions includes
// an entry whose OID and value both match the expected values for the CT
// Poison extension.
@ -486,16 +454,15 @@ func RequestFromPrecert(precert *x509.Certificate, scts []ct.SignedCertificateTi
return nil, errors.New("provided certificate doesn't contain the CT poison extension")
}
return &IssuanceRequest{
PublicKey: MarshalablePublicKey{precert.PublicKey},
SubjectKeyId: precert.SubjectKeyId,
Serial: precert.SerialNumber.Bytes(),
NotBefore: precert.NotBefore,
NotAfter: precert.NotAfter,
CommonName: precert.Subject.CommonName,
DNSNames: precert.DNSNames,
IPAddresses: precert.IPAddresses,
IncludeMustStaple: ContainsMustStaple(precert.Extensions),
sctList: scts,
precertDER: precert.Raw,
PublicKey: MarshalablePublicKey{precert.PublicKey},
SubjectKeyId: precert.SubjectKeyId,
Serial: precert.SerialNumber.Bytes(),
NotBefore: precert.NotBefore,
NotAfter: precert.NotAfter,
CommonName: precert.Subject.CommonName,
DNSNames: precert.DNSNames,
IPAddresses: precert.IPAddresses,
sctList: scts,
precertDER: precert.Raw,
}, nil
}

View File

@ -127,19 +127,6 @@ func TestRequestValid(t *testing.T) {
},
expectedError: "unexpected subject key ID length",
},
{
name: "must staple not allowed",
issuer: &Issuer{
active: true,
},
profile: &Profile{},
request: &IssuanceRequest{
PublicKey: MarshalablePublicKey{&ecdsa.PublicKey{}},
SubjectKeyId: goodSKID,
IncludeMustStaple: true,
},
expectedError: "must-staple extension cannot be included",
},
{
name: "both sct list and ct poison provided",
issuer: &Issuer{
@ -322,7 +309,6 @@ func TestRequestValid(t *testing.T) {
func TestGenerateTemplate(t *testing.T) {
issuer := &Issuer{
ocspURL: "http://ocsp",
issuerURL: "http://issuer",
crlURLBase: "http://crl/",
sigAlg: x509.SHA256WithRSA,
@ -401,10 +387,10 @@ func TestIssue(t *testing.T) {
test.AssertDeepEquals(t, cert.IPAddresses, []net.IP{net.ParseIP("128.101.101.101").To4(), net.ParseIP("3fff:aaa:a:c0ff:ee:a:bad:deed")})
test.AssertByteEquals(t, cert.SerialNumber.Bytes(), []byte{1, 2, 3, 4, 5, 6, 7, 8, 9})
test.AssertDeepEquals(t, cert.PublicKey, pk.Public())
test.AssertEquals(t, len(cert.Extensions), 9) // Constraints, KU, EKU, SKID, AKID, AIA, SAN, Policies, Poison
test.AssertEquals(t, len(cert.Extensions), 10) // Constraints, KU, EKU, SKID, AKID, AIA, CRLDP, SAN, Policies, Poison
test.AssertEquals(t, cert.KeyUsage, tc.ku)
if len(cert.CRLDistributionPoints) > 0 {
t.Errorf("want CRLDistributionPoints=[], got %v", cert.CRLDistributionPoints)
if len(cert.CRLDistributionPoints) != 1 || !strings.HasPrefix(cert.CRLDistributionPoints[0], "http://crl-url.example.org/") {
t.Errorf("want CRLDistributionPoints=[http://crl-url.example.org/x.crl], got %v", cert.CRLDistributionPoints)
}
})
}
@ -656,8 +642,8 @@ func TestIssueCTPoison(t *testing.T) {
test.AssertNotError(t, err, "signature validation failed")
test.AssertByteEquals(t, cert.SerialNumber.Bytes(), []byte{1, 2, 3, 4, 5, 6, 7, 8, 9})
test.AssertDeepEquals(t, cert.PublicKey, pk.Public())
test.AssertEquals(t, len(cert.Extensions), 9) // Constraints, KU, EKU, SKID, AKID, AIA, SAN, Policies, CT Poison
test.AssertDeepEquals(t, cert.Extensions[8], ctPoisonExt)
test.AssertEquals(t, len(cert.Extensions), 10) // Constraints, KU, EKU, SKID, AKID, AIA, CRLDP, SAN, Policies, Poison
test.AssertDeepEquals(t, cert.Extensions[9], ctPoisonExt)
}
func mustDecodeB64(b string) []byte {
@ -728,8 +714,8 @@ func TestIssueSCTList(t *testing.T) {
test.AssertNotError(t, err, "signature validation failed")
test.AssertByteEquals(t, finalCert.SerialNumber.Bytes(), []byte{1, 2, 3, 4, 5, 6, 7, 8, 9})
test.AssertDeepEquals(t, finalCert.PublicKey, pk.Public())
test.AssertEquals(t, len(finalCert.Extensions), 9) // Constraints, KU, EKU, SKID, AKID, AIA, SAN, Policies, SCT list
test.AssertDeepEquals(t, finalCert.Extensions[8], pkix.Extension{
test.AssertEquals(t, len(finalCert.Extensions), 10) // Constraints, KU, EKU, SKID, AKID, AIA, CRLDP, SAN, Policies, Poison
test.AssertDeepEquals(t, finalCert.Extensions[9], pkix.Extension{
Id: sctListOID,
Value: []byte{
4, 100, 0, 98, 0, 47, 0, 56, 152, 140, 148, 208, 53, 152, 195, 147, 45,
@ -742,37 +728,6 @@ func TestIssueSCTList(t *testing.T) {
})
}
func TestIssueMustStaple(t *testing.T) {
fc := clock.NewFake()
fc.Set(time.Now())
signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc)
test.AssertNotError(t, err, "NewIssuer failed")
pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
test.AssertNotError(t, err, "failed to generate test key")
_, issuanceToken, err := signer.Prepare(defaultProfile(), &IssuanceRequest{
PublicKey: MarshalablePublicKey{pk.Public()},
SubjectKeyId: goodSKID,
Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
DNSNames: []string{"example.com"},
IncludeMustStaple: true,
NotBefore: fc.Now(),
NotAfter: fc.Now().Add(time.Hour - time.Second),
IncludeCTPoison: true,
})
test.AssertNotError(t, err, "Prepare failed")
certBytes, err := signer.Issue(issuanceToken)
test.AssertNotError(t, err, "Issue failed")
cert, err := x509.ParseCertificate(certBytes)
test.AssertNotError(t, err, "failed to parse certificate")
err = cert.CheckSignatureFrom(issuerCert.Certificate)
test.AssertNotError(t, err, "signature validation failed")
test.AssertByteEquals(t, cert.SerialNumber.Bytes(), []byte{1, 2, 3, 4, 5, 6, 7, 8, 9})
test.AssertDeepEquals(t, cert.PublicKey, pk.Public())
test.AssertEquals(t, len(cert.Extensions), 10) // Constraints, KU, EKU, SKID, AKID, AIA, SAN, Policies, Must-Staple, Poison
test.AssertDeepEquals(t, cert.Extensions[9], mustStapleExt)
}
func TestIssueBadLint(t *testing.T) {
fc := clock.NewFake()
fc.Set(time.Now())
@ -966,17 +921,9 @@ func TestNewProfile(t *testing.T) {
}{
{
name: "happy path",
config: ProfileConfig{
MaxValidityBackdate: config.Duration{Duration: 1 * time.Hour},
MaxValidityPeriod: config.Duration{Duration: 90 * 24 * time.Hour},
},
},
{
name: "crl but no ocsp",
config: ProfileConfig{
MaxValidityBackdate: config.Duration{Duration: 1 * time.Hour},
MaxValidityPeriod: config.Duration{Duration: 90 * 24 * time.Hour},
OmitOCSP: false,
IncludeCRLDistributionPoints: true,
},
},
@ -1001,7 +948,6 @@ func TestNewProfile(t *testing.T) {
config: ProfileConfig{
MaxValidityBackdate: config.Duration{Duration: 1 * time.Hour},
MaxValidityPeriod: config.Duration{Duration: 90 * 24 * time.Hour},
OmitOCSP: true,
IncludeCRLDistributionPoints: false,
},
wantErr: "revocation mechanism must be included",

View File

@ -161,9 +161,11 @@ type IssuerConfig struct {
Active bool
IssuerURL string `validate:"required,url"`
OCSPURL string `validate:"required,url"`
CRLURLBase string `validate:"required,url,startswith=http://,endswith=/"`
// TODO(#8177): Remove this.
OCSPURL string `validate:"omitempty,url"`
// Number of CRL shards.
// This must be nonzero if adding CRLDistributionPoints to certificates
// (that is, if profile.IncludeCRLDistributionPoints is true).
@ -205,9 +207,6 @@ type Issuer struct {
// Used to set the Authority Information Access caIssuers URL in issued
// certificates.
issuerURL string
// Used to set the Authority Information Access ocsp URL in issued
// certificates.
ocspURL string
// Used to set the Issuing Distribution Point extension in issued CRLs
// and the CRL Distribution Point extension in issued certs.
crlURLBase string
@ -243,9 +242,6 @@ func newIssuer(config IssuerConfig, cert *Certificate, signer crypto.Signer, clk
if config.IssuerURL == "" {
return nil, errors.New("Issuer URL is required")
}
if config.OCSPURL == "" {
return nil, errors.New("OCSP URL is required")
}
if config.CRLURLBase == "" {
return nil, errors.New("CRL URL base is required")
}
@ -281,7 +277,6 @@ func newIssuer(config IssuerConfig, cert *Certificate, signer crypto.Signer, clk
sigAlg: sigAlg,
active: config.Active,
issuerURL: config.IssuerURL,
ocspURL: config.OCSPURL,
crlURLBase: config.CRLURLBase,
crlShards: config.CRLShards,
clk: clk,

View File

@ -24,9 +24,10 @@ import (
func defaultProfileConfig() *ProfileConfig {
return &ProfileConfig{
AllowMustStaple: true,
MaxValidityPeriod: config.Duration{Duration: time.Hour},
MaxValidityBackdate: config.Duration{Duration: time.Hour},
AllowMustStaple: true,
IncludeCRLDistributionPoints: true,
MaxValidityPeriod: config.Duration{Duration: time.Hour},
MaxValidityBackdate: config.Duration{Duration: time.Hour},
IgnoredLints: []string{
// Ignore the two SCT lints because these tests don't get SCTs.
"w_ct_sct_policy_count_unsatisfied",
@ -42,8 +43,8 @@ func defaultIssuerConfig() IssuerConfig {
return IssuerConfig{
Active: true,
IssuerURL: "http://issuer-url.example.org",
OCSPURL: "http://ocsp-url.example.org",
CRLURLBase: "http://crl-url.example.org/",
CRLShards: 10,
}
}

View File

@ -1,9 +1,12 @@
package ra
import (
"bytes"
"context"
"crypto"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/json"
"errors"
"fmt"
@ -1045,6 +1048,26 @@ func (ra *RegistrationAuthorityImpl) FinalizeOrder(ctx context.Context, req *rap
}
}
// containsMustStaple returns true if the provided set of extensions includes
// an entry whose OID and value both match the expected values for the OCSP
// Must-Staple (a.k.a. id-pe-tlsFeature) extension.
func containsMustStaple(extensions []pkix.Extension) bool {
// RFC 7633: id-pe-tlsfeature OBJECT IDENTIFIER ::= { id-pe 24 }
var mustStapleExtId = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 24}
// ASN.1 encoding of:
// SEQUENCE
// INTEGER 5
// where "5" is the status_request feature (RFC 6066)
var mustStapleExtValue = []byte{0x30, 0x03, 0x02, 0x01, 0x05}
for _, ext := range extensions {
if ext.Id.Equal(mustStapleExtId) && bytes.Equal(ext.Value, mustStapleExtValue) {
return true
}
}
return false
}
// validateFinalizeRequest checks that a FinalizeOrder request is fully correct
// and ready for issuance.
func (ra *RegistrationAuthorityImpl) validateFinalizeRequest(
@ -1085,7 +1108,7 @@ func (ra *RegistrationAuthorityImpl) validateFinalizeRequest(
return nil, berrors.BadCSRError("unable to parse CSR: %s", err.Error())
}
if issuance.ContainsMustStaple(csr.Extensions) {
if containsMustStaple(csr.Extensions) {
ra.mustStapleRequestsCounter.WithLabelValues("denied").Inc()
return nil, berrors.UnauthorizedError(
"OCSP must-staple extension is no longer available: see https://letsencrypt.org/2024/12/05/ending-ocsp",

View File

@ -54,8 +54,6 @@
"issuance": {
"certProfiles": {
"legacy": {
"allowMustStaple": true,
"omitOCSP": true,
"includeCRLDistributionPoints": true,
"maxValidityPeriod": "7776000s",
"maxValidityBackdate": "1h5m",
@ -66,12 +64,10 @@
]
},
"modern": {
"allowMustStaple": true,
"omitCommonName": true,
"omitKeyEncipherment": true,
"omitClientAuth": true,
"omitSKID": true,
"omitOCSP": true,
"includeCRLDistributionPoints": true,
"maxValidityPeriod": "583200s",
"maxValidityBackdate": "1h5m",
@ -81,12 +77,10 @@
]
},
"shortlived": {
"allowMustStaple": true,
"omitCommonName": true,
"omitKeyEncipherment": true,
"omitClientAuth": true,
"omitSKID": true,
"omitOCSP": true,
"includeCRLDistributionPoints": true,
"maxValidityPeriod": "160h",
"maxValidityBackdate": "1h5m",
@ -106,7 +100,6 @@
"active": true,
"crlShards": 10,
"issuerURL": "http://ca.example.org:4502/int-ecdsa-a",
"ocspURL": "http://ca.example.org:4002/",
"crlURLBase": "http://ca.example.org:4501/lets-encrypt-crls/43104258997432926/",
"location": {
"configFile": "test/certs/webpki/int-ecdsa-a.pkcs11.json",
@ -118,7 +111,6 @@
"active": true,
"crlShards": 10,
"issuerURL": "http://ca.example.org:4502/int-ecdsa-b",
"ocspURL": "http://ca.example.org:4002/",
"crlURLBase": "http://ca.example.org:4501/lets-encrypt-crls/17302365692836921/",
"location": {
"configFile": "test/certs/webpki/int-ecdsa-b.pkcs11.json",
@ -130,7 +122,6 @@
"active": false,
"crlShards": 10,
"issuerURL": "http://ca.example.org:4502/int-ecdsa-c",
"ocspURL": "http://ca.example.org:4002/",
"crlURLBase": "http://ca.example.org:4501/lets-encrypt-crls/56560759852043581/",
"location": {
"configFile": "test/certs/webpki/int-ecdsa-c.pkcs11.json",
@ -142,7 +133,6 @@
"active": true,
"crlShards": 10,
"issuerURL": "http://ca.example.org:4502/int-rsa-a",
"ocspURL": "http://ca.example.org:4002/",
"crlURLBase": "http://ca.example.org:4501/lets-encrypt-crls/29947985078257530/",
"location": {
"configFile": "test/certs/webpki/int-rsa-a.pkcs11.json",
@ -154,7 +144,6 @@
"active": true,
"crlShards": 10,
"issuerURL": "http://ca.example.org:4502/int-rsa-b",
"ocspURL": "http://ca.example.org:4002/",
"crlURLBase": "http://ca.example.org:4501/lets-encrypt-crls/6762885421992935/",
"location": {
"configFile": "test/certs/webpki/int-rsa-b.pkcs11.json",
@ -166,7 +155,6 @@
"active": false,
"crlShards": 10,
"issuerURL": "http://ca.example.org:4502/int-rsa-c",
"ocspURL": "http://ca.example.org:4002/",
"crlURLBase": "http://ca.example.org:4501/lets-encrypt-crls/56183656833365902/",
"location": {
"configFile": "test/certs/webpki/int-rsa-c.pkcs11.json",

View File

@ -56,6 +56,7 @@
"certProfiles": {
"legacy": {
"allowMustStaple": true,
"omitOCSP": true,
"includeCRLDistributionPoints": true,
"maxValidityPeriod": "7776000s",
"maxValidityBackdate": "1h5m",
@ -71,6 +72,7 @@
"omitKeyEncipherment": true,
"omitClientAuth": true,
"omitSKID": true,
"omitOCSP": true,
"includeCRLDistributionPoints": true,
"maxValidityPeriod": "583200s",
"maxValidityBackdate": "1h5m",
@ -85,6 +87,7 @@
"omitKeyEncipherment": true,
"omitClientAuth": true,
"omitSKID": true,
"omitOCSP": true,
"includeCRLDistributionPoints": true,
"maxValidityPeriod": "160h",
"maxValidityBackdate": "1h5m",