Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lints: add new lints for Mozilla Root Store Policy (adopted) #353

Merged
merged 44 commits into from
Jan 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
3da3eaf
Lints: add new lints for Mozilla Root Store Policy.
fotisl Oct 2, 2019
2551ecc
Split Mozilla Root Store Policy RSA key lint
fotisl Oct 4, 2019
b682246
Deleted old Mozilla Root Store Policy RSA key lint.
fotisl Oct 4, 2019
31bcd3f
Moved hasEKU() to util package.
fotisl Oct 4, 2019
549b6a9
Added fetching Mozilla Trust Store SPKIs.
fotisl Oct 7, 2019
076268e
Added cross-cert detection for MP EKU lint.
fotisl Oct 7, 2019
a60ffb3
Added fatal error details to MP AuthKeyID lint.
fotisl Oct 7, 2019
762bcc3
Minor style change.
fotisl Oct 7, 2019
43b0e8c
Added error details to MP ECDSA lint.
fotisl Oct 7, 2019
223ed00
Renamed lint_mp_allowed_rsa_keys_exponent to e_mp_exponent_cannot_be_…
fotisl Oct 17, 2019
855427c
Split RSA modulus lints into two files.
fotisl Oct 17, 2019
c95b61f
Minor fix in test function name.
fotisl Oct 17, 2019
6a156ff
Update lints/lint_mp_modulus_must_be_divisible_by_8.go
fotisl Oct 21, 2019
aafe271
Update lints/lint_mp_modulus_must_be_divisible_by_8.go
fotisl Oct 21, 2019
3e0b24c
Update lints/lint_mp_modulus_must_be_divisible_by_8.go
fotisl Oct 21, 2019
02e439f
Update lints/lint_mp_modulus_must_be_2048_bits_or_more.go
fotisl Oct 21, 2019
fc98c12
Update lints/lint_mp_exponent_cannot_be_one.go
fotisl Oct 21, 2019
64234ab
Update lints/lint_mp_modulus_must_be_2048_bits_or_more.go
fotisl Oct 21, 2019
fdecdc2
Update lints/lint_mp_modulus_must_be_2048_bits_or_more.go
fotisl Oct 21, 2019
ba2c31b
Fixed incorrect commits by github ui.
fotisl Nov 8, 2019
3f9b825
Minor syntax change.
fotisl Nov 8, 2019
53ba27b
Removed zlint-mozilla-trusted-roots-update.
fotisl Nov 8, 2019
0b6d7eb
Renamed IsSPKIMozillaTrusted() to IsInMozillaRootStore().
fotisl Nov 8, 2019
8a0097d
Merge branch 'master' into master
zakird Dec 6, 2019
f65f3a8
Merge branch 'master' into master
Dec 18, 2019
561ec7c
Merge branch 'master' into master
zakird Dec 28, 2019
8846a65
Merge remote-tracking branch 'zmap/master' into cpu-adopts-323
Jan 14, 2020
8f0bb74
lints: move lint_mp_* to lints/mozilla
Jan 14, 2020
d4e68e6
lints: remove unneeded .gitinclude
Jan 14, 2020
214a927
lints/mozilla: fix build breakages from refactoring in master
Jan 14, 2020
727ef34
lint: add src link for MozillaRootStorePolicy
Jan 14, 2020
aa1390e
zlint: run Mozilla lints
Jan 14, 2020
99d713d
util: remove IsInMozillaRootStore and assoc. data.
Jan 14, 2020
72b1fec
lints/mozilla: demote lint_mp_allowed_eku to notice
Jan 14, 2020
9404590
lints/mozilla; simplify lint_mp_ecdsa_allowed_algo CheckApplies.
Jan 14, 2020
d506af7
lints/mozilla: rename ecdsa_allowed_algorithm -> ecdsa_allowed_curve_…
Jan 14, 2020
26fddcb
lints/mozilla: add ecdsa curve/hash pair err detail.
Jan 14, 2020
353ee3a
lints/mozilla: ref trusted roots data issue num
Jan 15, 2020
efc84c6
lints/mozilla: fix mp_allowed_eku lint name
Jan 15, 2020
63295c4
lints/mozilla: clarify allowed_eku desc
Jan 15, 2020
0828819
lints/mozilla: use 0 for err return from getSigningKeySize
Jan 15, 2020
0f8571d
lints/mozilla: assume CheckApplies works
Jan 15, 2020
69fdd4e
lints/mozilla: remove `e_mp_ecdsa_allowed_curve_hash_pair`.
Jan 15, 2020
44d8557
integration: add vetted expected results for Moz. lints
Jan 16, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions integration/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,16 @@
"e_invalid_certificate_version": {},
"e_issuer_dn_country_not_printable_string": {},
"e_issuer_field_empty": {},
"e_mp_authority_key_identifier_correct": {
"ErrCount": 135
},
"e_mp_exponent_cannot_be_one": {},
"e_mp_modulus_must_be_2048_bits_or_more": {
"ErrCount": 1
},
"e_mp_modulus_must_be_divisible_by_8": {
"ErrCount": 21
},
"e_name_constraint_empty": {},
"e_name_constraint_maximum_not_absent": {},
"e_name_constraint_minimum_non_zero": {},
Expand Down Expand Up @@ -616,6 +626,9 @@
"n_ecdsa_ee_invalid_ku": {
"NoticeCount": 29
},
"n_mp_allowed_eku": {
"NoticeCount": 14
},
"n_multiple_subject_rdn": {},
"n_san_dns_name_duplicate": {
"NoticeCount": 193
Expand Down
3 changes: 2 additions & 1 deletion lint/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ const (
AWSLabs
EtsiEsi // ETSI - Electronic Signatures and Infrastructures (ESI)
CABFEVGuidelines
AppleCTPolicy // https://support.apple.com/en-us/HT205280
AppleCTPolicy // https://support.apple.com/en-us/HT205280
MozillaRootStorePolicy // https://github.com/mozilla/pkipolicy
)

// LintSources contains a list of the valid lint sources we expect to be used
Expand Down
Empty file removed lints/mozilla/.gitinclude
Empty file.
76 changes: 76 additions & 0 deletions lints/mozilla/lint_mp_allowed_eku.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* ZLint Copyright 2019 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

/********************************************************************
Section 5.3 - Intermediate Certificates
Intermediate certificates created after January 1, 2019, with the exception
of cross-certificates that share a private key with a corresponding root
certificate: MUST contain an EKU extension; and, MUST NOT include the
anyExtendedKeyUsage KeyPurposeId; and, * MUST NOT include both the
id-kp-serverAuth and id-kp-emailProtection KeyPurposeIds in the same
certificate.
Note that the lint cannot distinguish cross-certificates from other
intermediates.
********************************************************************/

package lints

import (
"time"

"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/lint"
"github.com/zmap/zlint/util"
)

type allowedEKU struct{}

func (l *allowedEKU) Initialize() error {
return nil
}

func (l *allowedEKU) CheckApplies(c *x509.Certificate) bool {
// TODO(@cpu): This lint should be limited to SubCAs that do not share
// a private key with a corresponding root certificate in the Mozilla root
// store. See https://github.com/zmap/zlint/issues/352
return util.IsSubCA(c)
}

func (l *allowedEKU) Execute(c *x509.Certificate) *lint.LintResult {
noEKU := len(c.ExtKeyUsage) == 0
anyEKU := util.HasEKU(c, x509.ExtKeyUsageAny)
emailAndServerAuthEKU :=
util.HasEKU(c, x509.ExtKeyUsageEmailProtection) &&
util.HasEKU(c, x509.ExtKeyUsageServerAuth)

if noEKU || anyEKU || emailAndServerAuthEKU {
// NOTE(@cpu): When this lint's scope is improved (see CheckApplies TODO)
// this should be a lint.Error result instead of lint.Notice. See
// https://github.com/zmap/zlint/issues/352
return &lint.LintResult{Status: lint.Notice}
}

return &lint.LintResult{Status: lint.Pass}
}

func init() {
lint.RegisterLint(&lint.Lint{
Name: "n_mp_allowed_eku",
Description: "A SubCA certificate must not have key usage that allows for both server auth and email protection, and must not use anyKeyUsage",
Citation: "Mozilla Root Store Policy / Section 5.3",
Source: lint.MozillaRootStorePolicy,
EffectiveDate: time.Date(2019, time.January, 1, 0, 0, 0, 0, time.UTC),
Lint: &allowedEKU{},
})
}
70 changes: 70 additions & 0 deletions lints/mozilla/lint_mp_allowed_eku_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package lints

/*
* ZLint Copyright 2018 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

import (
"fmt"
"testing"

"github.com/zmap/zlint/lint"
"github.com/zmap/zlint/util"
)

func TestAllowedEKUs(t *testing.T) {
testCases := []struct {
Name string
InputFilename string
ExpectedResult lint.LintStatus
}{
{
Name: "SubCA with no EKU",
InputFilename: "mpSubCAEKUDisallowed1.pem",
ExpectedResult: lint.Notice,
},
{
Name: "SubCA with anyExtendedKeyUsage",
InputFilename: "mpSubCAEKUDisallowed2.pem",
ExpectedResult: lint.Notice,
},
{
Name: "SubCA with serverAuth and emailProtection",
InputFilename: "mpSubCAEKUDisallowed3.pem",
ExpectedResult: lint.Notice,
},
{
Name: "SubCA with serverAuth EKU",
InputFilename: "mpSubCAEKUAllowed.pem",
ExpectedResult: lint.Pass,
},
{
Name: "Cross-Certificate with no EKU",
InputFilename: "mpCrossCertNoEKU.pem",
// NOTE(@cpu): This should be a lint.Pass. It is a false positive that
// would be addressed by tracking Mozilla trusted roots. See
// https://github.com/zmap/zlint/issues/352
ExpectedResult: lint.Notice,
},
}

for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
inputPath := fmt.Sprintf("%s%s", util.TestCaseDir, tc.InputFilename)
result := lint.Lints["n_mp_allowed_eku"].Execute(util.ReadCertificate(inputPath))
if result.Status != tc.ExpectedResult {
t.Errorf("expected result %v was %v", tc.ExpectedResult, result.Status)
}
})
}
}
78 changes: 78 additions & 0 deletions lints/mozilla/lint_mp_authority_key_identifier_correct.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* ZLint Copyright 2019 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

/********************************************************************
Section 5.2 - Forbidden and Required Practices
CAs MUST NOT issue certificates that have:
- incorrect extensions (e.g., SSL certificates that exclude SSL usage, or authority key IDs
that include both the key ID and the issuer’s issuer name and serial number);
********************************************************************/

package lints

import (
"encoding/asn1"
"fmt"

"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/lint"
"github.com/zmap/zlint/util"
)

type keyIdentifier struct {
KeyIdentifier asn1.RawValue `asn1:"optional,tag:0"`
AuthorityCertIssuer asn1.RawValue `asn1:"optional,tag:1"`
AuthorityCertSerialNumber asn1.RawValue `asn1:"optional,tag:2"`
}

type authorityKeyIdentifierCorrect struct{}

func (l *authorityKeyIdentifierCorrect) Initialize() error {
return nil
}

func (l *authorityKeyIdentifierCorrect) CheckApplies(c *x509.Certificate) bool {
return util.IsExtInCert(c, util.AuthkeyOID)
}

func (l *authorityKeyIdentifierCorrect) Execute(c *x509.Certificate) *lint.LintResult {
var keyID keyIdentifier

// ext is assumed not-nil based on CheckApplies.
ext := util.GetExtFromCert(c, util.AuthkeyOID)
if _, err := asn1.Unmarshal(ext.Value, &keyID); err != nil {
return &lint.LintResult{
Status: lint.Fatal,
Details: fmt.Sprintf("error unmarshalling authority key identifier extension: %v", err),
}
}

hasKeyID := len(keyID.KeyIdentifier.Bytes) > 0
hasCertIssuer := len(keyID.AuthorityCertIssuer.Bytes) > 0
if hasKeyID && hasCertIssuer {
return &lint.LintResult{Status: lint.Error}
}
return &lint.LintResult{Status: lint.Pass}
}

func init() {
lint.RegisterLint(&lint.Lint{
Name: "e_mp_authority_key_identifier_correct",
Description: "CAs MUST NOT issue certificates that have authority key IDs that include both the key ID and the issuer's issuer name and serial number",
Citation: "Mozilla Root Store Policy / Section 5.2",
Source: lint.MozillaRootStorePolicy,
EffectiveDate: util.MozillaPolicy22Date,
Lint: &authorityKeyIdentifierCorrect{},
})
}
52 changes: 52 additions & 0 deletions lints/mozilla/lint_mp_authority_key_identifier_correct_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package lints

/*
* ZLint Copyright 2018 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

import (
"fmt"
"testing"

"github.com/zmap/zlint/lint"
"github.com/zmap/zlint/util"
)

func TestAuthorityKeyIdentifier(t *testing.T) {
testCases := []struct {
Name string
InputFilename string
ExpectedResult lint.LintStatus
}{
{
Name: "Authority key ID includes both the key ID and the issuer's name and serial",
InputFilename: "mpAuthorityKeyIdentifierIncorrect.pem",
ExpectedResult: lint.Error,
},
{
Name: "Authority key ID includes the key ID",
InputFilename: "mpAuthorityKeyIdentifierCorrect.pem",
ExpectedResult: lint.Pass,
},
}

for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
inputPath := fmt.Sprintf("%s%s", util.TestCaseDir, tc.InputFilename)
result := lint.Lints["e_mp_authority_key_identifier_correct"].Execute(util.ReadCertificate(inputPath))
if result.Status != tc.ExpectedResult {
t.Errorf("expected result %v was %v", tc.ExpectedResult, result.Status)
}
})
}
}
66 changes: 66 additions & 0 deletions lints/mozilla/lint_mp_exponent_cannot_be_one.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* ZLint Copyright 2019 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

/********************************************************************
Section 5.2 - Forbidden and Required Practices
CAs MUST NOT issue certificates that have:
- invalid public keys (e.g., RSA certificates with public exponent equal to 1);
********************************************************************/

package lints

import (
"crypto/rsa"

"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/lint"
"github.com/zmap/zlint/util"
)

type exponentCannotBeOne struct{}

func (l *exponentCannotBeOne) Initialize() error {
return nil
}

func (l *exponentCannotBeOne) CheckApplies(c *x509.Certificate) bool {
return c.PublicKeyAlgorithm == x509.RSA
}

func (l *exponentCannotBeOne) Execute(c *x509.Certificate) *lint.LintResult {
pubKey, ok := c.PublicKey.(*rsa.PublicKey)
if !ok {
return &lint.LintResult{
Status: lint.Fatal,
Details: "certificate public key was not an RSA public key",
}
}

if pubKey.E == 1 {
return &lint.LintResult{Status: lint.Error}
}

return &lint.LintResult{Status: lint.Pass}
}

func init() {
lint.RegisterLint(&lint.Lint{
Name: "e_mp_exponent_cannot_be_one",
Description: "CAs MUST NOT issue certificates that have invalid public keys (e.g., RSA certificates with public exponent equal to 1)",
Citation: "Mozilla Root Store Policy / Section 5.2",
Source: lint.MozillaRootStorePolicy,
EffectiveDate: util.MozillaPolicy24Date,
Lint: &exponentCannotBeOne{},
})
}
Loading