diff --git a/v3/lints/cabf_smime_br/mailbox_validated_enforce_subject_field_restrictions.go b/v3/lints/cabf_smime_br/mailbox_validated_enforce_subject_field_restrictions.go index fdb366fb9..782d35ef6 100644 --- a/v3/lints/cabf_smime_br/mailbox_validated_enforce_subject_field_restrictions.go +++ b/v3/lints/cabf_smime_br/mailbox_validated_enforce_subject_field_restrictions.go @@ -72,12 +72,13 @@ func NewMailboxValidatedEnforceSubjectFieldRestrictions() lint.LintInterface { } } -// CheckApplies returns true if the provided certificate contains one-or-more of the following SMIME BR policy identifiers: +// CheckApplies returns true if the provided certificate is a subscriber certificate and contains one-or-more of the following +// SMIME BR policy identifiers: // - Mailbox Validated Legacy // - Mailbox Validated Multipurpose // - Mailbox Validated Strict func (l *mailboxValidatedEnforceSubjectFieldRestrictions) CheckApplies(c *x509.Certificate) bool { - return util.IsMailboxValidatedCertificate(c) + return util.IsMailboxValidatedCertificate(c) && util.IsSubscriberCert(c) } // Execute applies the requirements on what fields are allowed for mailbox validated SMIME certificates diff --git a/v3/lints/cabf_smime_br/smime_legacy_multipurpose_eku_check.go b/v3/lints/cabf_smime_br/smime_legacy_multipurpose_eku_check.go new file mode 100644 index 000000000..a3257ca55 --- /dev/null +++ b/v3/lints/cabf_smime_br/smime_legacy_multipurpose_eku_check.go @@ -0,0 +1,80 @@ +package cabf_smime_br + +/* + * ZLint Copyright 2023 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 ( + "github.com/zmap/zcrypto/x509" + "github.com/zmap/zlint/v3/lint" + "github.com/zmap/zlint/v3/util" +) + +// shallHaveCrlDistributionPoints - linter to enforce requirement that SMIME certificates SHALL contain emailProtecton EKU +type legacyMultipurposeEKUCheck struct { +} + +func init() { + lint.RegisterCertificateLint(&lint.CertificateLint{ + LintMetadata: lint.LintMetadata{ + Name: "e_smime_legacy_multipurpose_eku_check", + Description: "Strict/Multipurpose and Legacy: id-kp-emailProtection SHALL be present. Other values MAY be present. The values id-kp-serverAuth, id-kp-codeSigning, id-kp-timeStamping, and anyExtendedKeyUsage values SHALL NOT be present.", + Citation: "SMIME BRs: 7.1.2.3.f", + Source: lint.CABFSMIMEBaselineRequirements, + EffectiveDate: util.CABF_SMIME_BRs_1_0_0_Date, + }, + Lint: NewLegacyMultipurposeEKUCheck, + }) +} + +// NewShallHaveCrlDistributionPoints creates a new linter to enforce MAY/SHALL NOT field requirements for mailbox validated SMIME certs +func NewLegacyMultipurposeEKUCheck() lint.CertificateLintInterface { + return &legacyMultipurposeEKUCheck{} +} + +// CheckApplies returns true if the provided certificate contains one-or-more of the following SMIME BR policy identifiers: +// - Mailbox Validated Legacy +// - Mailbox Validated Multipurpose +// - Organization Validated Legacy +// - Organization Validated Multipurpose +// - Sponsor Validated Legacy +// - Sponsor Validated Multipurpose +// - Individual Validated Legacy +// - Individual Validated Multipurpose +func (l *legacyMultipurposeEKUCheck) CheckApplies(c *x509.Certificate) bool { + return (util.IsLegacySMIMECertificate(c) || util.IsMultipurposeSMIMECertificate(c)) && util.IsSubscriberCert(c) +} + +// Execute applies the requirements on what fields are allowed for mailbox validated SMIME certificates +func (l *legacyMultipurposeEKUCheck) Execute(c *x509.Certificate) *lint.LintResult { + hasEmailProtectionEKU := false + ekusOK := true + + for _, eku := range c.ExtKeyUsage { + if eku == x509.ExtKeyUsageEmailProtection { + hasEmailProtectionEKU = true + } else if eku == x509.ExtKeyUsageServerAuth || eku == x509.ExtKeyUsageCodeSigning || eku == x509.ExtKeyUsageTimeStamping || eku == x509.ExtKeyUsageAny { + ekusOK = false + } + } + + if !hasEmailProtectionEKU { + return &lint.LintResult{Status: lint.Error, Details: "id-kp-emailProtection SHALL be present"} + } + + if !ekusOK { + return &lint.LintResult{Status: lint.Error, Details: "id-kp-serverAuth, id-kp-codeSigning, id-kp-timeStamping, and anyExtendedKeyUsage values SHALL NOT be present"} + } + + return &lint.LintResult{Status: lint.Pass} +} diff --git a/v3/lints/cabf_smime_br/smime_legacy_multipurpose_eku_check_test.go b/v3/lints/cabf_smime_br/smime_legacy_multipurpose_eku_check_test.go new file mode 100644 index 000000000..fe195eedf --- /dev/null +++ b/v3/lints/cabf_smime_br/smime_legacy_multipurpose_eku_check_test.go @@ -0,0 +1,73 @@ +package cabf_smime_br + +/* + * ZLint Copyright 2021 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 ( + "testing" + + "github.com/zmap/zlint/v3/lint" + "github.com/zmap/zlint/v3/test" +) + +func TestLegacyMultipurposeEKUCheck(t *testing.T) { + testCases := []struct { + Name string + InputFilename string + + ExpectedResult lint.LintStatus + ExpectedDetails string + }{ + { + Name: "pass - mailbox validated, legacy with commonName", + InputFilename: "smime/mailboxValidatedLegacyWithCommonName.pem", + ExpectedResult: lint.Pass, + }, + { + Name: "na - certificate without mailbox validated policy", + InputFilename: "smime/domainValidatedWithEmailCommonName.pem", + ExpectedResult: lint.NA, + }, + { + Name: "ne - certificate with NotBefore before effective date of lint", + InputFilename: "smime/mailboxValidatedLegacyWithCommonNameMay2023.pem", + ExpectedResult: lint.NE, + }, + { + Name: "error - certificate without emailProtection EKU", + InputFilename: "smime/mailboxValidatedLegacyWithoutEmailProtectionEKU.pem", + ExpectedResult: lint.Error, + ExpectedDetails: "id-kp-emailProtection SHALL be present", + }, + { + Name: "error - certificate containing serverAuthEKU", + InputFilename: "smime/organizationValidatedMultipurposeWithServerAuthEKU.pem", + ExpectedResult: lint.Error, + ExpectedDetails: "id-kp-serverAuth, id-kp-codeSigning, id-kp-timeStamping, and anyExtendedKeyUsage values SHALL NOT be present", + }, + } + + for _, tc := range testCases { + t.Run(tc.Name, func(t *testing.T) { + result := test.TestLint("e_smime_legacy_multipurpose_eku_check", tc.InputFilename) + if result.Status != tc.ExpectedResult { + t.Errorf("expected result %v was %v - details: %v", tc.ExpectedResult, result.Status, result.Details) + } + + if tc.ExpectedDetails != "" && tc.ExpectedDetails != result.Details { + t.Errorf("expected details: %s, was %s", tc.ExpectedDetails, result.Details) + } + }) + } +} diff --git a/v3/lints/cabf_smime_br/smime_strict_eku_check.go b/v3/lints/cabf_smime_br/smime_strict_eku_check.go new file mode 100644 index 000000000..a7bc1a9af --- /dev/null +++ b/v3/lints/cabf_smime_br/smime_strict_eku_check.go @@ -0,0 +1,71 @@ +package cabf_smime_br + +/* + * ZLint Copyright 2023 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 ( + "github.com/zmap/zcrypto/x509" + "github.com/zmap/zlint/v3/lint" + "github.com/zmap/zlint/v3/util" +) + +// strictEKUCheck - linter to enforce requirement that SMIME certificates SHALL contain emailProtecton EKU +type strictEKUCheck struct { +} + +func init() { + lint.RegisterCertificateLint(&lint.CertificateLint{ + LintMetadata: lint.LintMetadata{ + Name: "e_smime_strict_eku_check", + Description: "Strict: id-kp-emailProtection SHALL be present. Other values SHALL NOT be present", + Citation: "SMIME BRs: 7.1.2.3.f", + Source: lint.CABFSMIMEBaselineRequirements, + EffectiveDate: util.CABF_SMIME_BRs_1_0_0_Date, + }, + Lint: NewStrictEKUCheck, + }) +} + +// NewShallHaveCrlDistributionPoints creates a new linter to enforce MAY/SHALL NOT field requirements for mailbox validated SMIME certs +func NewStrictEKUCheck() lint.CertificateLintInterface { + return &strictEKUCheck{} +} + +// CheckApplies returns true if the provided certificate contains one-or-more of the following SMIME BR policy identifiers: +// - Mailbox Validated Strict +// - Organization Validated Strict +// - Sponsor Validated Strict +// - Individual Validated Strict +func (l *strictEKUCheck) CheckApplies(c *x509.Certificate) bool { + return util.IsStrictSMIMECertificate(c) && util.IsSubscriberCert(c) +} + +// Execute applies the requirements on what fields are allowed for mailbox validated SMIME certificates +func (l *strictEKUCheck) Execute(c *x509.Certificate) *lint.LintResult { + hasEmailProtectionEKU := false + + for _, eku := range c.ExtKeyUsage { + if eku == x509.ExtKeyUsageEmailProtection { + hasEmailProtectionEKU = true + } else { + return &lint.LintResult{Status: lint.Error} + } + } + + if hasEmailProtectionEKU { + return &lint.LintResult{Status: lint.Pass} + } + + return &lint.LintResult{Status: lint.Error} +} diff --git a/v3/lints/cabf_smime_br/smime_strict_eku_check_test.go b/v3/lints/cabf_smime_br/smime_strict_eku_check_test.go new file mode 100644 index 000000000..0ddd3577b --- /dev/null +++ b/v3/lints/cabf_smime_br/smime_strict_eku_check_test.go @@ -0,0 +1,66 @@ +package cabf_smime_br + +/* + * ZLint Copyright 2021 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 ( + "testing" + + "github.com/zmap/zlint/v3/lint" + "github.com/zmap/zlint/v3/test" +) + +func TestStrictEKUCheck(t *testing.T) { + testCases := []struct { + Name string + InputFilename string + + ExpectedResult lint.LintStatus + }{ + { + Name: "pass - mailbox validated, strict with EmailProtectionEKU", + InputFilename: "smime/mailboxValidatedStrictWithCommonName.pem", + ExpectedResult: lint.Pass, + }, + { + Name: "na - certificate without mailbox validated policy", + InputFilename: "smime/domainValidatedWithEmailCommonName.pem", + ExpectedResult: lint.NA, + }, + { + Name: "na - mailbox validated legacy certificate", + InputFilename: "smime/mailboxValidatedLegacyWithCommonName.pem", + ExpectedResult: lint.NA, + }, + { + Name: "ne - certificate with NotBefore before effective date of lint", + InputFilename: "smime/mailboxValidatedStrictMay2023.pem", + ExpectedResult: lint.NE, + }, + { + Name: "error - certificate with extra EKU", + InputFilename: "smime/individualValidatedStrictWithServerAuthEKU.pem", + ExpectedResult: lint.Error, + }, + } + + for _, tc := range testCases { + t.Run(tc.Name, func(t *testing.T) { + result := test.TestLint("e_smime_strict_eku_check", tc.InputFilename) + if result.Status != tc.ExpectedResult { + t.Errorf("expected result %v was %v - details: %v", tc.ExpectedResult, result.Status, result.Details) + } + }) + } +} diff --git a/v3/testdata/smime/individualValidatedStrictWithServerAuthEKU.pem b/v3/testdata/smime/individualValidatedStrictWithServerAuthEKU.pem new file mode 100644 index 000000000..6fd83436e --- /dev/null +++ b/v3/testdata/smime/individualValidatedStrictWithServerAuthEKU.pem @@ -0,0 +1,41 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: + Validity + Not Before: Sep 2 00:00:00 2023 GMT + Not After : Nov 30 00:00:00 9998 GMT + Subject: CN = johnsmith@example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:f3:96:63:02:f4:04:19:9b:03:3f:01:a4:78:80: + f3:fe:ca:fb:ea:54:d1:e0:5c:1d:f9:58:9e:38:9a: + 3f:70:b4:b9:3e:41:6f:a5:4c:5f:c3:fc:d4:a6:a3: + e6:c2:34:31:31:f4:ef:7c:15:f4:0d:f3:c5:0d:5d: + 36:08:d0:67:20 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Extended Key Usage: + E-mail Protection, TLS Web Server Authentication + X509v3 Certificate Policies: + Policy: 2.23.140.1.5.4.3 + + Signature Algorithm: ecdsa-with-SHA256 + 30:46:02:21:00:8e:9c:01:a7:ea:ea:5a:ba:1a:7a:a0:e8:34: + ef:75:65:32:23:ed:db:6d:b6:f0:6a:c0:6d:f4:1c:6c:17:91: + 72:02:21:00:e5:1e:31:8b:4e:4f:7e:65:74:c0:75:1d:03:54: + 6b:c1:21:b7:93:10:81:bf:e2:8c:39:36:05:8d:fb:cf:5b:66 +-----BEGIN CERTIFICATE----- +MIIBSDCB7qADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMwOTAyMDAwMDAwWhgP +OTk5ODExMzAwMDAwMDBaMCAxHjAcBgNVBAMMFWpvaG5zbWl0aEBleGFtcGxlLmNv +bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPOWYwL0BBmbAz8BpHiA8/7K++pU +0eBcHflYnjiaP3C0uT5Bb6VMX8P81Kaj5sI0MTH073wV9A3zxQ1dNgjQZyCjNzA1 +MB0GA1UdJQQWMBQGCCsGAQUFBwMEBggrBgEFBQcDATAUBgNVHSAEDTALMAkGB2eB +DAEFBAMwCgYIKoZIzj0EAwIDSQAwRgIhAI6cAafq6lq6Gnqg6DTvdWUyI+3bbbbw +asBt9BxsF5FyAiEA5R4xi05PfmV0wHUdA1RrwSG3kxCBv+KMOTYFjfvPW2Y= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/v3/testdata/smime/mailboxValidatedLegacyWithCommonName.pem b/v3/testdata/smime/mailboxValidatedLegacyWithCommonName.pem index 7cc031221..845a230d6 100644 --- a/v3/testdata/smime/mailboxValidatedLegacyWithCommonName.pem +++ b/v3/testdata/smime/mailboxValidatedLegacyWithCommonName.pem @@ -12,28 +12,30 @@ Certificate: Public Key Algorithm: id-ecPublicKey Public-Key: (256 bit) pub: - 04:a1:ed:8b:dd:62:fc:cc:2d:f4:28:cd:8c:8d:5a: - 1d:1f:6c:36:c3:03:81:b4:9f:6e:6d:2d:90:b1:7d: - fa:2f:eb:d6:3c:83:7c:9f:2c:5a:b4:37:3e:ae:56: - 57:6b:db:df:6a:1c:db:73:e6:d4:25:b1:15:d6:47: - f2:71:de:51:d0 + 04:d7:dd:dd:da:90:73:84:98:a6:9c:29:96:f2:9f: + ae:33:b1:0c:f6:43:5d:78:7f:a7:4a:6b:d0:e4:bf: + 9b:b0:13:cb:14:4c:da:79:5b:25:6c:f9:62:e1:fc: + f2:a7:22:6f:3b:98:97:76:08:6b:0e:e7:8b:11:4a: + 24:64:e9:c1:bd ASN1 OID: prime256v1 NIST CURVE: P-256 X509v3 extensions: + X509v3 Extended Key Usage: + E-mail Protection X509v3 Certificate Policies: Policy: 2.23.140.1.5.1.1 Signature Algorithm: ecdsa-with-SHA256 - 30:45:02:20:41:fa:93:51:d2:80:69:a5:5e:4a:cb:85:6a:1e: - 47:eb:cb:9b:b3:7b:2b:94:a7:be:a4:b2:55:cc:4a:15:16:f7: - 02:21:00:81:0c:18:bd:55:7a:16:6a:0c:84:a9:3b:bf:29:e2: - 21:d0:fd:b6:9b:99:14:5b:0b:55:a8:43:b9:64:b6:8e:dc + 30:45:02:20:5c:fe:57:a1:85:87:b9:ec:61:51:c0:8d:da:96: + d1:1a:09:bd:29:4a:8a:22:f7:c1:a3:93:45:f3:7e:a5:cd:cf: + 02:21:00:c4:27:2c:38:2e:87:f0:d3:32:5f:82:d5:68:8c:bc: + c5:1f:db:c2:9b:ab:5f:07:cf:39:de:49:52:a1:f4:3c:4d -----BEGIN CERTIFICATE----- -MIIBKDCBz6ADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMwOTAyMDAwMDAwWhgP +MIIBPTCB5KADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMwOTAyMDAwMDAwWhgP OTk5ODExMzAwMDAwMDBaMCAxHjAcBgNVBAMMFWpvaG5zbWl0aEBleGFtcGxlLmNv -bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABKHti91i/Mwt9CjNjI1aHR9sNsMD -gbSfbm0tkLF9+i/r1jyDfJ8sWrQ3Pq5WV2vb32oc23Pm1CWxFdZH8nHeUdCjGDAW -MBQGA1UdIAQNMAswCQYHZ4EMAQUBATAKBggqhkjOPQQDAgNIADBFAiBB+pNR0oBp -pV5Ky4VqHkfry5uzeyuUp76kslXMShUW9wIhAIEMGL1VehZqDISpO78p4iHQ/bab -mRRbC1WoQ7lkto7c +bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABNfd3dqQc4SYppwplvKfrjOxDPZD +XXh/p0pr0OS/m7ATyxRM2nlbJWz5YuH88qcibzuYl3YIaw7nixFKJGTpwb2jLTAr +MBMGA1UdJQQMMAoGCCsGAQUFBwMEMBQGA1UdIAQNMAswCQYHZ4EMAQUBATAKBggq +hkjOPQQDAgNIADBFAiBc/lehhYe57GFRwI3altEaCb0pSooi98Gjk0XzfqXNzwIh +AMQnLDguh/DTMl+C1WiMvMUf28Kbq18HzzneSVKh9DxN -----END CERTIFICATE----- \ No newline at end of file diff --git a/v3/testdata/smime/mailboxValidatedLegacyWithoutEmailProtectionEKU.pem b/v3/testdata/smime/mailboxValidatedLegacyWithoutEmailProtectionEKU.pem new file mode 100644 index 000000000..f1ba6dfdb --- /dev/null +++ b/v3/testdata/smime/mailboxValidatedLegacyWithoutEmailProtectionEKU.pem @@ -0,0 +1,39 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: + Validity + Not Before: Sep 2 00:00:00 2023 GMT + Not After : Nov 30 00:00:00 9998 GMT + Subject: CN = johnsmith@example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:bb:04:4b:ac:30:58:56:1f:7e:a7:7b:a5:4e:28: + 05:53:82:4d:43:3c:ee:64:ae:a9:9c:7a:5c:2b:ee: + ec:5c:72:76:2c:79:50:63:98:e8:f9:84:13:0a:87: + 78:e2:7d:25:4b:fb:d0:35:df:55:da:5b:f7:5d:55: + 96:87:c6:0e:5e + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Certificate Policies: + Policy: 2.23.140.1.5.1.1 + + Signature Algorithm: ecdsa-with-SHA256 + 30:45:02:20:35:9f:54:c6:63:b6:43:b5:17:ed:6f:86:08:eb: + 2e:0b:04:6f:4c:44:b7:ec:74:e1:7e:1c:01:67:51:2c:51:d4: + 02:21:00:ba:f8:6c:3d:d8:f5:64:e6:a2:a1:2e:bb:51:0a:51: + 8a:0c:23:d7:dc:01:70:76:4f:ea:52:d2:2b:25:79:89:71 +-----BEGIN CERTIFICATE----- +MIIBKDCBz6ADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMwOTAyMDAwMDAwWhgP +OTk5ODExMzAwMDAwMDBaMCAxHjAcBgNVBAMMFWpvaG5zbWl0aEBleGFtcGxlLmNv +bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLsES6wwWFYffqd7pU4oBVOCTUM8 +7mSuqZx6XCvu7Fxydix5UGOY6PmEEwqHeOJ9JUv70DXfVdpb911VlofGDl6jGDAW +MBQGA1UdIAQNMAswCQYHZ4EMAQUBATAKBggqhkjOPQQDAgNIADBFAiA1n1TGY7ZD +tRftb4YI6y4LBG9MRLfsdOF+HAFnUSxR1AIhALr4bD3Y9WTmoqEuu1EKUYoMI9fc +AXB2T+pS0isleYlx +-----END CERTIFICATE----- \ No newline at end of file diff --git a/v3/testdata/smime/mailboxValidatedStrictMay2023.pem b/v3/testdata/smime/mailboxValidatedStrictMay2023.pem new file mode 100644 index 000000000..49d3d267a --- /dev/null +++ b/v3/testdata/smime/mailboxValidatedStrictMay2023.pem @@ -0,0 +1,41 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: + Validity + Not Before: May 1 00:00:00 2023 GMT + Not After : Nov 30 00:00:00 9998 GMT + Subject: CN = johnsmith@example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:31:bd:c6:39:0e:ec:75:4e:d8:d0:61:ca:ed:66: + 70:e7:de:6f:91:03:ab:c8:5f:6c:ae:cf:6f:d4:84: + 14:15:89:18:ea:a8:33:03:ac:e1:4d:41:21:fb:57: + 47:9f:6a:37:ad:6a:1e:cc:84:9d:06:b3:54:f2:c7: + 68:56:9d:29:2e + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Extended Key Usage: + E-mail Protection + X509v3 Certificate Policies: + Policy: 2.23.140.1.5.1.3 + + Signature Algorithm: ecdsa-with-SHA256 + 30:44:02:20:05:64:4d:8c:35:21:2d:59:14:69:a9:3e:8d:eb: + 38:01:69:18:a6:5c:78:7f:b8:c6:01:a9:2b:ad:59:e3:90:b4: + 02:20:18:05:30:eb:40:30:57:52:a8:1a:46:e2:22:db:26:60: + f3:db:a0:5f:da:84:44:cb:dd:24:a4:81:dd:6c:6c:13 +-----BEGIN CERTIFICATE----- +MIIBPDCB5KADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMwNTAxMDAwMDAwWhgP +OTk5ODExMzAwMDAwMDBaMCAxHjAcBgNVBAMMFWpvaG5zbWl0aEBleGFtcGxlLmNv +bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABDG9xjkO7HVO2NBhyu1mcOfeb5ED +q8hfbK7Pb9SEFBWJGOqoMwOs4U1BIftXR59qN61qHsyEnQazVPLHaFadKS6jLTAr +MBMGA1UdJQQMMAoGCCsGAQUFBwMEMBQGA1UdIAQNMAswCQYHZ4EMAQUBAzAKBggq +hkjOPQQDAgNHADBEAiAFZE2MNSEtWRRpqT6N6zgBaRimXHh/uMYBqSutWeOQtAIg +GAUw60AwV1KoGkbiItsmYPPboF/ahETL3SSkgd1sbBM= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/v3/testdata/smime/mailboxValidatedStrictWithCommonName.pem b/v3/testdata/smime/mailboxValidatedStrictWithCommonName.pem index 9c546e380..8350b931e 100644 --- a/v3/testdata/smime/mailboxValidatedStrictWithCommonName.pem +++ b/v3/testdata/smime/mailboxValidatedStrictWithCommonName.pem @@ -12,28 +12,30 @@ Certificate: Public Key Algorithm: id-ecPublicKey Public-Key: (256 bit) pub: - 04:40:42:9c:5b:49:e2:31:38:01:3d:07:42:a1:4c: - c8:43:2b:0a:cd:62:3d:5b:40:4a:e1:f6:ed:df:06: - a8:d3:cc:fd:bf:21:c1:4a:48:41:bb:3f:c1:66:a8: - 12:b3:84:40:97:18:a3:b9:ce:3e:31:cb:d4:48:84: - 81:12:52:93:df + 04:3f:0b:04:2d:3d:8b:ee:55:2a:4e:5c:8a:76:cf: + 7c:e8:31:81:59:29:66:70:1f:9e:42:9c:af:7e:7b: + b6:af:df:b8:92:be:b9:38:bd:af:80:d6:eb:df:f7: + 38:de:a6:32:33:35:31:0f:2f:e8:0c:8d:ff:dc:a9: + bd:33:20:1e:f3 ASN1 OID: prime256v1 NIST CURVE: P-256 X509v3 extensions: + X509v3 Extended Key Usage: + E-mail Protection X509v3 Certificate Policies: Policy: 2.23.140.1.5.1.3 Signature Algorithm: ecdsa-with-SHA256 - 30:45:02:20:09:34:af:8d:f7:20:90:a3:2e:de:44:12:8c:92: - c7:cf:02:73:b7:c3:e1:fb:fd:32:2a:19:65:7f:37:b8:f0:25: - 02:21:00:d0:50:43:27:a6:91:f0:52:7d:73:9d:ca:7c:6f:9d: - 7e:00:84:c9:3f:3f:2f:02:91:da:11:a1:6f:09:6f:a0:7a + 30:44:02:20:2d:70:70:13:e1:59:27:4e:00:8f:3a:fd:8c:dd: + 54:a8:0c:bf:81:d6:2c:31:81:04:0e:80:30:0a:1d:9f:ff:10: + 02:20:4b:59:90:f3:9c:0b:d0:9c:cc:fa:74:45:99:2d:8e:f3: + c0:cf:e2:d6:67:61:20:71:6b:91:93:39:5b:f2:38:e7 -----BEGIN CERTIFICATE----- -MIIBKDCBz6ADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMwOTAyMDAwMDAwWhgP +MIIBPDCB5KADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMwOTAyMDAwMDAwWhgP OTk5ODExMzAwMDAwMDBaMCAxHjAcBgNVBAMMFWpvaG5zbWl0aEBleGFtcGxlLmNv -bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABEBCnFtJ4jE4AT0HQqFMyEMrCs1i -PVtASuH27d8GqNPM/b8hwUpIQbs/wWaoErOEQJcYo7nOPjHL1EiEgRJSk9+jGDAW -MBQGA1UdIAQNMAswCQYHZ4EMAQUBAzAKBggqhkjOPQQDAgNIADBFAiAJNK+N9yCQ -oy7eRBKMksfPAnO3w+H7/TIqGWV/N7jwJQIhANBQQyemkfBSfXOdynxvnX4AhMk/ -Py8CkdoRoW8Jb6B6 +bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABD8LBC09i+5VKk5cinbPfOgxgVkp +ZnAfnkKcr357tq/fuJK+uTi9r4DW69/3ON6mMjM1MQ8v6AyN/9ypvTMgHvOjLTAr +MBMGA1UdJQQMMAoGCCsGAQUFBwMEMBQGA1UdIAQNMAswCQYHZ4EMAQUBAzAKBggq +hkjOPQQDAgNHADBEAiAtcHAT4VknTgCPOv2M3VSoDL+B1iwxgQQOgDAKHZ//EAIg +S1mQ85wL0JzM+nRFmS2O88DP4tZnYSBxa5GTOVvyOOc= -----END CERTIFICATE----- \ No newline at end of file diff --git a/v3/testdata/smime/organizationValidatedMultipurposeWithServerAuthEKU.pem b/v3/testdata/smime/organizationValidatedMultipurposeWithServerAuthEKU.pem new file mode 100644 index 000000000..42cea2ff2 --- /dev/null +++ b/v3/testdata/smime/organizationValidatedMultipurposeWithServerAuthEKU.pem @@ -0,0 +1,41 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: + Validity + Not Before: Sep 2 00:00:00 2023 GMT + Not After : Nov 30 00:00:00 9998 GMT + Subject: CN = johnsmith@example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:5c:03:67:b8:33:4d:10:4f:6e:50:17:75:21:ba: + 0b:6d:11:fa:c2:92:7d:40:a1:fe:0b:f0:0e:e8:84: + 20:90:2a:10:bf:10:8b:9c:7e:ec:01:1d:01:85:b6: + ff:3a:e3:3a:d6:67:2c:66:2a:c3:92:6f:d1:ec:eb: + 83:12:ee:c9:4d + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Extended Key Usage: + E-mail Protection, TLS Web Server Authentication + X509v3 Certificate Policies: + Policy: 2.23.140.1.5.2.2 + + Signature Algorithm: ecdsa-with-SHA256 + 30:45:02:21:00:e3:8d:ee:a5:8d:4f:27:4c:ec:c8:49:01:e8: + b9:94:57:aa:cd:78:43:e5:fc:5a:5f:a1:63:0f:d5:34:a0:4f: + 95:02:20:67:36:85:e5:e7:d9:75:c6:3a:7a:37:8a:c2:79:63: + 51:0f:63:3c:aa:58:1e:62:ac:f1:5c:9e:15:32:c4:97:43 +-----BEGIN CERTIFICATE----- +MIIBRzCB7qADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMwOTAyMDAwMDAwWhgP +OTk5ODExMzAwMDAwMDBaMCAxHjAcBgNVBAMMFWpvaG5zbWl0aEBleGFtcGxlLmNv +bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABFwDZ7gzTRBPblAXdSG6C20R+sKS +fUCh/gvwDuiEIJAqEL8Qi5x+7AEdAYW2/zrjOtZnLGYqw5Jv0ezrgxLuyU2jNzA1 +MB0GA1UdJQQWMBQGCCsGAQUFBwMEBggrBgEFBQcDATAUBgNVHSAEDTALMAkGB2eB +DAEFAgIwCgYIKoZIzj0EAwIDSAAwRQIhAOON7qWNTydM7MhJAei5lFeqzXhD5fxa +X6FjD9U0oE+VAiBnNoXl59l1xjp6N4rCeWNRD2M8qlgeYqzxXJ4VMsSXQw== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/v3/util/oid.go b/v3/util/oid.go index 5abe25b57..429bc9011 100644 --- a/v3/util/oid.go +++ b/v3/util/oid.go @@ -50,14 +50,23 @@ var ( SubjectKeyIdentityOID = asn1.ObjectIdentifier{2, 5, 29, 14} // Subject Key Identifier ReasonCodeOID = asn1.ObjectIdentifier{2, 5, 29, 21} // CRL Reason Code // CA/B reserved policies - BRDomainValidatedOID = asn1.ObjectIdentifier{2, 23, 140, 1, 2, 1} // CA/B BR Domain-Validated - BROrganizationValidatedOID = asn1.ObjectIdentifier{2, 23, 140, 1, 2, 2} // CA/B BR Organization-Validated - BRIndividualValidatedOID = asn1.ObjectIdentifier{2, 23, 140, 1, 2, 3} // CA/B BR Individual-Validated - BRTorServiceDescriptor = asn1.ObjectIdentifier{2, 23, 140, 1, 31} // CA/B BR Tor Service Descriptor - CabfExtensionOrganizationIdentifier = asn1.ObjectIdentifier{2, 23, 140, 3, 1} // CA/B EV 9.8.2 cabfOrganizationIdentifier - SMIMEBRMailboxValidatedLegacyOID = asn1.ObjectIdentifier{2, 23, 140, 1, 5, 1, 1} // CA/B SMIME BR Mailbox Validated, Legacy - SMIMEBRMailboxValidatedMultipurposeOID = asn1.ObjectIdentifier{2, 23, 140, 1, 5, 1, 2} // CA/B SMIME BR Mailbox Validated, Multipurpose - SMIMEBRMailboxValidatedStrictOID = asn1.ObjectIdentifier{2, 23, 140, 1, 5, 1, 3} // CA/B SMIME BR Mailbox Validated, Strict + BRDomainValidatedOID = asn1.ObjectIdentifier{2, 23, 140, 1, 2, 1} // CA/B BR Domain-Validated + BROrganizationValidatedOID = asn1.ObjectIdentifier{2, 23, 140, 1, 2, 2} // CA/B BR Organization-Validated + BRIndividualValidatedOID = asn1.ObjectIdentifier{2, 23, 140, 1, 2, 3} // CA/B BR Individual-Validated + BRTorServiceDescriptor = asn1.ObjectIdentifier{2, 23, 140, 1, 31} // CA/B BR Tor Service Descriptor + CabfExtensionOrganizationIdentifier = asn1.ObjectIdentifier{2, 23, 140, 3, 1} // CA/B EV 9.8.2 cabfOrganizationIdentifier + SMIMEBRMailboxValidatedLegacyOID = asn1.ObjectIdentifier{2, 23, 140, 1, 5, 1, 1} // CA/B SMIME BR Mailbox Validated, Legacy + SMIMEBRMailboxValidatedMultipurposeOID = asn1.ObjectIdentifier{2, 23, 140, 1, 5, 1, 2} // CA/B SMIME BR Mailbox Validated, Multipurpose + SMIMEBRMailboxValidatedStrictOID = asn1.ObjectIdentifier{2, 23, 140, 1, 5, 1, 3} // CA/B SMIME BR Mailbox Validated, Strict + SMIMEBROrganizationValidatedLegacyOID = asn1.ObjectIdentifier{2, 23, 140, 1, 5, 2, 1} // CA/B SMIME BR Organization Validated, Legacy + SMIMEBROrganizationValidatedMultipurposeOID = asn1.ObjectIdentifier{2, 23, 140, 1, 5, 2, 2} // CA/B SMIME BR Organization Validated, Multipurpose + SMIMEBROrganizationValidatedStrictOID = asn1.ObjectIdentifier{2, 23, 140, 1, 5, 2, 3} // CA/B SMIME BR Organization Validated, Strict + SMIMEBRSponsorValidatedLegacyOID = asn1.ObjectIdentifier{2, 23, 140, 1, 5, 3, 1} // CA/B SMIME BR Sponsor Validated, Legacy + SMIMEBRSponsorValidatedMultipurposeOID = asn1.ObjectIdentifier{2, 23, 140, 1, 5, 3, 2} // CA/B SMIME BR Sponsor Validated, Multipurpose + SMIMEBRSponsorValidatedStrictOID = asn1.ObjectIdentifier{2, 23, 140, 1, 5, 3, 3} // CA/B SMIME BR Sponsor Validated, Strict + SMIMEBRIndividualValidatedLegacyOID = asn1.ObjectIdentifier{2, 23, 140, 1, 5, 4, 1} // CA/B SMIME BR Individual Validated, Legacy + SMIMEBRIndividualValidatedMultipurposeOID = asn1.ObjectIdentifier{2, 23, 140, 1, 5, 4, 2} // CA/B SMIME BR Individual Validated, Multipurpose + SMIMEBRIndividualValidatedStrictOID = asn1.ObjectIdentifier{2, 23, 140, 1, 5, 4, 3} // CA/B SMIME BR Individual Validated, Strict //X.500 attribute types CommonNameOID = asn1.ObjectIdentifier{2, 5, 4, 3} SurnameOID = asn1.ObjectIdentifier{2, 5, 4, 4} diff --git a/v3/util/smime_policies.go b/v3/util/smime_policies.go index 051e483ba..c8c5453af 100644 --- a/v3/util/smime_policies.go +++ b/v3/util/smime_policies.go @@ -14,7 +14,9 @@ package util * permissions and limitations under the License. */ -import "github.com/zmap/zcrypto/x509" +import ( + "github.com/zmap/zcrypto/x509" +) func IsMailboxValidatedCertificate(c *x509.Certificate) bool { for _, oid := range c.PolicyIdentifiers { @@ -25,3 +27,33 @@ func IsMailboxValidatedCertificate(c *x509.Certificate) bool { return false } + +func IsLegacySMIMECertificate(c *x509.Certificate) bool { + for _, oid := range c.PolicyIdentifiers { + if oid.Equal(SMIMEBRMailboxValidatedLegacyOID) || oid.Equal(SMIMEBROrganizationValidatedLegacyOID) || oid.Equal(SMIMEBRSponsorValidatedLegacyOID) || oid.Equal(SMIMEBRIndividualValidatedLegacyOID) { + return true + } + } + + return false +} + +func IsMultipurposeSMIMECertificate(c *x509.Certificate) bool { + for _, oid := range c.PolicyIdentifiers { + if oid.Equal(SMIMEBRMailboxValidatedMultipurposeOID) || oid.Equal(SMIMEBROrganizationValidatedMultipurposeOID) || oid.Equal(SMIMEBRSponsorValidatedMultipurposeOID) || oid.Equal(SMIMEBRIndividualValidatedMultipurposeOID) { + return true + } + } + + return false +} + +func IsStrictSMIMECertificate(c *x509.Certificate) bool { + for _, oid := range c.PolicyIdentifiers { + if oid.Equal(SMIMEBRMailboxValidatedStrictOID) || oid.Equal(SMIMEBROrganizationValidatedStrictOID) || oid.Equal(SMIMEBRSponsorValidatedStrictOID) || oid.Equal(SMIMEBRIndividualValidatedStrictOID) { + return true + } + } + + return false +}