Configure lints separately for each profile (#7636)
Move the two lint-configuration keys, LintConfig and IgnoreLints, from the top-level CA.Issuance config stanza into each individual CA.Issuance.CertProfiles stanza. This allows us to have differently-configured lints for different profiles, to ensure that our linting regime is as strict as possible. Without this change, it would be necessary for us to ignore both the "common name included" and the "no subject key id" lints at the top-level, when in fact each of those warnings only triggers on one of our two profiles. Fixes https://github.com/letsencrypt/boulder/issues/7635
This commit is contained in:
parent
c13591ab82
commit
7b6935d223
11
ca/ca.go
11
ca/ca.go
|
|
@ -23,7 +23,6 @@ import (
|
|||
"github.com/jmhodges/clock"
|
||||
"github.com/miekg/pkcs11"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/zmap/zlint/v3/lint"
|
||||
"golang.org/x/crypto/cryptobyte"
|
||||
cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
|
||||
"golang.org/x/crypto/ocsp"
|
||||
|
|
@ -166,14 +165,13 @@ func makeIssuerMaps(issuers []*issuance.Issuer) (issuerMaps, error) {
|
|||
// profile configs into a two pre-computed maps: 1) a human-readable name to the
|
||||
// profile and 2) a unique hash over contents of the profile to the profile
|
||||
// itself. It returns the maps or an error if a duplicate name or hash is found.
|
||||
// It also associates the given lint registry with each profile.
|
||||
//
|
||||
// The unique hash is used in the case of
|
||||
// - RA instructs CA1 to issue a precertificate
|
||||
// - CA1 returns the precertificate DER bytes and profile hash to the RA
|
||||
// - RA instructs CA2 to issue a final certificate, but CA2 does not contain a
|
||||
// profile corresponding to that hash and an issuance is prevented.
|
||||
func makeCertificateProfilesMap(defaultName string, profiles map[string]issuance.ProfileConfig, lints lint.Registry) (certProfilesMaps, error) {
|
||||
func makeCertificateProfilesMap(defaultName string, profiles map[string]*issuance.ProfileConfig) (certProfilesMaps, error) {
|
||||
if len(profiles) <= 0 {
|
||||
return certProfilesMaps{}, fmt.Errorf("must pass at least one certificate profile")
|
||||
}
|
||||
|
|
@ -188,7 +186,7 @@ func makeCertificateProfilesMap(defaultName string, profiles map[string]issuance
|
|||
profilesByHash := make(map[[32]byte]*certProfileWithID, len(profiles))
|
||||
|
||||
for name, profileConfig := range profiles {
|
||||
profile, err := issuance.NewProfile(profileConfig, lints)
|
||||
profile, err := issuance.NewProfile(profileConfig)
|
||||
if err != nil {
|
||||
return certProfilesMaps{}, err
|
||||
}
|
||||
|
|
@ -234,8 +232,7 @@ func NewCertificateAuthorityImpl(
|
|||
pa core.PolicyAuthority,
|
||||
boulderIssuers []*issuance.Issuer,
|
||||
defaultCertProfileName string,
|
||||
certificateProfiles map[string]issuance.ProfileConfig,
|
||||
lints lint.Registry,
|
||||
certificateProfiles map[string]*issuance.ProfileConfig,
|
||||
serialPrefix int,
|
||||
maxNames int,
|
||||
keyPolicy goodkey.KeyPolicy,
|
||||
|
|
@ -255,7 +252,7 @@ func NewCertificateAuthorityImpl(
|
|||
return nil, errors.New("must have at least one issuer")
|
||||
}
|
||||
|
||||
certProfiles, err := makeCertificateProfilesMap(defaultCertProfileName, certificateProfiles, lints)
|
||||
certProfiles, err := makeCertificateProfilesMap(defaultCertProfileName, certificateProfiles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import (
|
|||
"github.com/jmhodges/clock"
|
||||
"github.com/miekg/pkcs11"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/zmap/zlint/v3/lint"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
|
||||
|
|
@ -34,7 +33,6 @@ import (
|
|||
"github.com/letsencrypt/boulder/features"
|
||||
"github.com/letsencrypt/boulder/goodkey"
|
||||
"github.com/letsencrypt/boulder/issuance"
|
||||
"github.com/letsencrypt/boulder/linter"
|
||||
blog "github.com/letsencrypt/boulder/log"
|
||||
"github.com/letsencrypt/boulder/metrics"
|
||||
"github.com/letsencrypt/boulder/must"
|
||||
|
|
@ -104,8 +102,7 @@ type testCtx struct {
|
|||
ocsp *ocspImpl
|
||||
crl *crlImpl
|
||||
defaultCertProfileName string
|
||||
lints lint.Registry
|
||||
certProfiles map[string]issuance.ProfileConfig
|
||||
certProfiles map[string]*issuance.ProfileConfig
|
||||
serialPrefix int
|
||||
maxNames int
|
||||
boulderIssuers []*issuance.Issuer
|
||||
|
|
@ -156,13 +153,14 @@ func setup(t *testing.T) *testCtx {
|
|||
err = pa.LoadHostnamePolicyFile("../test/hostname-policy.yaml")
|
||||
test.AssertNotError(t, err, "Couldn't set hostname policy")
|
||||
|
||||
certProfiles := make(map[string]issuance.ProfileConfig, 0)
|
||||
certProfiles["legacy"] = issuance.ProfileConfig{
|
||||
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"},
|
||||
}
|
||||
certProfiles["modern"] = issuance.ProfileConfig{
|
||||
certProfiles["modern"] = &issuance.ProfileConfig{
|
||||
AllowMustStaple: true,
|
||||
OmitCommonName: true,
|
||||
OmitKeyEncipherment: true,
|
||||
|
|
@ -170,6 +168,7 @@ func setup(t *testing.T) *testCtx {
|
|||
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"},
|
||||
}
|
||||
test.AssertEquals(t, len(certProfiles), 2)
|
||||
|
||||
|
|
@ -208,9 +207,6 @@ func setup(t *testing.T) *testCtx {
|
|||
})
|
||||
cametrics := &caMetrics{signatureCount, signErrorCount, lintErrorCount}
|
||||
|
||||
lints, err := linter.NewRegistry([]string{"w_subject_common_name_included"})
|
||||
test.AssertNotError(t, err, "Failed to create zlint registry")
|
||||
|
||||
ocsp, err := NewOCSPImpl(
|
||||
boulderIssuers,
|
||||
24*time.Hour,
|
||||
|
|
@ -240,7 +236,6 @@ func setup(t *testing.T) *testCtx {
|
|||
ocsp: ocsp,
|
||||
crl: crl,
|
||||
defaultCertProfileName: "legacy",
|
||||
lints: lints,
|
||||
certProfiles: certProfiles,
|
||||
serialPrefix: 17,
|
||||
maxNames: 2,
|
||||
|
|
@ -262,7 +257,6 @@ func TestSerialPrefix(t *testing.T) {
|
|||
nil,
|
||||
"",
|
||||
nil,
|
||||
nil,
|
||||
0,
|
||||
testCtx.maxNames,
|
||||
testCtx.keyPolicy,
|
||||
|
|
@ -277,7 +271,6 @@ func TestSerialPrefix(t *testing.T) {
|
|||
nil,
|
||||
"",
|
||||
nil,
|
||||
nil,
|
||||
128,
|
||||
testCtx.maxNames,
|
||||
testCtx.keyPolicy,
|
||||
|
|
@ -375,7 +368,6 @@ func issueCertificateSubTestSetup(t *testing.T) (*certificateAuthorityImpl, *moc
|
|||
testCtx.boulderIssuers,
|
||||
testCtx.defaultCertProfileName,
|
||||
testCtx.certProfiles,
|
||||
testCtx.lints,
|
||||
testCtx.serialPrefix,
|
||||
testCtx.maxNames,
|
||||
testCtx.keyPolicy,
|
||||
|
|
@ -415,7 +407,6 @@ func TestNoIssuers(t *testing.T) {
|
|||
nil, // No issuers
|
||||
testCtx.defaultCertProfileName,
|
||||
testCtx.certProfiles,
|
||||
testCtx.lints,
|
||||
testCtx.serialPrefix,
|
||||
testCtx.maxNames,
|
||||
testCtx.keyPolicy,
|
||||
|
|
@ -437,7 +428,6 @@ func TestMultipleIssuers(t *testing.T) {
|
|||
testCtx.boulderIssuers,
|
||||
testCtx.defaultCertProfileName,
|
||||
testCtx.certProfiles,
|
||||
testCtx.lints,
|
||||
testCtx.serialPrefix,
|
||||
testCtx.maxNames,
|
||||
testCtx.keyPolicy,
|
||||
|
|
@ -512,7 +502,6 @@ func TestUnpredictableIssuance(t *testing.T) {
|
|||
boulderIssuers,
|
||||
testCtx.defaultCertProfileName,
|
||||
testCtx.certProfiles,
|
||||
testCtx.lints,
|
||||
testCtx.serialPrefix,
|
||||
testCtx.maxNames,
|
||||
testCtx.keyPolicy,
|
||||
|
|
@ -572,7 +561,7 @@ func TestMakeCertificateProfilesMap(t *testing.T) {
|
|||
testCases := []struct {
|
||||
name string
|
||||
defaultName string
|
||||
profileConfigs map[string]issuance.ProfileConfig
|
||||
profileConfigs map[string]*issuance.ProfileConfig
|
||||
expectedErrSubstr string
|
||||
expectedProfiles []nameToHash
|
||||
}{
|
||||
|
|
@ -583,36 +572,36 @@ func TestMakeCertificateProfilesMap(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "no profiles",
|
||||
profileConfigs: map[string]issuance.ProfileConfig{},
|
||||
profileConfigs: map[string]*issuance.ProfileConfig{},
|
||||
expectedErrSubstr: "at least one certificate profile",
|
||||
},
|
||||
{
|
||||
name: "no profile matching default name",
|
||||
defaultName: "default",
|
||||
profileConfigs: map[string]issuance.ProfileConfig{
|
||||
"notDefault": testProfile,
|
||||
profileConfigs: map[string]*issuance.ProfileConfig{
|
||||
"notDefault": &testProfile,
|
||||
},
|
||||
expectedErrSubstr: "profile object was not found for that name",
|
||||
},
|
||||
{
|
||||
name: "duplicate hash",
|
||||
defaultName: "default",
|
||||
profileConfigs: map[string]issuance.ProfileConfig{
|
||||
"default": testProfile,
|
||||
"default2": testProfile,
|
||||
profileConfigs: map[string]*issuance.ProfileConfig{
|
||||
"default": &testProfile,
|
||||
"default2": &testProfile,
|
||||
},
|
||||
expectedErrSubstr: "duplicate certificate profile hash",
|
||||
},
|
||||
{
|
||||
name: "empty profile config",
|
||||
defaultName: "empty",
|
||||
profileConfigs: map[string]issuance.ProfileConfig{
|
||||
profileConfigs: map[string]*issuance.ProfileConfig{
|
||||
"empty": {},
|
||||
},
|
||||
expectedProfiles: []nameToHash{
|
||||
{
|
||||
name: "empty",
|
||||
hash: [32]byte{0xec, 0xf4, 0x43, 0xe, 0x26, 0x1, 0x8c, 0x8b, 0x85, 0x83, 0x0, 0x6f, 0x55, 0xbd, 0x45, 0xd8, 0x66, 0x88, 0x95, 0x41, 0xd0, 0x9f, 0x8, 0x2e, 0x9b, 0x2b, 0xc9, 0x8a, 0xb4, 0x86, 0x69, 0x59},
|
||||
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},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -623,11 +612,11 @@ func TestMakeCertificateProfilesMap(t *testing.T) {
|
|||
expectedProfiles: []nameToHash{
|
||||
{
|
||||
name: "legacy",
|
||||
hash: [32]byte{0x1e, 0x35, 0x19, 0x16, 0x69, 0xff, 0x4, 0x7b, 0xa5, 0xb5, 0xf, 0x2b, 0x59, 0x88, 0x7e, 0xe4, 0x22, 0x23, 0xb1, 0xad, 0xfc, 0x18, 0xe9, 0x9c, 0x57, 0x3f, 0x3, 0x95, 0xe3, 0xac, 0xff, 0x3c},
|
||||
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},
|
||||
},
|
||||
{
|
||||
name: "modern",
|
||||
hash: [32]byte{0xa7, 0x9b, 0xb1, 0x14, 0x8e, 0x12, 0x4, 0xb4, 0xb1, 0x14, 0xe9, 0x78, 0x2e, 0x4c, 0x20, 0x91, 0x90, 0xd0, 0x2d, 0x4e, 0x30, 0x96, 0xb2, 0xcf, 0xe0, 0xff, 0x70, 0x1f, 0x4e, 0x51, 0xf, 0x1e},
|
||||
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},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -636,9 +625,7 @@ func TestMakeCertificateProfilesMap(t *testing.T) {
|
|||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
profiles, err := makeCertificateProfilesMap(
|
||||
tc.defaultName, tc.profileConfigs, lint.NewRegistry(),
|
||||
)
|
||||
profiles, err := makeCertificateProfilesMap(tc.defaultName, tc.profileConfigs)
|
||||
|
||||
if tc.expectedErrSubstr != "" {
|
||||
test.AssertError(t, err, "profile construction should have failed")
|
||||
|
|
@ -726,7 +713,6 @@ func TestInvalidCSRs(t *testing.T) {
|
|||
testCtx.boulderIssuers,
|
||||
testCtx.defaultCertProfileName,
|
||||
testCtx.certProfiles,
|
||||
testCtx.lints,
|
||||
testCtx.serialPrefix,
|
||||
testCtx.maxNames,
|
||||
testCtx.keyPolicy,
|
||||
|
|
@ -766,7 +752,6 @@ func TestRejectValidityTooLong(t *testing.T) {
|
|||
testCtx.boulderIssuers,
|
||||
testCtx.defaultCertProfileName,
|
||||
testCtx.certProfiles,
|
||||
testCtx.lints,
|
||||
testCtx.serialPrefix,
|
||||
testCtx.maxNames,
|
||||
testCtx.keyPolicy,
|
||||
|
|
@ -860,7 +845,6 @@ func TestIssueCertificateForPrecertificate(t *testing.T) {
|
|||
testCtx.boulderIssuers,
|
||||
testCtx.defaultCertProfileName,
|
||||
testCtx.certProfiles,
|
||||
testCtx.lints,
|
||||
testCtx.serialPrefix,
|
||||
testCtx.maxNames,
|
||||
testCtx.keyPolicy,
|
||||
|
|
@ -926,7 +910,6 @@ func TestIssueCertificateForPrecertificateWithSpecificCertificateProfile(t *test
|
|||
testCtx.boulderIssuers,
|
||||
testCtx.defaultCertProfileName,
|
||||
testCtx.certProfiles,
|
||||
testCtx.lints,
|
||||
testCtx.serialPrefix,
|
||||
testCtx.maxNames,
|
||||
testCtx.keyPolicy,
|
||||
|
|
@ -1043,7 +1026,6 @@ func TestIssueCertificateForPrecertificateDuplicateSerial(t *testing.T) {
|
|||
testCtx.boulderIssuers,
|
||||
testCtx.defaultCertProfileName,
|
||||
testCtx.certProfiles,
|
||||
testCtx.lints,
|
||||
testCtx.serialPrefix,
|
||||
testCtx.maxNames,
|
||||
testCtx.keyPolicy,
|
||||
|
|
@ -1091,7 +1073,6 @@ func TestIssueCertificateForPrecertificateDuplicateSerial(t *testing.T) {
|
|||
testCtx.boulderIssuers,
|
||||
testCtx.defaultCertProfileName,
|
||||
testCtx.certProfiles,
|
||||
testCtx.lints,
|
||||
testCtx.serialPrefix,
|
||||
testCtx.maxNames,
|
||||
testCtx.keyPolicy,
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ func TestOCSP(t *testing.T) {
|
|||
testCtx.boulderIssuers,
|
||||
testCtx.defaultCertProfileName,
|
||||
testCtx.certProfiles,
|
||||
testCtx.lints,
|
||||
testCtx.serialPrefix,
|
||||
testCtx.maxNames,
|
||||
testCtx.keyPolicy,
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@ import (
|
|||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/zmap/zlint/v3/lint"
|
||||
|
||||
"github.com/letsencrypt/boulder/ca"
|
||||
capb "github.com/letsencrypt/boulder/ca/proto"
|
||||
"github.com/letsencrypt/boulder/cmd"
|
||||
|
|
@ -19,7 +17,6 @@ import (
|
|||
"github.com/letsencrypt/boulder/goodkey/sagoodkey"
|
||||
bgrpc "github.com/letsencrypt/boulder/grpc"
|
||||
"github.com/letsencrypt/boulder/issuance"
|
||||
"github.com/letsencrypt/boulder/linter"
|
||||
"github.com/letsencrypt/boulder/policy"
|
||||
sapb "github.com/letsencrypt/boulder/sa/proto"
|
||||
)
|
||||
|
|
@ -48,12 +45,18 @@ type Config struct {
|
|||
|
||||
// One of the profile names must match the value of
|
||||
// DefaultCertificateProfileName or boulder-ca will fail to start.
|
||||
CertProfiles map[string]issuance.ProfileConfig `validate:"dive,keys,alphanum,min=1,max=32,endkeys,required_without=Profile,structonly"`
|
||||
CertProfiles map[string]*issuance.ProfileConfig `validate:"dive,keys,alphanum,min=1,max=32,endkeys,required_without=Profile,structonly"`
|
||||
|
||||
// TODO(#7159): Make this required once all live configs are using it.
|
||||
CRLProfile issuance.CRLProfileConfig `validate:"-"`
|
||||
Issuers []issuance.IssuerConfig `validate:"min=1,dive"`
|
||||
LintConfig string
|
||||
CRLProfile issuance.CRLProfileConfig `validate:"-"`
|
||||
Issuers []issuance.IssuerConfig `validate:"min=1,dive"`
|
||||
|
||||
// LintConfig is a path to a zlint config file.
|
||||
// Deprecated: Use CertProfiles.LintConfig instead.
|
||||
LintConfig string
|
||||
// IgnoredLints is a list of lint names for which any errors should be
|
||||
// ignored.
|
||||
// Deprecated: Use CertProfiles.IgnoredLints instead.
|
||||
IgnoredLints []string
|
||||
}
|
||||
|
||||
|
|
@ -209,19 +212,22 @@ func main() {
|
|||
cmd.Fail("Only one of Issuance.Profile or Issuance.CertProfiles can be configured")
|
||||
}
|
||||
|
||||
// TODO(#7414) Remove this check.
|
||||
// Use the deprecated Profile as a CertProfiles
|
||||
// If no individual cert profiles are configured, pretend that the deprecated
|
||||
// top-level profile as the only individual profile instead.
|
||||
// TODO(#7414) Remove this fallback.
|
||||
if len(c.CA.Issuance.CertProfiles) == 0 {
|
||||
c.CA.Issuance.CertProfiles = make(map[string]issuance.ProfileConfig, 0)
|
||||
c.CA.Issuance.CertProfiles[c.CA.Issuance.DefaultCertificateProfileName] = c.CA.Issuance.Profile
|
||||
c.CA.Issuance.CertProfiles = make(map[string]*issuance.ProfileConfig, 0)
|
||||
c.CA.Issuance.CertProfiles[c.CA.Issuance.DefaultCertificateProfileName] = &c.CA.Issuance.Profile
|
||||
}
|
||||
|
||||
lints, err := linter.NewRegistry(c.CA.Issuance.IgnoredLints)
|
||||
cmd.FailOnError(err, "Failed to create zlint registry")
|
||||
if c.CA.Issuance.LintConfig != "" {
|
||||
lintconfig, err := lint.NewConfigFromFile(c.CA.Issuance.LintConfig)
|
||||
cmd.FailOnError(err, "Failed to load zlint config file")
|
||||
lints.SetConfiguration(lintconfig)
|
||||
// If any individual cert profile doesn't have its own lint configuration,
|
||||
// instead copy in the deprecated top-level lint configuration.
|
||||
// TODO(#7414): Remove this fallback.
|
||||
for _, prof := range c.CA.Issuance.CertProfiles {
|
||||
if prof.LintConfig == "" && len(prof.IgnoredLints) == 0 {
|
||||
prof.LintConfig = c.CA.Issuance.LintConfig
|
||||
prof.IgnoredLints = c.CA.Issuance.IgnoredLints
|
||||
}
|
||||
}
|
||||
|
||||
tlsConfig, err := c.CA.TLS.Load(scope)
|
||||
|
|
@ -274,7 +280,6 @@ func main() {
|
|||
issuers,
|
||||
c.CA.Issuance.DefaultCertificateProfileName,
|
||||
c.CA.Issuance.CertProfiles,
|
||||
lints,
|
||||
c.CA.SerialPrefix,
|
||||
c.CA.MaxNames,
|
||||
kp,
|
||||
|
|
|
|||
|
|
@ -21,7 +21,9 @@ import (
|
|||
"github.com/jmhodges/clock"
|
||||
"github.com/zmap/zlint/v3/lint"
|
||||
|
||||
"github.com/letsencrypt/boulder/cmd"
|
||||
"github.com/letsencrypt/boulder/config"
|
||||
"github.com/letsencrypt/boulder/linter"
|
||||
"github.com/letsencrypt/boulder/precert"
|
||||
)
|
||||
|
||||
|
|
@ -58,6 +60,13 @@ type ProfileConfig struct {
|
|||
MaxValidityPeriod config.Duration
|
||||
MaxValidityBackdate config.Duration
|
||||
|
||||
// LintConfig is a path to a zlint config file, which can be used to control
|
||||
// the behavior of zlint's "customizable lints".
|
||||
LintConfig string
|
||||
// IgnoredLints is a list of lint names that we know will fail for this
|
||||
// profile, and which we know it is safe to ignore.
|
||||
IgnoredLints []string
|
||||
|
||||
// Deprecated: we do not respect this field.
|
||||
Policies []PolicyConfig `validate:"-"`
|
||||
}
|
||||
|
|
@ -81,8 +90,8 @@ type Profile struct {
|
|||
lints lint.Registry
|
||||
}
|
||||
|
||||
// NewProfile converts the profile config and lint registry into a usable profile.
|
||||
func NewProfile(profileConfig ProfileConfig, lints lint.Registry) (*Profile, error) {
|
||||
// NewProfile converts the profile config into a usable profile.
|
||||
func NewProfile(profileConfig *ProfileConfig) (*Profile, error) {
|
||||
// The Baseline Requirements, Section 7.1.2.7, says that the notBefore time
|
||||
// must be "within 48 hours of the time of signing". We can be even stricter.
|
||||
if profileConfig.MaxValidityBackdate.Duration >= 24*time.Hour {
|
||||
|
|
@ -95,6 +104,14 @@ func NewProfile(profileConfig ProfileConfig, lints lint.Registry) (*Profile, err
|
|||
return nil, fmt.Errorf("validity period %q is too large", profileConfig.MaxValidityPeriod.Duration)
|
||||
}
|
||||
|
||||
lints, err := linter.NewRegistry(profileConfig.IgnoredLints)
|
||||
cmd.FailOnError(err, "Failed to create zlint registry")
|
||||
if profileConfig.LintConfig != "" {
|
||||
lintconfig, err := lint.NewConfigFromFile(profileConfig.LintConfig)
|
||||
cmd.FailOnError(err, "Failed to load zlint config file")
|
||||
lints.SetConfiguration(lintconfig)
|
||||
}
|
||||
|
||||
sp := &Profile{
|
||||
allowMustStaple: profileConfig.AllowMustStaple,
|
||||
omitCommonName: profileConfig.OmitCommonName,
|
||||
|
|
|
|||
|
|
@ -27,11 +27,7 @@ var (
|
|||
)
|
||||
|
||||
func defaultProfile() *Profile {
|
||||
lints, _ := linter.NewRegistry([]string{
|
||||
"w_ct_sct_policy_count_unsatisfied",
|
||||
"e_scts_from_same_operator",
|
||||
})
|
||||
p, _ := NewProfile(defaultProfileConfig(), lints)
|
||||
p, _ := NewProfile(defaultProfileConfig())
|
||||
return p
|
||||
}
|
||||
|
||||
|
|
@ -390,13 +386,13 @@ func TestIssueCommonName(t *testing.T) {
|
|||
fc := clock.NewFake()
|
||||
fc.Set(time.Now())
|
||||
|
||||
lints, err := linter.NewRegistry([]string{
|
||||
prof := defaultProfileConfig()
|
||||
prof.IgnoredLints = []string{
|
||||
"w_subject_common_name_included",
|
||||
"w_ct_sct_policy_count_unsatisfied",
|
||||
"e_scts_from_same_operator",
|
||||
})
|
||||
test.AssertNotError(t, err, "building test lint registry")
|
||||
cnProfile, err := NewProfile(defaultProfileConfig(), lints)
|
||||
}
|
||||
cnProfile, err := NewProfile(prof)
|
||||
test.AssertNotError(t, err, "NewProfile failed")
|
||||
signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc)
|
||||
test.AssertNotError(t, err, "NewIssuer failed")
|
||||
|
|
@ -448,18 +444,17 @@ func TestIssueOmissions(t *testing.T) {
|
|||
fc := clock.NewFake()
|
||||
fc.Set(time.Now())
|
||||
|
||||
lints, err := linter.NewRegistry([]string{
|
||||
"w_ext_subject_key_identifier_missing_sub_cert",
|
||||
"w_ct_sct_policy_count_unsatisfied",
|
||||
"e_scts_from_same_operator",
|
||||
})
|
||||
test.AssertNotError(t, err, "building test lint registry")
|
||||
pc := defaultProfileConfig()
|
||||
pc.OmitCommonName = true
|
||||
pc.OmitKeyEncipherment = true
|
||||
pc.OmitClientAuth = true
|
||||
pc.OmitSKID = true
|
||||
prof, err := NewProfile(pc, lints)
|
||||
pc.IgnoredLints = []string{
|
||||
"w_ext_subject_key_identifier_missing_sub_cert",
|
||||
"w_ct_sct_policy_count_unsatisfied",
|
||||
"e_scts_from_same_operator",
|
||||
}
|
||||
prof, err := NewProfile(pc)
|
||||
test.AssertNotError(t, err, "building test profile")
|
||||
|
||||
signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc)
|
||||
|
|
@ -533,9 +528,9 @@ func TestIssueSCTList(t *testing.T) {
|
|||
err := loglist.InitLintList("../test/ct-test-srv/log_list.json")
|
||||
test.AssertNotError(t, err, "failed to load log list")
|
||||
|
||||
lints, err := linter.NewRegistry([]string{})
|
||||
test.AssertNotError(t, err, "building test lint registry")
|
||||
enforceSCTsProfile, err := NewProfile(defaultProfileConfig(), lints)
|
||||
pc := defaultProfileConfig()
|
||||
pc.IgnoredLints = []string{}
|
||||
enforceSCTsProfile, err := NewProfile(pc)
|
||||
test.AssertNotError(t, err, "NewProfile failed")
|
||||
signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc)
|
||||
test.AssertNotError(t, err, "NewIssuer failed")
|
||||
|
|
@ -632,9 +627,9 @@ func TestIssueBadLint(t *testing.T) {
|
|||
fc := clock.NewFake()
|
||||
fc.Set(time.Now())
|
||||
|
||||
lints, err := linter.NewRegistry([]string{})
|
||||
test.AssertNotError(t, err, "building test lint registry")
|
||||
noSkipLintsProfile, err := NewProfile(defaultProfileConfig(), lints)
|
||||
pc := defaultProfileConfig()
|
||||
pc.IgnoredLints = []string{}
|
||||
noSkipLintsProfile, err := NewProfile(pc)
|
||||
test.AssertNotError(t, err, "NewProfile failed")
|
||||
signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc)
|
||||
test.AssertNotError(t, err, "NewIssuer failed")
|
||||
|
|
@ -758,13 +753,13 @@ func TestMismatchedProfiles(t *testing.T) {
|
|||
issuer1, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc)
|
||||
test.AssertNotError(t, err, "NewIssuer failed")
|
||||
|
||||
lints, err := linter.NewRegistry([]string{
|
||||
pc := defaultProfileConfig()
|
||||
pc.IgnoredLints = []string{
|
||||
"w_subject_common_name_included",
|
||||
"w_ct_sct_policy_count_unsatisfied",
|
||||
"e_scts_from_same_operator",
|
||||
})
|
||||
test.AssertNotError(t, err, "building test lint registry")
|
||||
cnProfile, err := NewProfile(defaultProfileConfig(), lints)
|
||||
}
|
||||
cnProfile, err := NewProfile(pc)
|
||||
test.AssertNotError(t, err, "NewProfile failed")
|
||||
|
||||
pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
|
|
@ -785,14 +780,14 @@ func TestMismatchedProfiles(t *testing.T) {
|
|||
test.AssertNotError(t, err, "signing precert")
|
||||
|
||||
// Create a new profile that differs slightly (no common name)
|
||||
profileConfig := defaultProfileConfig()
|
||||
profileConfig.AllowCommonName = false
|
||||
lints, err = linter.NewRegistry([]string{
|
||||
pc = defaultProfileConfig()
|
||||
pc.AllowCommonName = false
|
||||
pc.IgnoredLints = []string{
|
||||
"w_ct_sct_policy_count_unsatisfied",
|
||||
"e_scts_from_same_operator",
|
||||
})
|
||||
}
|
||||
test.AssertNotError(t, err, "building test lint registry")
|
||||
noCNProfile, err := NewProfile(profileConfig, lints)
|
||||
noCNProfile, err := NewProfile(pc)
|
||||
test.AssertNotError(t, err, "NewProfile failed")
|
||||
|
||||
issuer2, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc)
|
||||
|
|
|
|||
|
|
@ -22,11 +22,15 @@ import (
|
|||
"github.com/letsencrypt/boulder/test"
|
||||
)
|
||||
|
||||
func defaultProfileConfig() ProfileConfig {
|
||||
return ProfileConfig{
|
||||
func defaultProfileConfig() *ProfileConfig {
|
||||
return &ProfileConfig{
|
||||
AllowMustStaple: true,
|
||||
MaxValidityPeriod: config.Duration{Duration: time.Hour},
|
||||
MaxValidityBackdate: config.Duration{Duration: time.Hour},
|
||||
IgnoredLints: []string{
|
||||
"w_ct_sct_policy_count_unsatisfied",
|
||||
"e_scts_from_same_operator",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,12 @@
|
|||
"legacy": {
|
||||
"allowMustStaple": true,
|
||||
"maxValidityPeriod": "7776000s",
|
||||
"maxValidityBackdate": "1h5m"
|
||||
"maxValidityBackdate": "1h5m",
|
||||
"lintConfig": "test/config-next/zlint.toml",
|
||||
"ignoredLints": [
|
||||
"w_subject_common_name_included",
|
||||
"w_sub_cert_aia_contains_internal_names"
|
||||
]
|
||||
},
|
||||
"modern": {
|
||||
"allowMustStaple": true,
|
||||
|
|
@ -56,7 +61,12 @@
|
|||
"omitClientAuth": true,
|
||||
"omitSKID": true,
|
||||
"maxValidityPeriod": "583200s",
|
||||
"maxValidityBackdate": "1h5m"
|
||||
"maxValidityBackdate": "1h5m",
|
||||
"lintConfig": "test/config-next/zlint.toml",
|
||||
"ignoredLints": [
|
||||
"w_ext_subject_key_identifier_missing_sub_cert",
|
||||
"w_sub_cert_aia_contains_internal_names"
|
||||
]
|
||||
}
|
||||
},
|
||||
"crlProfile": {
|
||||
|
|
@ -130,11 +140,6 @@
|
|||
"numSessions": 2
|
||||
}
|
||||
}
|
||||
],
|
||||
"lintConfig": "test/config-next/zlint.toml",
|
||||
"ignoredLints": [
|
||||
"w_subject_common_name_included",
|
||||
"w_sub_cert_aia_contains_internal_names"
|
||||
]
|
||||
},
|
||||
"serialPrefix": 127,
|
||||
|
|
|
|||
Loading…
Reference in New Issue