diff --git a/v3/integration/config.json b/v3/integration/config.json index 18ed88ddc..131db0f28 100644 --- a/v3/integration/config.json +++ b/v3/integration/config.json @@ -323,6 +323,8 @@ } ], "Expected": { + "e_adobe_extensions_legacy_multipurpose_criticality": {}, + "e_adobe_extensions_strict_presence": {}, "e_algorithm_identifier_improper_encoding": {}, "e_basic_constraints_not_critical": { "ErrCount": 23 @@ -416,7 +418,10 @@ }, "e_dsa_unique_correct_representation": {}, "e_ec_improper_curves": {}, + "e_ec_other_key_usages": {}, "e_ecdsa_allowed_ku": {}, + "e_ecpublickey_key_usages": {}, + "e_edwardspublickey_key_usages": {}, "e_ev_business_category_missing": { "ErrCount": 2 }, @@ -546,6 +551,9 @@ "ErrCount": 31843 }, "e_key_usage_incorrect_length": {}, + "e_key_usage_presence": {}, + "e_mailbox_address_shall_contain_an_rfc822_name": {}, + "e_mailbox_validated_enforce_subject_field_restrictions": {}, "e_mp_authority_key_identifier_correct": { "ErrCount": 3704 }, @@ -583,6 +591,7 @@ "ErrCount": 17 }, "e_path_len_constraint_zero_or_less": {}, + "e_policy_qualifiers_other_than_cps_not_permitted": {}, "e_prohibit_dsa_usage": {}, "e_public_key_type_not_allowed": {}, "e_qcstatem_etsi_present_qcs_critical": {}, @@ -598,6 +607,7 @@ "e_qcstatem_qcretentionperiod_valid": {}, "e_qcstatem_qcsscd_valid": {}, "e_qcstatem_qctype_valid": {}, + "e_registration_scheme_id_matches_subject_country": {}, "e_rfc_dnsname_empty_label": { "ErrCount": 16 }, @@ -624,10 +634,13 @@ }, "e_rsa_exp_negative": {}, "e_rsa_fermat_factorization": {}, + "e_rsa_key_usage_legacy_multipurpose": {}, + "e_rsa_key_usage_strict": {}, "e_rsa_mod_less_than_2048_bits": { "ErrCount": 34006 }, "e_rsa_no_public_key": {}, + "e_rsa_other_key_usages": {}, "e_rsa_public_exponent_not_odd": {}, "e_rsa_public_exponent_too_small": {}, "e_san_bare_wildcard": { @@ -637,6 +650,7 @@ "e_san_dns_name_onion_invalid": {}, "e_san_dns_name_onion_not_ev_cert": {}, "e_san_dns_name_starts_with_period": {}, + "e_san_shall_be_present": {}, "e_san_wildcard_not_first": { "ErrCount": 12 }, @@ -649,9 +663,15 @@ "e_signature_algorithm_not_supported": { "ErrCount": 23 }, + "e_single_email_if_present": {}, + "e_smime_legacy_aia_shall_have_one_http": {}, + "e_smime_legacy_multipurpose_eku_check": {}, + "e_smime_strict_aia_shall_have_http_only": {}, + "e_smime_strict_eku_check": {}, "e_spki_rsa_encryption_parameter_not_null": { "ErrCount": 7 }, + "e_strict_multipurpose_smime_ext_subject_directory_attr": {}, "e_sub_ca_aia_marked_critical": {}, "e_sub_ca_aia_missing": { "ErrCount": 292 @@ -673,6 +693,7 @@ "e_sub_cert_aia_missing": { "ErrCount": 11935 }, + "e_sub_cert_basic_constraints_not_critical": {}, "e_sub_cert_cert_policy_empty": { "ErrCount": 738 }, @@ -774,6 +795,7 @@ "e_subject_state_name_max_length": {}, "e_subject_street_address_max_length": {}, "e_subject_surname_max_length": {}, + "e_subscribers_shall_have_crl_distribution_points": {}, "e_superfluous_ku_encoding": { "ErrCount": 3 }, @@ -784,6 +806,8 @@ "ErrCount": 3 }, "e_underscore_not_permissible_in_dnsname": {}, + "e_underscore_permissible_in_dnsname_if_valid_when_replaced": {}, + "e_underscore_present_with_too_long_validity": {}, "e_utc_time_does_not_include_seconds": { "ErrCount": 1 }, @@ -865,12 +889,14 @@ "w_ext_subject_key_identifier_missing_sub_cert": { "WarnCount": 119268 }, + "w_ext_subject_key_identifier_not_recommended_subscriber": {}, "w_extra_subject_common_names": { "WarnCount": 36 }, "w_ian_iana_pub_suffix_empty": {}, "w_issuer_dn_leading_whitespace": {}, "w_issuer_dn_trailing_whitespace": {}, + "w_key_usage_criticality": {}, "w_multiple_issuer_rdn": {}, "w_name_constraint_on_edi_party_name": {}, "w_name_constraint_on_registered_id": {}, @@ -895,6 +921,8 @@ "w_rsa_public_exponent_not_in_range": { "WarnCount": 110 }, + "w_san_should_not_be_critical": {}, + "w_smime_aia_contains_internal_names": {}, "w_sub_ca_aia_does_not_contain_issuing_ca_url": { "WarnCount": 990 }, @@ -908,6 +936,9 @@ "w_sub_ca_name_constraints_not_critical": { "WarnCount": 115 }, + "w_sub_cert_aia_contains_internal_names": { + "WarnCount": 210 + }, "w_sub_cert_aia_does_not_contain_issuing_ca_url": { "WarnCount": 48465 }, @@ -918,6 +949,7 @@ "w_sub_cert_sha1_expiration_too_long": { "WarnCount": 11058 }, + "w_subject_common_name_included": {}, "w_subject_contains_malformed_arpa_ip": { "WarnCount": 2 }, @@ -931,9 +963,6 @@ "w_subject_surname_recommended_max_length": {}, "w_tls_server_cert_valid_time_longer_than_397_days": { "WarnCount": 223 - }, - "w_sub_cert_aia_contains_internal_names": { - "WarnCount": 210 } } } \ No newline at end of file diff --git a/v3/lints/cabf_smime_br/mailbox_address_from_san.go b/v3/lints/cabf_smime_br/mailbox_address_from_san.go new file mode 100644 index 000000000..0374003a4 --- /dev/null +++ b/v3/lints/cabf_smime_br/mailbox_address_from_san.go @@ -0,0 +1,113 @@ +package cabf_smime_br + +/* + * ZLint Copyright 2024 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/encoding/asn1" + "github.com/zmap/zcrypto/x509" + "github.com/zmap/zcrypto/x509/pkix" + "github.com/zmap/zlint/v3/lint" + "github.com/zmap/zlint/v3/util" +) + +// MailboxAddressFromSAN - linter to enforce MAY/SHALL NOT requirements for SMIME certificates +type MailboxAddressFromSAN struct { +} + +func init() { + lint.RegisterLint(&lint.Lint{ + Name: "e_mailbox_address_shall_contain_an_rfc822_name", + Description: "All Mailbox Addresses in the subject field or entries of type dirName of this extension SHALL be repeated as rfc822Name or otherName values of type id-on-SmtpUTF8Mailbox in this extension", + Citation: "SMIME BRs: 7.1.4.2.1", + Source: lint.CABFSMIMEBaselineRequirements, + EffectiveDate: util.CABF_SMIME_BRs_1_0_0_Date, + Lint: NewMailboxAddressFromSAN, + }) +} + +// NewMailboxAddressFromSAN creates a new linter to enforce the requirement that all Mailbox Addresses in SMIME BR certificates must be copied from the SAN +func NewMailboxAddressFromSAN() lint.LintInterface { + return &MailboxAddressFromSAN{} +} + +// CheckApplies is returns true if the certificate's policies assert that it conforms to the SMIME BRs +func (l *MailboxAddressFromSAN) CheckApplies(c *x509.Certificate) bool { + if util.HasEKU(c, x509.ExtKeyUsageEmailProtection) || util.HasEKU(c, x509.ExtKeyUsageAny) { + return true + } + + return util.IsMailboxValidatedCertificate(c) && util.IsSubscriberCert(c) +} + +// Execute checks all the places where Mailbox Addresses may be found in an SMIME certificate and confirms that they are present in the SAN rfc822Name or SAN otherName +func (l *MailboxAddressFromSAN) Execute(c *x509.Certificate) *lint.LintResult { + lintErr := &lint.LintResult{ + Status: lint.Error, + Details: "all certificate mailbox addresses must be present in san:emailAddresses or san:otherNames in addition to any other field they may appear", + } + + // build list of Mailbox addresses from subject:commonName, subject:emailAddress, dirName + toFindMailboxAddresses := getMailboxAddressesFromDistinguishedName(c.Subject) + + for _, dirName := range c.DirectoryNames { + toFindMailboxAddresses = append(toFindMailboxAddresses, getMailboxAddressesFromDistinguishedName(dirName)...) + } + + sanNames := map[string]bool{} + for _, rfc822Name := range c.EmailAddresses { + sanNames[rfc822Name] = true + } + + for _, otherName := range c.OtherNames { + if otherName.TypeID.Equal(util.OidIdOnSmtpUtf8Mailbox) { + // The otherName needs to be specially unmarshalled since it is + // stored as a UTF-8 string rather than what the asn1 package + // describes as a PrintableString. + var otherNameValue string + rest, err := asn1.UnmarshalWithParams(otherName.Value.Bytes, &otherNameValue, "utf8") + if len(rest) > 0 || err != nil { + return lintErr + } + + sanNames[otherNameValue] = true + } + } + + for _, mailboxAddress := range toFindMailboxAddresses { + if _, found := sanNames[mailboxAddress]; !found { + return lintErr + } + } + + return &lint.LintResult{Status: lint.Pass} +} + +func getMailboxAddressesFromDistinguishedName(name pkix.Name) []string { + mailboxAddresses := []string{} + + for _, commonName := range name.CommonNames { + if util.IsMailboxAddress(commonName) { + mailboxAddresses = append(mailboxAddresses, commonName) + } + } + + for _, emailAddress := range name.EmailAddress { + if util.IsMailboxAddress(emailAddress) { + mailboxAddresses = append(mailboxAddresses, emailAddress) + } + } + + return mailboxAddresses +} diff --git a/v3/lints/cabf_smime_br/mailbox_address_from_san_test.go b/v3/lints/cabf_smime_br/mailbox_address_from_san_test.go new file mode 100644 index 000000000..f8a80270d --- /dev/null +++ b/v3/lints/cabf_smime_br/mailbox_address_from_san_test.go @@ -0,0 +1,103 @@ +package cabf_smime_br + +/* + * ZLint Copyright 2024 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 TestMailboxAddressFromSANLint(t *testing.T) { + testCases := []struct { + Name string + InputFilename string + + ExpectedResult lint.LintStatus + ExpectedDetails string + }{ + { + Name: "pass - subject:commonName email address matches san:otherName", + InputFilename: "WithOtherNameMatched.pem", + + ExpectedResult: lint.Pass, + }, + { + Name: "pass - subject:commonName email address matches san:emailAddress", + InputFilename: "WithSANEmailMatched.pem", + + ExpectedResult: lint.Pass, + }, + { + Name: "pass - only contains one san:emailAddress value", + InputFilename: "WithOnlySANEmail.pem", + + ExpectedResult: lint.Pass, + }, + { + Name: "pass - only contains one san:otherName value", + InputFilename: "WithOnlySANOtherName.pem", + + ExpectedResult: lint.Pass, + }, + { + Name: "NE - before effective date", + InputFilename: "NotEffective.pem", + + ExpectedResult: lint.NE, + }, + { + Name: "NA - does not contain smime certificate policy", + InputFilename: "NotApplicable.pem", + + ExpectedResult: lint.NA, + }, + { + Name: "fail - subject:commonName email address does not match san:otherName", + InputFilename: "WithOtherNameUnmatched.pem", + + ExpectedResult: lint.Error, + ExpectedDetails: "all certificate mailbox addresses must be present in san:emailAddresses or san:otherNames in addition to any other field they may appear", + }, + { + Name: "fail - subject:commonName email address does not match the email value under san:otherName", + InputFilename: "WithOtherNameIncorrectType.pem", + + ExpectedResult: lint.Error, + ExpectedDetails: "all certificate mailbox addresses must be present in san:emailAddresses or san:otherNames in addition to any other field they may appear", + }, + { + Name: "fail - subject:commonName email address does not match san:emailAddress", + InputFilename: "WithSANEmailUnmatched.pem", + + ExpectedResult: lint.Error, + ExpectedDetails: "all certificate mailbox addresses must be present in san:emailAddresses or san:otherNames in addition to any other field they may appear", + }, + } + + for _, tc := range testCases { + t.Run(tc.Name, func(t *testing.T) { + result := test.TestLint("e_mailbox_address_shall_contain_an_rfc822_name", "smime/MailboxAddressFromSAN/"+tc.InputFilename) + if result.Status != tc.ExpectedResult { + t.Errorf("expected result %v was %v", tc.ExpectedResult, result.Status) + } + + if tc.ExpectedResult == lint.Error && tc.ExpectedDetails != result.Details { + t.Errorf("expected details: %q, was %q", tc.ExpectedDetails, result.Details) + } + }) + } +} diff --git a/v3/testdata/smime/MailboxAddressFromSAN/NotApplicable.pem b/v3/testdata/smime/MailboxAddressFromSAN/NotApplicable.pem new file mode 100644 index 000000000..689cada1f --- /dev/null +++ b/v3/testdata/smime/MailboxAddressFromSAN/NotApplicable.pem @@ -0,0 +1,40 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: + Validity + Not Before: Sep 1 00:00:00 2023 GMT + Not After : Nov 30 00:00:00 9998 GMT + Subject: CN = unmatched@example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:26:b9:6a:c2:88:bc:24:98:ab:63:d4:4a:f4:41: + b7:33:28:43:a4:60:d6:9a:9e:3f:4d:cc:37:43:6a: + 6e:7d:8d:94:cd:bf:39:94:48:b1:2c:d4:6f:e2:a6: + 2c:df:ce:6a:d7:a0:ea:e9:5e:c1:3c:ce:cb:c3:eb: + 45:d5:0a:e8:c3 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Subject Alternative Name: + email:test@example.com + Signature Algorithm: ecdsa-with-SHA256 + Signature Value: + 30:45:02:21:00:c7:bb:8e:ac:a1:d1:d7:6f:02:d0:f9:2d:e4: + 9a:f7:d0:91:d1:e6:90:65:3f:73:ef:79:cd:3a:45:8c:0e:59: + 3e:02:20:4e:e4:46:d4:05:a5:82:2e:ee:c3:a2:8f:6e:58:20: + 17:82:91:26:0c:38:62:00:12:ba:1e:cf:27:dc:77:d3:2b +-----BEGIN CERTIFICATE----- +MIIBLzCB1qADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMwOTAxMDAwMDAwWhgP +OTk5ODExMzAwMDAwMDBaMCAxHjAcBgNVBAMMFXVubWF0Y2hlZEBleGFtcGxlLmNv +bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCa5asKIvCSYq2PUSvRBtzMoQ6Rg +1pqeP03MN0Nqbn2NlM2/OZRIsSzUb+KmLN/Oateg6ulewTzOy8PrRdUK6MOjHzAd +MBsGA1UdEQQUMBKBEHRlc3RAZXhhbXBsZS5jb20wCgYIKoZIzj0EAwIDSAAwRQIh +AMe7jqyh0ddvAtD5LeSa99CR0eaQZT9z73nNOkWMDlk+AiBO5EbUBaWCLu7Doo9u +WCAXgpEmDDhiABK6Hs8n3HfTKw== +-----END CERTIFICATE----- + diff --git a/v3/testdata/smime/MailboxAddressFromSAN/NotEffective.pem b/v3/testdata/smime/MailboxAddressFromSAN/NotEffective.pem new file mode 100644 index 000000000..cc880261b --- /dev/null +++ b/v3/testdata/smime/MailboxAddressFromSAN/NotEffective.pem @@ -0,0 +1,42 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: + Validity + Not Before: Aug 31 23:00:00 2023 GMT + Not After : Nov 30 00:00:00 9998 GMT + Subject: CN = unmatched@example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:e8:78:25:8d:1c:67:c7:64:99:32:31:5c:4a:fa: + fd:9c:b8:37:f2:1e:51:28:9d:30:1f:75:73:d3:ae: + d9:b7:09:e0:ef:6f:18:76:8d:eb:35:e6:65:e1:60: + e8:bb:f6:01:ee:dc:3a:78:6c:7c:73:cb:15:08:fc: + 4f:17:9a:c1:95 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Subject Alternative Name: + email:test@example.com + X509v3 Certificate Policies: + Policy: 2.23.140.1.5.1.1 + Signature Algorithm: ecdsa-with-SHA256 + Signature Value: + 30:45:02:20:3a:43:d2:9b:15:b0:2b:f9:72:dd:74:6b:0d:76: + 96:e3:8d:91:f3:01:8c:4f:1f:7f:fd:49:4b:0f:a7:d8:c0:88: + 02:21:00:98:92:e3:e9:13:3b:98:4a:6a:16:4a:bd:86:b8:e0: + ee:2f:4e:93:8d:e2:fb:66:a0:ca:38:77:0d:d0:f5:bd:54 +-----BEGIN CERTIFICATE----- +MIIBRTCB7KADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMwODMxMjMwMDAwWhgP +OTk5ODExMzAwMDAwMDBaMCAxHjAcBgNVBAMMFXVubWF0Y2hlZEBleGFtcGxlLmNv +bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOh4JY0cZ8dkmTIxXEr6/Zy4N/Ie +USidMB91c9Ou2bcJ4O9vGHaN6zXmZeFg6Lv2Ae7cOnhsfHPLFQj8TxeawZWjNTAz +MBsGA1UdEQQUMBKBEHRlc3RAZXhhbXBsZS5jb20wFAYDVR0gBA0wCzAJBgdngQwB +BQEBMAoGCCqGSM49BAMCA0gAMEUCIDpD0psVsCv5ct10aw12luONkfMBjE8ff/1J +Sw+n2MCIAiEAmJLj6RM7mEpqFkq9hrjg7i9Ok43i+2agyjh3DdD1vVQ= +-----END CERTIFICATE----- + diff --git a/v3/testdata/smime/MailboxAddressFromSAN/WithOnlySANEmail.pem b/v3/testdata/smime/MailboxAddressFromSAN/WithOnlySANEmail.pem new file mode 100644 index 000000000..8994e8986 --- /dev/null +++ b/v3/testdata/smime/MailboxAddressFromSAN/WithOnlySANEmail.pem @@ -0,0 +1,42 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: + Validity + Not Before: Sep 1 00:00:00 2023 GMT + Not After : Nov 30 00:00:00 9998 GMT + Subject: + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:8e:4d:90:a7:a0:3f:15:e0:6a:de:89:e1:19:74: + 23:51:db:37:5d:9c:21:13:db:7a:65:96:10:43:e5: + 77:f6:dd:52:99:e1:5c:b9:08:81:07:71:cf:59:95: + 2c:13:6a:bc:34:15:8a:b7:17:99:4c:d4:0d:b0:54: + 8a:0a:6d:a7:60 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Extended Key Usage: + E-mail Protection + X509v3 Subject Alternative Name: + email:test@example.com + Signature Algorithm: ecdsa-with-SHA256 + Signature Value: + 30:44:02:20:63:fe:50:25:07:b3:7c:f1:cb:1a:3f:da:e4:17: + d8:ec:95:33:08:65:c5:da:d2:4d:af:9d:fb:34:05:80:cb:2b: + 02:20:63:c7:3b:dd:13:d7:3a:60:86:7a:34:c7:a0:a4:35:2b: + fa:b9:03:37:14:75:cb:e9:8f:db:f9:85:ef:f9:4b:74 +-----BEGIN CERTIFICATE----- +MIIBIzCBy6ADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMwOTAxMDAwMDAwWhgP +OTk5ODExMzAwMDAwMDBaMAAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASOTZCn +oD8V4GreieEZdCNR2zddnCET23pllhBD5Xf23VKZ4Vy5CIEHcc9ZlSwTarw0FYq3 +F5lM1A2wVIoKbadgozQwMjATBgNVHSUEDDAKBggrBgEFBQcDBDAbBgNVHREEFDAS +gRB0ZXN0QGV4YW1wbGUuY29tMAoGCCqGSM49BAMCA0cAMEQCIGP+UCUHs3zxyxo/ +2uQX2OyVMwhlxdrSTa+d+zQFgMsrAiBjxzvdE9c6YIZ6NMegpDUr+rkDNxR1y+mP +2/mF7/lLdA== +-----END CERTIFICATE----- + diff --git a/v3/testdata/smime/MailboxAddressFromSAN/WithOnlySANOtherName.pem b/v3/testdata/smime/MailboxAddressFromSAN/WithOnlySANOtherName.pem new file mode 100644 index 000000000..091f41946 --- /dev/null +++ b/v3/testdata/smime/MailboxAddressFromSAN/WithOnlySANOtherName.pem @@ -0,0 +1,42 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: + Validity + Not Before: Sep 1 00:00:00 2023 GMT + Not After : Nov 30 00:00:00 9998 GMT + Subject: + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:a5:21:3a:ef:c4:e4:dd:5d:ad:17:c4:b5:1a:6e: + 43:72:02:a0:f5:a2:85:e6:56:1e:c7:fe:07:6b:c0: + 0d:89:14:8e:8c:45:f4:32:24:22:62:d2:48:cc:b7: + 3e:14:7f:10:d5:95:7f:45:b6:b6:93:40:a9:f6:8a: + d6:07:64:0b:c6 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Extended Key Usage: + E-mail Protection + X509v3 Subject Alternative Name: critical + othername: SmtpUTF8Mailbox::test@example.com + Signature Algorithm: ecdsa-with-SHA256 + Signature Value: + 30:45:02:21:00:b1:e6:48:b7:2d:ef:dc:ec:ca:ae:bb:4a:39: + 61:d0:32:9e:e5:1f:6f:e0:64:bb:75:dd:50:27:ca:6e:f7:75: + cf:02:20:77:33:c7:f4:79:96:99:5d:be:6b:e4:45:7b:11:18: + 82:05:df:db:29:8d:83:5c:d1:91:81:cf:15:0b:2f:4f:8f +-----BEGIN CERTIFICATE----- +MIIBNTCB3KADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMwOTAxMDAwMDAwWhgP +OTk5ODExMzAwMDAwMDBaMAAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASlITrv +xOTdXa0XxLUabkNyAqD1ooXmVh7H/gdrwA2JFI6MRfQyJCJi0kjMtz4UfxDVlX9F +traTQKn2itYHZAvGo0UwQzATBgNVHSUEDDAKBggrBgEFBQcDBDAsBgNVHREBAf8E +IjAgoB4GCCsGAQUFBwgJoBIMEHRlc3RAZXhhbXBsZS5jb20wCgYIKoZIzj0EAwID +SAAwRQIhALHmSLct79zsyq67Sjlh0DKe5R9v4GS7dd1QJ8pu93XPAiB3M8f0eZaZ +Xb5r5EV7ERiCBd/bKY2DXNGRgc8VCy9Pjw== +-----END CERTIFICATE----- + diff --git a/v3/testdata/smime/MailboxAddressFromSAN/WithOtherNameIncorrectType.pem b/v3/testdata/smime/MailboxAddressFromSAN/WithOtherNameIncorrectType.pem new file mode 100644 index 000000000..69ff58a1a --- /dev/null +++ b/v3/testdata/smime/MailboxAddressFromSAN/WithOtherNameIncorrectType.pem @@ -0,0 +1,43 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: + Validity + Not Before: Sep 1 00:00:00 2023 GMT + Not After : Nov 30 00:00:00 9998 GMT + Subject: CN = test@example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:d0:34:91:6f:e3:95:da:54:c8:8c:2b:91:97:bc: + ec:7b:85:be:9f:42:f1:17:e2:e3:bb:d3:0b:67:8f: + fb:34:4c:9a:45:be:cd:12:46:13:9f:28:61:b9:17: + 05:cc:c5:a7:d5:b2:17:dd:68:3d:61:33:a2:f6:db: + c7:d9:ea:0d:7a + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Certificate Policies: + Policy: 2.23.140.1.5.1.1 + X509v3 Subject Alternative Name: critical + othername: id-on-personalData::test@example.com + Signature Algorithm: ecdsa-with-SHA256 + Signature Value: + 30:45:02:21:00:f1:a7:1a:40:59:15:5e:4c:01:c6:0d:92:37: + 5f:3c:6c:33:be:d8:29:d2:fc:c9:c7:76:c7:66:88:bf:e8:ab: + df:02:20:7a:2f:09:65:b9:09:46:2c:e7:9f:0b:13:82:ad:c9: + f5:db:f1:0d:ff:ed:e8:e4:17:26:ac:16:cd:0d:54:4f:41 +-----BEGIN CERTIFICATE----- +MIIBUTCB+KADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMwOTAxMDAwMDAwWhgP +OTk5ODExMzAwMDAwMDBaMBsxGTAXBgNVBAMMEHRlc3RAZXhhbXBsZS5jb20wWTAT +BgcqhkjOPQIBBggqhkjOPQMBBwNCAATQNJFv45XaVMiMK5GXvOx7hb6fQvEX4uO7 +0wtnj/s0TJpFvs0SRhOfKGG5FwXMxafVshfdaD1hM6L228fZ6g16o0YwRDAUBgNV +HSAEDTALMAkGB2eBDAEFAQEwLAYDVR0RAQH/BCIwIKAeBggrBgEFBQcIAaASDBB0 +ZXN0QGV4YW1wbGUuY29tMAoGCCqGSM49BAMCA0gAMEUCIQDxpxpAWRVeTAHGDZI3 +XzxsM77YKdL8ycd2x2aIv+ir3wIgei8JZbkJRiznnwsTgq3J9dvxDf/t6OQXJqwW +zQ1UT0E= +-----END CERTIFICATE----- + diff --git a/v3/testdata/smime/MailboxAddressFromSAN/WithOtherNameMatched.pem b/v3/testdata/smime/MailboxAddressFromSAN/WithOtherNameMatched.pem new file mode 100644 index 000000000..aa46e4780 --- /dev/null +++ b/v3/testdata/smime/MailboxAddressFromSAN/WithOtherNameMatched.pem @@ -0,0 +1,43 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: + Validity + Not Before: Sep 1 00:00:00 2023 GMT + Not After : Nov 30 00:00:00 9998 GMT + Subject: CN = test@example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:c1:81:4f:04:36:02:fc:9a:a0:76:51:81:8e:aa: + d8:6c:6d:b0:4f:44:30:04:da:c6:28:14:31:21:25: + 87:b1:63:19:d8:e5:3f:e4:fd:0e:4a:e8:fa:ae:c7: + 69:42:b1:d3:59:5a:39:07:f7:c7:39:c3:38:32:fd: + c7:ca:95:36:45 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Certificate Policies: + Policy: 2.23.140.1.5.1.1 + X509v3 Subject Alternative Name: critical + othername: SmtpUTF8Mailbox::test@example.com + Signature Algorithm: ecdsa-with-SHA256 + Signature Value: + 30:45:02:20:1b:0c:2f:00:ca:69:20:a0:8d:75:2b:90:96:57: + ad:7a:bb:98:64:5f:26:11:f6:aa:d7:f2:88:b1:dd:3c:67:2f: + 02:21:00:f9:62:c4:c5:4c:51:05:88:eb:d3:d9:ea:32:6e:74: + aa:fa:59:1a:a8:d4:55:44:cd:84:27:0d:1d:74:6f:12:54 +-----BEGIN CERTIFICATE----- +MIIBUTCB+KADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMwOTAxMDAwMDAwWhgP +OTk5ODExMzAwMDAwMDBaMBsxGTAXBgNVBAMMEHRlc3RAZXhhbXBsZS5jb20wWTAT +BgcqhkjOPQIBBggqhkjOPQMBBwNCAATBgU8ENgL8mqB2UYGOqthsbbBPRDAE2sYo +FDEhJYexYxnY5T/k/Q5K6Pqux2lCsdNZWjkH98c5wzgy/cfKlTZFo0YwRDAUBgNV +HSAEDTALMAkGB2eBDAEFAQEwLAYDVR0RAQH/BCIwIKAeBggrBgEFBQcICaASDBB0 +ZXN0QGV4YW1wbGUuY29tMAoGCCqGSM49BAMCA0gAMEUCIBsMLwDKaSCgjXUrkJZX +rXq7mGRfJhH2qtfyiLHdPGcvAiEA+WLExUxRBYjr09nqMm50qvpZGqjUVUTNhCcN +HXRvElQ= +-----END CERTIFICATE----- + diff --git a/v3/testdata/smime/MailboxAddressFromSAN/WithOtherNameUnmatched.pem b/v3/testdata/smime/MailboxAddressFromSAN/WithOtherNameUnmatched.pem new file mode 100644 index 000000000..bd924f37d --- /dev/null +++ b/v3/testdata/smime/MailboxAddressFromSAN/WithOtherNameUnmatched.pem @@ -0,0 +1,43 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: + Validity + Not Before: Sep 1 00:00:00 2023 GMT + Not After : Nov 30 00:00:00 9998 GMT + Subject: CN = unmatched@example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:ad:23:6e:fc:33:09:49:33:2a:cd:b8:88:fb:f0: + 6f:ee:37:49:9e:cf:60:54:20:96:e3:63:33:b0:87: + 44:7d:c4:50:20:d5:b3:66:bc:1a:1e:11:1b:80:d2: + 8e:ad:be:ff:5c:e5:48:e6:ea:ad:35:60:c8:0b:fb: + da:a7:f2:04:b8 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Certificate Policies: + Policy: 2.23.140.1.5.1.1 + X509v3 Subject Alternative Name: critical + othername: SmtpUTF8Mailbox::test@example.com + Signature Algorithm: ecdsa-with-SHA256 + Signature Value: + 30:45:02:20:21:22:9c:10:f3:b0:e9:a1:e4:6a:1c:8b:a6:51: + 99:f3:90:65:59:fe:0b:09:5e:fe:51:b5:8e:39:45:ae:82:61: + 02:21:00:dc:b2:43:ca:75:8d:0a:c4:9e:fb:51:17:24:78:38: + 35:c0:60:cf:41:49:68:9d:52:7d:22:8b:c8:7a:a9:8e:45 +-----BEGIN CERTIFICATE----- +MIIBVjCB/aADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMwOTAxMDAwMDAwWhgP +OTk5ODExMzAwMDAwMDBaMCAxHjAcBgNVBAMMFXVubWF0Y2hlZEBleGFtcGxlLmNv +bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABK0jbvwzCUkzKs24iPvwb+43SZ7P +YFQgluNjM7CHRH3EUCDVs2a8Gh4RG4DSjq2+/1zlSObqrTVgyAv72qfyBLijRjBE +MBQGA1UdIAQNMAswCQYHZ4EMAQUBATAsBgNVHREBAf8EIjAgoB4GCCsGAQUFBwgJ +oBIMEHRlc3RAZXhhbXBsZS5jb20wCgYIKoZIzj0EAwIDSAAwRQIgISKcEPOw6aHk +ahyLplGZ85BlWf4LCV7+UbWOOUWugmECIQDcskPKdY0KxJ77URckeDg1wGDPQUlo +nVJ9IovIeqmORQ== +-----END CERTIFICATE----- + diff --git a/v3/testdata/smime/MailboxAddressFromSAN/WithSANEmailMatched.pem b/v3/testdata/smime/MailboxAddressFromSAN/WithSANEmailMatched.pem new file mode 100644 index 000000000..917688bfc --- /dev/null +++ b/v3/testdata/smime/MailboxAddressFromSAN/WithSANEmailMatched.pem @@ -0,0 +1,42 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: + Validity + Not Before: Sep 1 00:00:00 2023 GMT + Not After : Nov 30 00:00:00 9998 GMT + Subject: CN = test@example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:0b:af:6b:67:c2:cd:db:66:05:ed:6f:30:23:33: + e7:cc:cf:61:a2:b3:c8:9b:7c:d2:52:07:ff:86:c6: + 1e:fa:3c:4f:f8:65:30:79:c8:da:d3:3f:42:f8:c3: + 15:f1:47:ac:7b:35:fd:d9:b2:cd:f3:ad:05:7d:a8: + 1c:ef:8a:3f:c8 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Subject Alternative Name: + email:test@example.com + X509v3 Certificate Policies: + Policy: 2.23.140.1.5.1.1 + Signature Algorithm: ecdsa-with-SHA256 + Signature Value: + 30:45:02:21:00:b6:87:bd:d9:b6:dc:97:69:67:35:ab:e2:37: + 77:30:01:20:0a:41:18:2d:d7:2a:3f:d6:14:77:e9:67:b9:33: + 7d:02:20:62:d9:30:56:13:82:d6:2f:f8:62:90:d5:f3:3a:52: + 1c:b5:b6:11:59:f9:b1:4b:26:2d:8d:7c:4e:8c:ea:26:21 +-----BEGIN CERTIFICATE----- +MIIBQDCB56ADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMwOTAxMDAwMDAwWhgP +OTk5ODExMzAwMDAwMDBaMBsxGTAXBgNVBAMMEHRlc3RAZXhhbXBsZS5jb20wWTAT +BgcqhkjOPQIBBggqhkjOPQMBBwNCAAQLr2tnws3bZgXtbzAjM+fMz2Gis8ibfNJS +B/+Gxh76PE/4ZTB5yNrTP0L4wxXxR6x7Nf3Zss3zrQV9qBzvij/IozUwMzAbBgNV +HREEFDASgRB0ZXN0QGV4YW1wbGUuY29tMBQGA1UdIAQNMAswCQYHZ4EMAQUBATAK +BggqhkjOPQQDAgNIADBFAiEAtoe92bbcl2lnNaviN3cwASAKQRgt1yo/1hR36We5 +M30CIGLZMFYTgtYv+GKQ1fM6Uhy1thFZ+bFLJi2NfE6M6iYh +-----END CERTIFICATE----- + diff --git a/v3/testdata/smime/MailboxAddressFromSAN/WithSANEmailUnmatched.pem b/v3/testdata/smime/MailboxAddressFromSAN/WithSANEmailUnmatched.pem new file mode 100644 index 000000000..178b33f55 --- /dev/null +++ b/v3/testdata/smime/MailboxAddressFromSAN/WithSANEmailUnmatched.pem @@ -0,0 +1,42 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: + Validity + Not Before: Sep 1 00:00:00 2023 GMT + Not After : Nov 30 00:00:00 9998 GMT + Subject: CN = unmatched@example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:6a:9b:c4:ad:66:96:5d:56:6d:df:31:3c:b4:16: + 8a:88:1d:87:14:b2:aa:9a:00:75:dc:52:b5:81:9e: + 71:04:1b:32:d7:c2:0d:29:6f:54:7b:25:6f:67:73: + dd:6d:43:bf:eb:07:41:29:9e:2f:03:f1:ac:05:01: + 13:f3:b4:a1:da + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Subject Alternative Name: + email:test@example.com + X509v3 Certificate Policies: + Policy: 2.23.140.1.5.1.1 + Signature Algorithm: ecdsa-with-SHA256 + Signature Value: + 30:45:02:20:23:e0:6f:5e:74:ec:4c:ae:55:79:93:72:07:cf: + 3f:02:e7:b9:bc:e8:21:af:dc:77:42:6a:cd:65:2c:51:72:fc: + 02:21:00:cf:c4:ee:48:fe:45:c6:ef:11:89:83:f7:75:8c:ba: + 99:89:d0:d1:7f:16:1b:3c:bb:14:24:b0:df:9b:c0:28:c0 +-----BEGIN CERTIFICATE----- +MIIBRTCB7KADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMwOTAxMDAwMDAwWhgP +OTk5ODExMzAwMDAwMDBaMCAxHjAcBgNVBAMMFXVubWF0Y2hlZEBleGFtcGxlLmNv +bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGqbxK1mll1Wbd8xPLQWiogdhxSy +qpoAddxStYGecQQbMtfCDSlvVHslb2dz3W1Dv+sHQSmeLwPxrAUBE/O0odqjNTAz +MBsGA1UdEQQUMBKBEHRlc3RAZXhhbXBsZS5jb20wFAYDVR0gBA0wCzAJBgdngQwB +BQEBMAoGCCqGSM49BAMCA0gAMEUCICPgb1507EyuVXmTcgfPPwLnubzoIa/cd0Jq +zWUsUXL8AiEAz8TuSP5Fxu8RiYP3dYy6mYnQ0X8WGzy7FCSw35vAKMA= +-----END CERTIFICATE----- + diff --git a/v3/util/san.go b/v3/util/san.go index d1f2f551a..a22bda719 100644 --- a/v3/util/san.go +++ b/v3/util/san.go @@ -1,6 +1,10 @@ package util -import "github.com/zmap/zcrypto/x509" +import ( + "net/mail" + + "github.com/zmap/zcrypto/x509" +) func HasEmailSAN(c *x509.Certificate) bool { for _, san := range c.EmailAddresses { @@ -17,3 +21,10 @@ func HasEmailSAN(c *x509.Certificate) bool { return false } + +// IsMailboxAddress returns true if the passed in string resembles an RFC 5322 +// mailbox address. +func IsMailboxAddress(address string) bool { + validAddress, err := mail.ParseAddress(address) + return err == nil && validAddress.Address == address +}