Skip to content

Commit 3fa3184

Browse files
committed
Simplify profile config hashing
1 parent f71d2ea commit 3fa3184

10 files changed

Lines changed: 46 additions & 166 deletions

File tree

ca/ca.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ func makeIssuerMaps(issuers []*issuance.Issuer) (issuerMaps, error) {
200200
// - CA1 returns the precertificate DER bytes and profile hash to the RA
201201
// - RA instructs CA2 to issue a final certificate, but CA2 does not contain a
202202
// profile corresponding to that hash and an issuance is prevented.
203-
func makeCertificateProfilesMap(profiles map[string]*issuance.ProfileConfigNew) (certProfilesMaps, error) {
203+
func makeCertificateProfilesMap(profiles map[string]*issuance.ProfileConfig) (certProfilesMaps, error) {
204204
if len(profiles) <= 0 {
205205
return certProfilesMaps{}, fmt.Errorf("must pass at least one certificate profile")
206206
}
@@ -241,7 +241,7 @@ func NewCertificateAuthorityImpl(
241241
sctService rapb.SCTProviderClient,
242242
pa core.PolicyAuthority,
243243
boulderIssuers []*issuance.Issuer,
244-
certificateProfiles map[string]*issuance.ProfileConfigNew,
244+
certificateProfiles map[string]*issuance.ProfileConfig,
245245
serialPrefix byte,
246246
maxNames int,
247247
keyPolicy goodkey.KeyPolicy,

ca/ca_test.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ type testCtx struct {
102102
pa core.PolicyAuthority
103103
ocsp *ocspImpl
104104
crl *crlImpl
105-
certProfiles map[string]*issuance.ProfileConfigNew
105+
certProfiles map[string]*issuance.ProfileConfig
106106
serialPrefix byte
107107
maxNames int
108108
boulderIssuers []*issuance.Issuer
@@ -153,14 +153,14 @@ func setup(t *testing.T) *testCtx {
153153
err = pa.LoadHostnamePolicyFile("../test/hostname-policy.yaml")
154154
test.AssertNotError(t, err, "Couldn't set hostname policy")
155155

156-
certProfiles := make(map[string]*issuance.ProfileConfigNew, 0)
157-
certProfiles["legacy"] = &issuance.ProfileConfigNew{
156+
certProfiles := make(map[string]*issuance.ProfileConfig, 0)
157+
certProfiles["legacy"] = &issuance.ProfileConfig{
158158
AllowMustStaple: true,
159159
MaxValidityPeriod: config.Duration{Duration: time.Hour * 24 * 90},
160160
MaxValidityBackdate: config.Duration{Duration: time.Hour},
161161
IgnoredLints: []string{"w_subject_common_name_included"},
162162
}
163-
certProfiles["modern"] = &issuance.ProfileConfigNew{
163+
certProfiles["modern"] = &issuance.ProfileConfig{
164164
AllowMustStaple: true,
165165
OmitCommonName: true,
166166
OmitKeyEncipherment: true,
@@ -552,7 +552,7 @@ func TestMakeCertificateProfilesMap(t *testing.T) {
552552
testCtx := setup(t)
553553
test.AssertEquals(t, len(testCtx.certProfiles), 2)
554554

555-
testProfile := issuance.ProfileConfigNew{
555+
testProfile := issuance.ProfileConfig{
556556
AllowMustStaple: false,
557557
MaxValidityPeriod: config.Duration{Duration: time.Hour * 24 * 90},
558558
MaxValidityBackdate: config.Duration{Duration: time.Hour},
@@ -565,7 +565,7 @@ func TestMakeCertificateProfilesMap(t *testing.T) {
565565

566566
testCases := []struct {
567567
name string
568-
profileConfigs map[string]*issuance.ProfileConfigNew
568+
profileConfigs map[string]*issuance.ProfileConfig
569569
expectedErrSubstr string
570570
expectedProfiles []nameToHash
571571
}{
@@ -576,26 +576,26 @@ func TestMakeCertificateProfilesMap(t *testing.T) {
576576
},
577577
{
578578
name: "no profiles",
579-
profileConfigs: map[string]*issuance.ProfileConfigNew{},
579+
profileConfigs: map[string]*issuance.ProfileConfig{},
580580
expectedErrSubstr: "at least one certificate profile",
581581
},
582582
{
583583
name: "duplicate hash",
584-
profileConfigs: map[string]*issuance.ProfileConfigNew{
584+
profileConfigs: map[string]*issuance.ProfileConfig{
585585
"default": &testProfile,
586586
"default2": &testProfile,
587587
},
588588
expectedErrSubstr: "duplicate certificate profile hash",
589589
},
590590
{
591591
name: "empty profile config",
592-
profileConfigs: map[string]*issuance.ProfileConfigNew{
592+
profileConfigs: map[string]*issuance.ProfileConfig{
593593
"empty": {},
594594
},
595595
expectedProfiles: []nameToHash{
596596
{
597597
name: "empty",
598-
hash: [32]byte{0x25, 0x27, 0x72, 0xa1, 0xaf, 0x95, 0xfe, 0xc7, 0x32, 0x78, 0x38, 0x97, 0xd0, 0xf1, 0x83, 0x92, 0xc3, 0xac, 0x60, 0x91, 0x68, 0x4f, 0x22, 0xb6, 0x57, 0x2f, 0x89, 0x1a, 0x54, 0xe5, 0xd8, 0xa3},
598+
hash: [32]byte{0xe4, 0xf6, 0xd, 0xa, 0xa6, 0xd7, 0xf3, 0xd3, 0xb6, 0xa6, 0x49, 0x4b, 0x1c, 0x86, 0x1b, 0x99, 0xf6, 0x49, 0xc6, 0xf9, 0xec, 0x51, 0xab, 0xaf, 0x20, 0x1b, 0x20, 0xf2, 0x97, 0x32, 0x7c, 0x95},
599599
},
600600
},
601601
},
@@ -605,11 +605,11 @@ func TestMakeCertificateProfilesMap(t *testing.T) {
605605
expectedProfiles: []nameToHash{
606606
{
607607
name: "legacy",
608-
hash: [32]byte{0x44, 0xc5, 0xbc, 0x73, 0x8, 0x95, 0xba, 0x4c, 0x13, 0x12, 0xc4, 0xc, 0x5d, 0x77, 0x2f, 0x54, 0xf8, 0x54, 0x1, 0xb8, 0x84, 0xaf, 0x6c, 0x58, 0x74, 0x6, 0xac, 0xda, 0x3e, 0x37, 0xfc, 0x88},
608+
hash: [32]byte{0xb7, 0xd9, 0x7e, 0xfc, 0x5a, 0xdd, 0xc7, 0xfe, 0xc, 0xea, 0xed, 0x7b, 0x8c, 0xf5, 0x4, 0x57, 0x71, 0x97, 0x42, 0x80, 0xbe, 0x4d, 0x14, 0xa, 0x35, 0x9a, 0x89, 0xc3, 0x7a, 0x57, 0x41, 0xb7},
609609
},
610610
{
611611
name: "modern",
612-
hash: [32]byte{0x58, 0x7, 0xea, 0x3a, 0x85, 0xcd, 0xf9, 0xd1, 0x7a, 0x9a, 0x59, 0x76, 0xfc, 0x92, 0xea, 0x1b, 0x69, 0x54, 0xe4, 0xbe, 0xcf, 0xe3, 0x91, 0xfa, 0x85, 0x4, 0xbf, 0x1f, 0x55, 0x97, 0x2c, 0x8b},
612+
hash: [32]byte{0x2e, 0x82, 0x9b, 0xe4, 0x4d, 0xac, 0xfc, 0x2d, 0x83, 0xbf, 0x62, 0xe5, 0xe1, 0x50, 0xe8, 0xba, 0xd2, 0x66, 0x1a, 0xb3, 0xf2, 0xe7, 0xb5, 0xf2, 0x24, 0x94, 0x1f, 0x83, 0xc6, 0x57, 0xe, 0x58},
613613
},
614614
},
615615
},

cmd/boulder-ca/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ type Config struct {
4646

4747
// One of the profile names must match the value of ra.defaultProfileName
4848
// or large amounts of issuance will fail.
49-
CertProfiles map[string]*issuance.ProfileConfigNew `validate:"dive,keys,alphanum,min=1,max=32,endkeys,required_without=Profile,structonly"`
49+
CertProfiles map[string]*issuance.ProfileConfig `validate:"dive,keys,alphanum,min=1,max=32,endkeys,required_without=Profile,structonly"`
5050

5151
// TODO(#7159): Make this required once all live configs are using it.
5252
CRLProfile issuance.CRLProfileConfig `validate:"-"`

issuance/cert.go

Lines changed: 6 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"crypto/x509"
1111
"crypto/x509/pkix"
1212
"encoding/asn1"
13-
"encoding/gob"
1413
"encoding/json"
1514
"errors"
1615
"fmt"
@@ -30,72 +29,7 @@ import (
3029
"github.com/letsencrypt/boulder/precert"
3130
)
3231

33-
// ProfileConfig is a subset of ProfileConfigNew used for hashing.
34-
//
35-
// Deprecated: Use ProfileConfigNew instead.
36-
//
37-
// This struct exists for backwards-compatibility purposes when generating hashes
38-
// of profile configs.
39-
//
40-
// The CA uses a hash of the gob encoding of ProfileConfig to ensure precert
41-
// and final cert issuance use the exact same profile settings. Gob encodes all
42-
// fields, including zero values, which means adding fields immediately changes all
43-
// hashes, causing a deployability problem. It also encodes the struct name.
44-
//
45-
// To solve the deployability problem, we're switching to ASN.1 encoding. However,
46-
// while deploying that we still need the ability to hash old configs the same way
47-
// they've always been hashed. So this struct (with the same name it always had)
48-
// gets hashed, only when `ProfileConfigNew.IncludeCRLDistributionPoints` (the
49-
// newly added field) is false.
50-
//
51-
// Note that gob encodes the names of structs, not just their fields, so we needed
52-
// to retain the name as well.
53-
type ProfileConfig struct {
54-
// AllowMustStaple, when false, causes all IssuanceRequests which specify the
55-
// OCSP Must Staple extension to be rejected.
56-
AllowMustStaple bool
57-
// AllowCTPoison has no effect.
58-
// Deprecated: We will always allow the CT Poison extension because it is
59-
// mandated for Precertificates.
60-
AllowCTPoison bool
61-
// AllowSCTList has no effect.
62-
// Deprecated: We intend to include SCTs in all final Certificates for the
63-
// foreseeable future.
64-
AllowSCTList bool
65-
// AllowCommonName has no effect.
66-
// Deprecated: Rather than rejecting IssuanceRequests which include a common
67-
// name, we would prefer to simply drop the CN. Use `OmitCommonName` instead.
68-
AllowCommonName bool
69-
70-
// OmitCommonName causes the CN field to be excluded from the resulting
71-
// certificate, regardless of its inclusion in the IssuanceRequest.
72-
OmitCommonName bool
73-
// OmitKeyEncipherment causes the keyEncipherment bit to be omitted from the
74-
// Key Usage field of all certificates (instead of only from ECDSA certs).
75-
OmitKeyEncipherment bool
76-
// OmitClientAuth causes the id-kp-clientAuth OID (TLS Client Authentication)
77-
// to be omitted from the EKU extension.
78-
OmitClientAuth bool
79-
// OmitSKID causes the Subject Key Identifier extension to be omitted.
80-
OmitSKID bool
81-
82-
MaxValidityPeriod config.Duration
83-
MaxValidityBackdate config.Duration
84-
85-
// LintConfig is a path to a zlint config file, which can be used to control
86-
// the behavior of zlint's "customizable lints".
87-
LintConfig string
88-
// IgnoredLints is a list of lint names that we know will fail for this
89-
// profile, and which we know it is safe to ignore.
90-
IgnoredLints []string
91-
92-
// Deprecated: we do not respect this field.
93-
Policies []PolicyConfig `validate:"-"`
94-
}
95-
96-
// ProfileConfigNew describes the certificate issuance constraints for all issuers.
97-
//
98-
// See ProfileConfig for why this is called "New".
32+
// ProfileConfig describes the certificate issuance constraints for all issuers.
9933
//
10034
// This struct gets hashed in the CA to allow matching up precert and final cert
10135
// issuance by the exact profile config. We compute the hash over an ASN.1 encoding
@@ -106,7 +40,7 @@ type ProfileConfig struct {
10640
//
10741
// Note: even though these fields have encoding instructions (tag:N), they will
10842
// be encoded in the order they appear in the struct, so do not reorder them.
109-
type ProfileConfigNew struct {
43+
type ProfileConfig struct {
11044
// AllowMustStaple, when false, causes all IssuanceRequests which specify the
11145
// OCSP Must Staple extension to be rejected.
11246
AllowMustStaple bool `asn1:"tag:1,optional"`
@@ -137,32 +71,8 @@ type ProfileConfigNew struct {
13771
IgnoredLints []string `asn1:"tag:10,optional"`
13872
}
13973

140-
func (pcn ProfileConfigNew) Hash() ([32]byte, error) {
141-
var encodedBytes []byte
142-
var err error
143-
if !pcn.IncludeCRLDistributionPoints {
144-
old := ProfileConfig{
145-
AllowMustStaple: pcn.AllowMustStaple,
146-
AllowCTPoison: false,
147-
AllowSCTList: false,
148-
AllowCommonName: false,
149-
OmitCommonName: pcn.OmitCommonName,
150-
OmitKeyEncipherment: pcn.OmitKeyEncipherment,
151-
OmitClientAuth: pcn.OmitClientAuth,
152-
OmitSKID: pcn.OmitSKID,
153-
MaxValidityPeriod: pcn.MaxValidityPeriod,
154-
MaxValidityBackdate: pcn.MaxValidityBackdate,
155-
LintConfig: pcn.LintConfig,
156-
IgnoredLints: pcn.IgnoredLints,
157-
Policies: nil,
158-
}
159-
var encoded bytes.Buffer
160-
enc := gob.NewEncoder(&encoded)
161-
err = enc.Encode(old)
162-
encodedBytes = encoded.Bytes()
163-
} else {
164-
encodedBytes, err = asn1.Marshal(pcn)
165-
}
74+
func (pcn ProfileConfig) hash() ([32]byte, error) {
75+
encodedBytes, err := asn1.Marshal(pcn)
16676
if err != nil {
16777
return [32]byte{}, err
16878
}
@@ -193,7 +103,7 @@ type Profile struct {
193103
}
194104

195105
// NewProfile converts the profile config into a usable profile.
196-
func NewProfile(profileConfig *ProfileConfigNew) (*Profile, error) {
106+
func NewProfile(profileConfig *ProfileConfig) (*Profile, error) {
197107
// The Baseline Requirements, Section 7.1.2.7, says that the notBefore time
198108
// must be "within 48 hours of the time of signing". We can be even stricter.
199109
if profileConfig.MaxValidityBackdate.Duration >= 24*time.Hour {
@@ -214,7 +124,7 @@ func NewProfile(profileConfig *ProfileConfigNew) (*Profile, error) {
214124
lints.SetConfiguration(lintconfig)
215125
}
216126

217-
hash, err := profileConfig.Hash()
127+
hash, err := profileConfig.hash()
218128
if err != nil {
219129
return nil, err
220130
}

issuance/cert_test.go

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -870,32 +870,9 @@ func TestMismatchedProfiles(t *testing.T) {
870870
}
871871

872872
func TestProfileHash(t *testing.T) {
873-
// A profile without IncludeCRLDistributionPoints.
874-
// Hash calculated over the gob encoding of the old `ProfileConfig`.
875-
profile := ProfileConfigNew{
876-
IncludeCRLDistributionPoints: false,
877-
AllowMustStaple: true,
878-
OmitCommonName: true,
879-
OmitKeyEncipherment: false,
880-
OmitClientAuth: false,
881-
OmitSKID: true,
882-
MaxValidityPeriod: config.Duration{Duration: time.Hour},
883-
MaxValidityBackdate: config.Duration{Duration: time.Second},
884-
LintConfig: "example/config.toml",
885-
IgnoredLints: []string{"one", "two"},
886-
}
887-
hash, err := profile.Hash()
888-
if err != nil {
889-
t.Fatalf("hashing %+v: %s", profile, err)
890-
}
891-
expectedHash := "f6b5766141fdc066824e781347095ffb3c86fa97a174e21123a323a93b078f46"
892-
if expectedHash != fmt.Sprintf("%x", hash) {
893-
t.Errorf("%+v.Hash()=%x, want %s", profile, hash, expectedHash)
894-
}
895-
896873
// A profile _with_ IncludeCRLDistributionPoints.
897874
// Hash calculated over the ASN.1 encoding of the `ProfileConfigNew`.
898-
profile = ProfileConfigNew{
875+
profile := ProfileConfig{
899876
IncludeCRLDistributionPoints: true,
900877
AllowMustStaple: true,
901878
OmitCommonName: true,
@@ -907,11 +884,11 @@ func TestProfileHash(t *testing.T) {
907884
LintConfig: "example/config.toml",
908885
IgnoredLints: []string{"one", "two"},
909886
}
910-
hash, err = profile.Hash()
887+
hash, err := profile.hash()
911888
if err != nil {
912889
t.Fatalf("hashing %+v: %s", profile, err)
913890
}
914-
expectedHash = "d2a6c9f0aa37d2ac0b15476cb6e0ae9b98ba59b1321d8d6da26efc620581c53d"
891+
expectedHash := "d2a6c9f0aa37d2ac0b15476cb6e0ae9b98ba59b1321d8d6da26efc620581c53d"
915892
if expectedHash != fmt.Sprintf("%x", hash) {
916893
t.Errorf("%+v.Hash()=%x, want %s", profile, hash, expectedHash)
917894
}

issuance/issuer_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ import (
2222
"github.com/letsencrypt/boulder/test"
2323
)
2424

25-
func defaultProfileConfig() *ProfileConfigNew {
26-
return &ProfileConfigNew{
25+
func defaultProfileConfig() *ProfileConfig {
26+
return &ProfileConfig{
2727
AllowMustStaple: true,
2828
MaxValidityPeriod: config.Duration{Duration: time.Hour},
2929
MaxValidityBackdate: config.Duration{Duration: time.Hour},

test/config-next/ca.json

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,7 @@
5555
"certProfiles": {
5656
"legacy": {
5757
"allowMustStaple": true,
58-
"maxValidityPeriod": "7776000s",
59-
"maxValidityBackdate": "1h5m",
6058
"includeCRLDistributionPoints": true,
61-
"lintConfig": "test/config-next/zlint.toml",
62-
"ignoredLints": [
63-
"w_subject_common_name_included",
64-
"w_ext_subject_key_identifier_not_recommended_subscriber"
65-
]
66-
},
67-
"legacyRenamedPriorToDeletion": {
68-
"allowMustStaple": true,
6959
"maxValidityPeriod": "7776000s",
7060
"maxValidityBackdate": "1h5m",
7161
"lintConfig": "test/config-next/zlint.toml",
@@ -88,19 +78,6 @@
8878
"w_ext_subject_key_identifier_missing_sub_cert"
8979
]
9080
},
91-
"modernRenamedPriorToDeletion": {
92-
"allowMustStaple": true,
93-
"omitCommonName": true,
94-
"omitKeyEncipherment": true,
95-
"omitClientAuth": true,
96-
"omitSKID": true,
97-
"maxValidityPeriod": "583200s",
98-
"maxValidityBackdate": "1h5m",
99-
"lintConfig": "test/config-next/zlint.toml",
100-
"ignoredLints": [
101-
"w_ext_subject_key_identifier_missing_sub_cert"
102-
]
103-
},
10481
"shortlived": {
10582
"allowMustStaple": true,
10683
"omitCommonName": true,

0 commit comments

Comments
 (0)