Skip to content

Commit 2bf5b26

Browse files
authored
Remove ability to configure policy OIDs (#6992)
Completely remove the ability to configure Certificate Policy OIDs in the Boulder CA. Instead, hard-code the Baseline Requirements Domain Validated Reserved Policy Identifier. Boulder will never perform OV or EV validation, so this is the only identifier that will be necessary. In the ceremony tool, introduce additional checks that assert that Root certificates do not have policies, and Intermediate certificates have exactly the one Baseline Requirements Domain Validated Reserved Policy Identifier.
1 parent 7d66d67 commit 2bf5b26

File tree

7 files changed

+54
-87
lines changed

7 files changed

+54
-87
lines changed

cmd/ceremony/cert.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,9 @@ type certProfile struct {
5555
// certificate
5656
IssuerURL string `yaml:"issuer-url"`
5757

58-
// PolicyOIDs should contain any OIDs to be inserted in a certificate
59-
// policies extension.
58+
// Policies should contain any OIDs to be inserted in a certificate
59+
// policies extension. It should be empty for Root certs, and contain the
60+
// BRs "domain-validated" Reserved Policy Identifier for Intermediates.
6061
Policies []policyInfoConfig `yaml:"policies"`
6162

6263
// KeyUsages should contain the set of key usage bits to set
@@ -140,13 +141,22 @@ func (profile *certProfile) verifyProfile(ct certType) error {
140141
return errors.New("country is required")
141142
}
142143

144+
if ct == rootCert {
145+
if len(profile.Policies) != 0 {
146+
return errors.New("policies should not be set on root certs")
147+
}
148+
}
149+
143150
if ct == intermediateCert {
144151
if profile.CRLURL == "" {
145152
return errors.New("crl-url is required for intermediates")
146153
}
147154
if profile.IssuerURL == "" {
148155
return errors.New("issuer-url is required for intermediates")
149156
}
157+
if len(profile.Policies) != 1 || profile.Policies[0].OID != "2.23.140.1.2.1" {
158+
return errors.New("policy should be exactly BRs domain-validated for intermediates")
159+
}
150160
}
151161

152162
if ct == ocspCert || ct == crlCert {
@@ -170,6 +180,9 @@ func parseOID(oidStr string) (asn1.ObjectIdentifier, error) {
170180
if err != nil {
171181
return nil, err
172182
}
183+
if i <= 0 {
184+
return nil, errors.New("OID components must be >= 1")
185+
}
173186
oid = append(oid, i)
174187
}
175188
return oid, nil

cmd/ceremony/cert_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ func TestParseOID(t *testing.T) {
3838
test.AssertError(t, err, "parseOID accepted an empty OID")
3939
_, err = parseOID("a.b.c")
4040
test.AssertError(t, err, "parseOID accepted an OID containing non-ints")
41+
_, err = parseOID("1.0.2")
42+
test.AssertError(t, err, "parseOID accepted an OID containing zero")
4143
oid, err := parseOID("1.2.3")
4244
test.AssertNotError(t, err, "parseOID failed with a valid OID")
4345
test.Assert(t, oid.Equal(asn1.ObjectIdentifier{1, 2, 3}), "parseOID returned incorrect OID")
@@ -306,6 +308,21 @@ func TestVerifyProfile(t *testing.T) {
306308
certType: intermediateCert,
307309
expectedErr: "issuer-url is required for intermediates",
308310
},
311+
{
312+
profile: certProfile{
313+
NotBefore: "a",
314+
NotAfter: "b",
315+
SignatureAlgorithm: "c",
316+
CommonName: "d",
317+
Organization: "e",
318+
Country: "f",
319+
OCSPURL: "g",
320+
CRLURL: "h",
321+
IssuerURL: "i",
322+
},
323+
certType: intermediateCert,
324+
expectedErr: "policy should be exactly BRs domain-validated for intermediates",
325+
},
309326
{
310327
profile: certProfile{
311328
NotBefore: "a",

cmd/ceremony/main_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ func TestIntermediateConfigValidate(t *testing.T) {
369369
OCSPURL: "g",
370370
CRLURL: "h",
371371
IssuerURL: "i",
372+
Policies: []policyInfoConfig{{OID: "2.23.140.1.2.1"}},
372373
},
373374
SkipLints: []string{},
374375
},

issuance/issuance.go

Lines changed: 5 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ import (
1717
"fmt"
1818
"math/big"
1919
"os"
20-
"strconv"
21-
"strings"
2220
"sync"
2321
"time"
2422

@@ -43,9 +41,11 @@ type ProfileConfig struct {
4341
AllowSCTList bool
4442
AllowCommonName bool
4543

46-
Policies []PolicyConfig `validate:"min=1,dive"`
4744
MaxValidityPeriod config.Duration
4845
MaxValidityBackdate config.Duration
46+
47+
// Deprecated: we do not respect this field.
48+
Policies []PolicyConfig `validate:"-"`
4949
}
5050

5151
// PolicyConfig describes a policy
@@ -161,27 +161,11 @@ type Profile struct {
161161
ocspURL string
162162
crlURL string
163163
issuerURL string
164-
policies []asn1.ObjectIdentifier
165164

166165
maxBackdate time.Duration
167166
maxValidity time.Duration
168167
}
169168

170-
func parseOID(oidStr string) (asn1.ObjectIdentifier, error) {
171-
var oid asn1.ObjectIdentifier
172-
for _, a := range strings.Split(oidStr, ".") {
173-
i, err := strconv.Atoi(a)
174-
if err != nil {
175-
return nil, err
176-
}
177-
if i <= 0 {
178-
return nil, errors.New("OID components must be >= 1")
179-
}
180-
oid = append(oid, i)
181-
}
182-
return oid, nil
183-
}
184-
185169
// NewProfile synthesizes the profile config and issuer config into a single
186170
// object, and checks various aspects for correctness.
187171
func NewProfile(profileConfig ProfileConfig, issuerConfig IssuerConfig) (*Profile, error) {
@@ -192,15 +176,6 @@ func NewProfile(profileConfig ProfileConfig, issuerConfig IssuerConfig) (*Profil
192176
return nil, errors.New("OCSP URL is required")
193177
}
194178

195-
var policies []asn1.ObjectIdentifier
196-
for _, policyConfig := range profileConfig.Policies {
197-
oid, err := parseOID(policyConfig.OID)
198-
if err != nil {
199-
return nil, fmt.Errorf("failed parsing policy OID %q: %w", policyConfig.OID, err)
200-
}
201-
policies = append(policies, oid)
202-
}
203-
204179
sp := &Profile{
205180
useForRSALeaves: issuerConfig.UseForRSALeaves,
206181
useForECDSALeaves: issuerConfig.UseForECDSALeaves,
@@ -211,7 +186,6 @@ func NewProfile(profileConfig ProfileConfig, issuerConfig IssuerConfig) (*Profil
211186
issuerURL: issuerConfig.IssuerURL,
212187
crlURL: issuerConfig.CRLURL,
213188
ocspURL: issuerConfig.OCSPURL,
214-
policies: policies,
215189
maxBackdate: profileConfig.MaxValidityBackdate.Duration,
216190
maxValidity: profileConfig.MaxValidityPeriod.Duration,
217191
}
@@ -294,7 +268,8 @@ func (p *Profile) generateTemplate() *x509.Certificate {
294268
OCSPServer: []string{p.ocspURL},
295269
IssuingCertificateURL: []string{p.issuerURL},
296270
BasicConstraintsValid: true,
297-
PolicyIdentifiers: p.policies,
271+
// Baseline Requirements, Section 7.1.6.1: domain-validated
272+
PolicyIdentifiers: []asn1.ObjectIdentifier{{2, 23, 140, 1, 2, 1}},
298273
}
299274

300275
if p.crlURL != "" {

issuance/issuance_test.go

Lines changed: 10 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,10 @@ import (
3232

3333
func defaultProfileConfig() ProfileConfig {
3434
return ProfileConfig{
35-
AllowCommonName: true,
36-
AllowCTPoison: true,
37-
AllowSCTList: true,
38-
AllowMustStaple: true,
39-
Policies: []PolicyConfig{
40-
{OID: "1.2.3"},
41-
},
35+
AllowCommonName: true,
36+
AllowCTPoison: true,
37+
AllowSCTList: true,
38+
AllowMustStaple: true,
4239
MaxValidityPeriod: config.Duration{Duration: time.Hour},
4340
MaxValidityBackdate: config.Duration{Duration: time.Hour},
4441
}
@@ -82,16 +79,6 @@ func TestMain(m *testing.M) {
8279
os.Exit(m.Run())
8380
}
8481

85-
func TestNewProfilePolicies(t *testing.T) {
86-
config := defaultProfileConfig()
87-
config.Policies = append(config.Policies, PolicyConfig{
88-
OID: "1.2.3.4",
89-
})
90-
profile, err := NewProfile(config, defaultIssuerConfig())
91-
test.AssertNotError(t, err, "NewProfile failed")
92-
test.AssertDeepEquals(t, profile.policies, []asn1.ObjectIdentifier{{1, 2, 3}, {1, 2, 3, 4}})
93-
}
94-
9582
func TestNewProfileNoIssuerURL(t *testing.T) {
9683
_, err := NewProfile(ProfileConfig{}, IssuerConfig{})
9784
test.AssertError(t, err, "NewProfile didn't fail with no issuer URL")
@@ -104,16 +91,6 @@ func TestNewProfileNoOCSPURL(t *testing.T) {
10491
test.AssertEquals(t, err.Error(), "OCSP URL is required")
10592
}
10693

107-
func TestNewProfileInvalidOID(t *testing.T) {
108-
_, err := NewProfile(ProfileConfig{
109-
Policies: []PolicyConfig{{
110-
OID: "a.b.c",
111-
}},
112-
}, defaultIssuerConfig())
113-
test.AssertError(t, err, "NewProfile didn't fail with malformed policy OID")
114-
test.AssertEquals(t, err.Error(), "failed parsing policy OID \"a.b.c\": strconv.Atoi: parsing \"a\": invalid syntax")
115-
}
116-
11794
func TestRequestValid(t *testing.T) {
11895
fc := clock.NewFake()
11996
fc.Add(time.Hour * 24)
@@ -343,21 +320,7 @@ func TestGenerateTemplate(t *testing.T) {
343320
IssuingCertificateURL: []string{""},
344321
OCSPServer: []string{""},
345322
CRLDistributionPoints: []string{"crl-url"},
346-
},
347-
},
348-
{
349-
name: "include policies",
350-
profile: &Profile{
351-
sigAlg: x509.SHA256WithRSA,
352-
policies: []asn1.ObjectIdentifier{{4, 5, 6}},
353-
},
354-
expectedTemplate: &x509.Certificate{
355-
BasicConstraintsValid: true,
356-
SignatureAlgorithm: x509.SHA256WithRSA,
357-
ExtKeyUsage: defaultEKU,
358-
IssuingCertificateURL: []string{""},
359-
OCSPServer: []string{""},
360-
PolicyIdentifiers: []asn1.ObjectIdentifier{{4, 5, 6}},
323+
PolicyIdentifiers: []asn1.ObjectIdentifier{{2, 23, 140, 1, 2, 1}},
361324
},
362325
},
363326
}
@@ -943,7 +906,7 @@ func TestMismatchedProfiles(t *testing.T) {
943906
linter, err := linter.New(
944907
issuerCert.Certificate,
945908
issuerSigner,
946-
[]string{},
909+
[]string{"n_subject_common_name_included"},
947910
)
948911
test.AssertNotError(t, err, "failed to create linter")
949912

@@ -954,6 +917,7 @@ func TestMismatchedProfiles(t *testing.T) {
954917
_, issuanceToken, err := issuer1.Prepare(&IssuanceRequest{
955918
PublicKey: pk.Public(),
956919
Serial: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
920+
CommonName: "example.com",
957921
DNSNames: []string{"example.com"},
958922
NotBefore: fc.Now(),
959923
NotAfter: fc.Now().Add(time.Hour - time.Second),
@@ -964,9 +928,9 @@ func TestMismatchedProfiles(t *testing.T) {
964928
precertDER, err := issuer1.Issue(issuanceToken)
965929
test.AssertNotError(t, err, "signing precert")
966930

967-
// Create a new profile that differs slightly (one more PolicyInformation than the precert)
931+
// Create a new profile that differs slightly (no common name)
968932
profileConfig := defaultProfileConfig()
969-
profileConfig.Policies = append(profileConfig.Policies, PolicyConfig{OID: "1.2.3.4"})
933+
profileConfig.AllowCommonName = false
970934
p, err := NewProfile(profileConfig, defaultIssuerConfig())
971935
test.AssertNotError(t, err, "NewProfile failed")
972936
issuer2, err := NewIssuer(issuerCert, issuerSigner, p, linter, fc)
@@ -988,6 +952,7 @@ func TestMismatchedProfiles(t *testing.T) {
988952

989953
request2, err := RequestFromPrecert(precert, sctList)
990954
test.AssertNotError(t, err, "RequestFromPrecert")
955+
request2.CommonName = ""
991956

992957
_, _, err = issuer2.Prepare(request2)
993958
test.AssertError(t, err, "preparing final cert issuance")

test/cert-ceremonies/intermediate-ceremony-ecdsa.yaml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,10 @@ certificate-profile:
1616
country: US
1717
not-before: 2020-01-01 12:00:00
1818
not-after: 2040-01-01 12:00:00
19-
crl-url: http://example.com/crl
20-
issuer-url: http://example.com/root
19+
crl-url: http://ecdsa.example.com/crl
20+
issuer-url: http://ecdsa.example.com/cert
2121
policies:
22-
- oid: 1.2.3
23-
- oid: 1.5.6
24-
cps-uri: "http://example.com/cps"
22+
- oid: 2.23.140.1.2.1
2523
key-usages:
2624
- Digital Signature
2725
- Cert Sign

test/cert-ceremonies/intermediate-ceremony-rsa.yaml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,10 @@ certificate-profile:
1616
country: US
1717
not-before: 2020-01-01 12:00:00
1818
not-after: 2040-01-01 12:00:00
19-
crl-url: http://example.com/crl
20-
issuer-url: http://example.com/root
19+
crl-url: http://rsa.example.com/crl
20+
issuer-url: http://rsa.example.com/cert
2121
policies:
22-
- oid: 1.2.3
23-
- oid: 1.5.6
24-
cps-uri: "http://example.com/cps"
22+
- oid: 2.23.140.1.2.1
2523
key-usages:
2624
- Digital Signature
2725
- Cert Sign

0 commit comments

Comments
 (0)