diff --git a/v3/lints/cabf_smime_br/lint_single_email_if_present.go b/v3/lints/cabf_smime_br/lint_single_email_if_present.go new file mode 100644 index 000000000..960420756 --- /dev/null +++ b/v3/lints/cabf_smime_br/lint_single_email_if_present.go @@ -0,0 +1,58 @@ +/* + * 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. + */ + +package cabf_smime_br + +import ( + "fmt" + + "github.com/zmap/zcrypto/x509" + "github.com/zmap/zlint/v3/lint" + "github.com/zmap/zlint/v3/util" +) + +func init() { + lint.RegisterLint(&lint.Lint{ + Name: "e_single_email_if_present", + Description: "If present, the subject:emailAddress SHALL contain a single Mailbox Address", + Citation: "7.1.4.2.h", + Source: lint.CABFSMIMEBaselineRequirements, + EffectiveDate: util.CABF_SMIME_BRs_1_0_0_Date, + Lint: func() lint.LintInterface { return &singleEmailIfPresent{} }, + }) +} + +type singleEmailIfPresent struct{} + +func NewSingleEmailIfPresent() lint.LintInterface { + return &singleEmailIfPresent{} +} + +func (l *singleEmailIfPresent) CheckApplies(c *x509.Certificate) bool { + return util.IsSubscriberCert(c) && c.EmailAddresses != nil && len(c.EmailAddresses) != 0 +} + +func (l *singleEmailIfPresent) Execute(c *x509.Certificate) *lint.LintResult { + if len(c.EmailAddresses) == 1 { + return &lint.LintResult{ + Status: lint.Pass, + } + } else { + return &lint.LintResult{ + Status: lint.Error, + Details: fmt.Sprintf("subject:emailAddress was present and containted %d names (%s)", len(c.EmailAddresses), c.EmailAddresses), + LintMetadata: lint.LintMetadata{}, + } + } +} diff --git a/v3/lints/cabf_smime_br/lint_single_email_if_present_test.go b/v3/lints/cabf_smime_br/lint_single_email_if_present_test.go new file mode 100644 index 000000000..30a288fb7 --- /dev/null +++ b/v3/lints/cabf_smime_br/lint_single_email_if_present_test.go @@ -0,0 +1,40 @@ +package cabf_smime_br + +import ( + "testing" + + "github.com/zmap/zlint/v3/lint" + "github.com/zmap/zlint/v3/test" +) + +func TestSingleEmailIfPresent(t *testing.T) { + testCases := []struct { + Name string + InputFilename string + ExpectedResult lint.LintStatus + }{ + { + Name: "pass - cert with one email address", + InputFilename: "smime/single_email_present.pem", + ExpectedResult: lint.Pass, + }, + { + Name: "NA - cert with no email addresses", + InputFilename: "smime/no_email_present.pem", + ExpectedResult: lint.NA, + }, + { + Name: "Error - cert with multiple email addresses", + InputFilename: "smime/multiple_email_present.pem", + ExpectedResult: lint.Error, + }, + } + for _, tc := range testCases { + t.Run(tc.Name, func(t *testing.T) { + result := test.TestLint("e_single_email_if_present", 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/multiple_email_present.pem b/v3/testdata/smime/multiple_email_present.pem new file mode 100644 index 000000000..b65b180a9 --- /dev/null +++ b/v3/testdata/smime/multiple_email_present.pem @@ -0,0 +1,41 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: + Validity + Not Before: Oct 15 17:52:28 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:cb:41:d2:58:66:06:29:c0:c8:bf:c9:20:76:7f: + 49:a7:6d:2a:f1:f4:7f:36:4c:94:b4:91:ac:6d:76: + 29:65:11:d0:34:0b:d5:d2:53:e0:dd:86:42:5b:ee: + 37:ca:bb:a0:bc:be:73:7f:61:cb:45:af:8e:46:74: + ce:4b:9a:ff:a2 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Extended Key Usage: + E-mail Protection + X509v3 Subject Alternative Name: + email:coolguy@coolplace.com, email:drumsolo@rockstar.org + Signature Algorithm: ecdsa-with-SHA256 + Signature Value: + 30:46:02:21:00:90:32:cc:3f:a1:bf:31:e7:be:57:8f:a7:30: + 33:bc:ed:2f:92:9a:7a:69:50:bc:7f:e1:72:aa:b1:25:1a:2e: + fe:02:21:00:c1:88:2d:90:b9:72:d4:03:12:c3:45:3a:b5:f3: + 45:72:23:9c:65:73:b4:5e:50:cd:f6:bc:4c:a7:ba:8e:6d:b8 +-----BEGIN CERTIFICATE----- +MIIBQTCB56ADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMxMDE1MTc1MjI4WhgP +OTk5ODExMzAwMDAwMDBaMAAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATLQdJY +ZgYpwMi/ySB2f0mnbSrx9H82TJS0kaxtdillEdA0C9XSU+DdhkJb7jfKu6C8vnN/ +YctFr45GdM5Lmv+io1AwTjATBgNVHSUEDDAKBggrBgEFBQcDBDA3BgNVHREEMDAu +gRVjb29sZ3V5QGNvb2xwbGFjZS5jb22BFWRydW1zb2xvQHJvY2tzdGFyLm9yZzAK +BggqhkjOPQQDAgNJADBGAiEAkDLMP6G/Mee+V4+nMDO87S+SmnppULx/4XKqsSUa +Lv4CIQDBiC2QuXLUAxLDRTq180VyI5xlc7ReUM32vEynuo5tuA== +-----END CERTIFICATE----- diff --git a/v3/testdata/smime/no_email_present.pem b/v3/testdata/smime/no_email_present.pem new file mode 100644 index 000000000..70f65d257 --- /dev/null +++ b/v3/testdata/smime/no_email_present.pem @@ -0,0 +1,38 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: + Validity + Not Before: Oct 15 17:53:09 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:4f:e8:85:20:80:1b:21:66:01:b1:ff:0b:db:f6: + f9:51:6d:d7:66:f4:64:2b:67:b3:31:99:65:35:97: + 9d:d1:69:29:b7:d3:15:65:84:8a:55:24:21:78:a5: + 89:43:be:14:b6:9f:8e:8f:63:50:85:62:44:52:4c: + 59:a1:0a:65:70 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Extended Key Usage: + E-mail Protection + Signature Algorithm: ecdsa-with-SHA256 + Signature Value: + 30:45:02:20:77:4e:a8:1e:bc:68:c9:ff:83:7b:ac:dc:16:2b: + cb:8f:38:1c:95:81:a5:db:55:93:fe:2a:ac:53:a7:f2:e2:4c: + 02:21:00:b0:9b:8b:b0:1f:a4:b6:3f:7e:8d:01:6e:0b:98:43: + a1:95:aa:8f:79:31:1d:35:5a:ed:3c:a1:30:2c:c6:1a:b2 +-----BEGIN CERTIFICATE----- +MIIBBzCBrqADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMxMDE1MTc1MzA5WhgP +OTk5ODExMzAwMDAwMDBaMAAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARP6IUg +gBshZgGx/wvb9vlRbddm9GQrZ7MxmWU1l53RaSm30xVlhIpVJCF4pYlDvhS2n46P +Y1CFYkRSTFmhCmVwoxcwFTATBgNVHSUEDDAKBggrBgEFBQcDBDAKBggqhkjOPQQD +AgNIADBFAiB3TqgevGjJ/4N7rNwWK8uPOByVgaXbVZP+KqxTp/LiTAIhALCbi7Af +pLY/fo0BbguYQ6GVqo95MR01Wu08oTAsxhqy +-----END CERTIFICATE----- diff --git a/v3/testdata/smime/single_email_present.pem b/v3/testdata/smime/single_email_present.pem new file mode 100644 index 000000000..d59599f4f --- /dev/null +++ b/v3/testdata/smime/single_email_present.pem @@ -0,0 +1,41 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: + Validity + Not Before: Oct 15 17:49:19 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:ef:76:01:b8:fe:88:a0:d2:69:ea:ed:d0:16:0f: + b2:57:f3:b9:a5:8c:50:e2:f6:82:ff:fc:6b:b6:0a: + 41:23:cb:dc:52:6f:26:1e:9b:c1:db:aa:26:9e:c0: + 58:6d:bc:ea:d1:1b:b3:55:ec:dd:dc:93:ed:07:36: + 06:44:f5:02:9c + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Extended Key Usage: + E-mail Protection + X509v3 Subject Alternative Name: + email:coolguy@coolplace.com + Signature Algorithm: ecdsa-with-SHA256 + Signature Value: + 30:45:02:20:58:18:e5:5b:31:e1:83:a6:5e:5c:76:40:fe:eb: + a2:82:3a:2b:d9:e0:0f:09:f6:d2:b7:ae:5e:e4:a7:36:13:e5: + 02:21:00:f6:f8:43:f6:76:2d:18:af:33:91:20:71:78:f5:2a: + 9e:9b:08:66:98:c6:ef:bf:cb:06:b9:62:7e:c2:44:92:51 +-----BEGIN CERTIFICATE----- +MIIBKTCB0KADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMxMDE1MTc0OTE5WhgP +OTk5ODExMzAwMDAwMDBaMAAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATvdgG4 +/oig0mnq7dAWD7JX87mljFDi9oL//Gu2CkEjy9xSbyYem8HbqiaewFhtvOrRG7NV +7N3ck+0HNgZE9QKcozkwNzATBgNVHSUEDDAKBggrBgEFBQcDBDAgBgNVHREEGTAX +gRVjb29sZ3V5QGNvb2xwbGFjZS5jb20wCgYIKoZIzj0EAwIDSAAwRQIgWBjlWzHh +g6ZeXHZA/uuigjor2eAPCfbSt65e5Kc2E+UCIQD2+EP2di0YrzORIHF49Sqemwhm +mMbvv8sGuWJ+wkSSUQ== +-----END CERTIFICATE-----