diff --git a/v3/lints/cabf_smime_br/lint_single_email_subject_if_present.go b/v3/lints/cabf_smime_br/lint_single_email_subject_if_present.go new file mode 100644 index 000000000..1958a95d5 --- /dev/null +++ b/v3/lints/cabf_smime_br/lint_single_email_subject_if_present.go @@ -0,0 +1,60 @@ +/* + * 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. + */ + +package cabf_smime_br + +import ( + "fmt" + "net/mail" + + "github.com/zmap/zcrypto/x509" + "github.com/zmap/zlint/v3/lint" + "github.com/zmap/zlint/v3/util" +) + +func init() { + lint.RegisterCertificateLint(&lint.CertificateLint{ + LintMetadata: lint.LintMetadata{ + Name: "e_single_email_subject_if_present", + Description: "If present, the subject:emailAddress SHALL contain a single Mailbox Address", + Citation: "7.1.4.2.2.h", + Source: lint.CABFSMIMEBaselineRequirements, + EffectiveDate: util.CABF_SMIME_BRs_1_0_0_Date, + }, + Lint: NewSingleEmailSubjectIfPresent, + }) +} + +type singleEmailSubjectIfPresent struct{} + +func NewSingleEmailSubjectIfPresent() lint.LintInterface { + return &singleEmailSubjectIfPresent{} +} + +func (l *singleEmailSubjectIfPresent) CheckApplies(c *x509.Certificate) bool { + emailAddress := c.Subject.EmailAddress + return util.IsSubscriberCert(c) && emailAddress != nil && len(emailAddress) != 0 && util.IsSMIMEBRCertificate(c) +} + +func (l *singleEmailSubjectIfPresent) Execute(c *x509.Certificate) *lint.LintResult { + for _, email := range c.Subject.EmailAddress { + if _, err := mail.ParseAddress(email); err != nil { + return &lint.LintResult{ + Status: lint.Error, + Details: fmt.Sprintf("subject:emailAddress was present and contained an invalid email address (%s)", email), + } + } + } + return &lint.LintResult{Status: lint.Pass} +} diff --git a/v3/lints/cabf_smime_br/lint_single_email_subject_if_present_test.go b/v3/lints/cabf_smime_br/lint_single_email_subject_if_present_test.go new file mode 100644 index 000000000..7e64ad9f1 --- /dev/null +++ b/v3/lints/cabf_smime_br/lint_single_email_subject_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 TestSingleEmailSubjectIfPresent(t *testing.T) { + testCases := []struct { + Name string + InputFilename string + ExpectedResult lint.LintStatus + }{ + { + Name: "error - email address present in subjectDN with multiple values", + InputFilename: "smime/twoEmailAddressesInSubjectDN.pem", + ExpectedResult: lint.Error, + }, + { + Name: "pass - email address present in subjectDN with one value", + InputFilename: "smime/oneEmailAddressInSubjectDN.pem", + ExpectedResult: lint.Pass, + }, + { + Name: "na - no email address present in subjectDN", + InputFilename: "smime/noEmailAddressInSubjectDN.pem", + ExpectedResult: lint.NA, + }, + } + for _, tc := range testCases { + t.Run(tc.Name, func(t *testing.T) { + result := test.TestLint("e_single_email_subject_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/noEmailAddressInSubjectDN.pem b/v3/testdata/smime/noEmailAddressInSubjectDN.pem new file mode 100644 index 000000000..58bbd4d26 --- /dev/null +++ b/v3/testdata/smime/noEmailAddressInSubjectDN.pem @@ -0,0 +1,41 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 42:17:33:09:8d:0d:17:ce:1e:5c:97:77 + Signature Algorithm: ecdsa-with-SHA256 + Issuer: CN = Lint CA, O = Lint, C = DE + Validity + Not Before: Sep 1 00:00:00 2023 GMT + Not After : Sep 1 00:00:00 2024 GMT + Subject: CN = SMIME, O = Lint, C = DE + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:fc:9d:49:5c:28:e0:11:83:2e:f2:eb:91:54:31: + 24:b6:78:82:5f:ee:42:29:8e:c8:c3:c1:00:1c:66: + d7:51:96:5d:28:a2:fd:1e:dc:a2:97:e5:e9:ce:53: + 58:4b:fb:0a:46:df:42:ff:35:c8:8e:27:48:96:4e: + 46:4e:32:68:20 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Certificate Policies: + Policy: 2.23.140.1.5.1.2 + + Signature Algorithm: ecdsa-with-SHA256 + 30:45:02:21:00:e7:47:dc:26:b3:2e:3b:fe:d7:af:a5:bc:63: + 94:ba:94:bd:38:7c:3c:ec:40:fa:38:39:29:ae:77:c0:3c:14: + 06:02:20:71:cf:42:af:f3:1b:b9:90:27:d2:bc:76:67:c0:00: + dd:59:54:61:95:b8:66:5f:c3:4e:99:6c:a2:58:0f:b6:e2 +-----BEGIN CERTIFICATE----- +MIIBbDCCARKgAwIBAgIMQhczCY0NF84eXJd3MAoGCCqGSM49BAMCMC4xEDAOBgNV +BAMMB0xpbnQgQ0ExDTALBgNVBAoMBExpbnQxCzAJBgNVBAYTAkRFMB4XDTIzMDkw +MTAwMDAwMFoXDTI0MDkwMTAwMDAwMFowLDEOMAwGA1UEAwwFU01JTUUxDTALBgNV +BAoMBExpbnQxCzAJBgNVBAYTAkRFMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE +/J1JXCjgEYMu8uuRVDEktniCX+5CKY7Iw8EAHGbXUZZdKKL9Htyil+XpzlNYS/sK +Rt9C/zXIjidIlk5GTjJoIKMYMBYwFAYDVR0gBA0wCzAJBgdngQwBBQECMAoGCCqG +SM49BAMCA0gAMEUCIQDnR9wmsy47/tevpbxjlLqUvTh8POxA+jg5Ka53wDwUBgIg +cc9Cr/MbuZAn0rx2Z8AA3VlUYZW4Zl/DTplsolgPtuI= +-----END CERTIFICATE----- diff --git a/v3/testdata/smime/oneEmailAddressInSubjectDN.pem b/v3/testdata/smime/oneEmailAddressInSubjectDN.pem new file mode 100644 index 000000000..9598a7c2a --- /dev/null +++ b/v3/testdata/smime/oneEmailAddressInSubjectDN.pem @@ -0,0 +1,42 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 89:20:fd:0d:4f:59:a1:79:ff:86:e5:26 + Signature Algorithm: ecdsa-with-SHA256 + Issuer: CN = Lint CA, O = Lint, C = DE + Validity + Not Before: Sep 1 00:00:00 2023 GMT + Not After : Sep 1 00:00:00 2024 GMT + Subject: emailAddress = zlint@example.com, O = Lint, C = DE + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:91:d8:6e:7f:71:94:58:a1:2d:2b:fd:0c:e2:51: + 1a:69:a5:2b:43:46:3d:1e:0c:e4:21:d4:29:a6:c3: + 9a:c5:07:df:9d:9a:81:05:04:92:43:45:4b:46:e3: + 24:e5:ba:5e:a6:70:a1:8e:b1:f8:d6:f4:be:d1:46: + b5:91:af:50:61 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Certificate Policies: + Policy: 2.23.140.1.5.1.2 + + Signature Algorithm: ecdsa-with-SHA256 + 30:46:02:21:00:f3:c0:3b:a7:6e:c2:e9:a7:31:c5:8c:ef:7c: + c5:3e:73:56:27:e4:af:dd:fe:5c:42:68:de:b8:e1:0a:b3:98: + 46:02:21:00:84:56:5e:50:93:17:17:8c:86:3c:93:56:8f:79: + 03:5e:53:01:f3:c9:4d:d2:4b:ea:6f:46:7b:ac:32:0d:c6:ad +-----BEGIN CERTIFICATE----- +MIIBgDCCASWgAwIBAgINAIkg/Q1PWaF5/4blJjAKBggqhkjOPQQDAjAuMRAwDgYD +VQQDDAdMaW50IENBMQ0wCwYDVQQKDARMaW50MQswCQYDVQQGEwJERTAeFw0yMzA5 +MDEwMDAwMDBaFw0yNDA5MDEwMDAwMDBaMD4xIDAeBgkqhkiG9w0BCQEWEXpsaW50 +QGV4YW1wbGUuY29tMQ0wCwYDVQQKDARMaW50MQswCQYDVQQGEwJERTBZMBMGByqG +SM49AgEGCCqGSM49AwEHA0IABJHYbn9xlFihLSv9DOJRGmmlK0NGPR4M5CHUKabD +msUH352agQUEkkNFS0bjJOW6XqZwoY6x+Nb0vtFGtZGvUGGjGDAWMBQGA1UdIAQN +MAswCQYHZ4EMAQUBAjAKBggqhkjOPQQDAgNJADBGAiEA88A7p27C6acxxYzvfMU+ +c1Yn5K/d/lxCaN644QqzmEYCIQCEVl5QkxcXjIY8k1aPeQNeUwHzyU3SS+pvRnus +Mg3GrQ== +-----END CERTIFICATE----- diff --git a/v3/testdata/smime/twoEmailAddressesInSubjectDN.pem b/v3/testdata/smime/twoEmailAddressesInSubjectDN.pem new file mode 100644 index 000000000..6560a6af7 --- /dev/null +++ b/v3/testdata/smime/twoEmailAddressesInSubjectDN.pem @@ -0,0 +1,42 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 11:58:a9:ab:65:63:46:e7:02:8f:b3:eb + Signature Algorithm: ecdsa-with-SHA256 + Issuer: CN = Lint CA, O = Lint, C = DE + Validity + Not Before: Sep 1 00:00:00 2023 GMT + Not After : Sep 1 00:00:00 2024 GMT + Subject: emailAddress = zlint@example.com second@example.com, O = Lint, C = DE + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:91:ee:42:50:c4:da:48:da:63:04:bd:e0:30:54: + 3e:65:b7:c8:17:1a:c1:38:4d:f4:a6:91:3b:03:0c: + d2:36:cf:f1:72:d9:b3:4c:d4:39:9e:a4:d0:b5:27: + d2:50:74:9f:80:b2:ac:d2:fa:af:ed:bd:de:8b:3e: + 52:d7:08:77:a2 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Certificate Policies: + Policy: 2.23.140.1.5.1.2 + + Signature Algorithm: ecdsa-with-SHA256 + 30:46:02:21:00:98:5f:ff:ba:1f:32:88:63:1f:cd:6d:f9:fb: + 81:82:48:c1:d9:2d:fb:84:5b:6e:6d:74:87:7f:61:ca:a3:a5: + a7:02:21:00:c8:f2:5b:c7:96:1c:3c:67:b5:4d:eb:27:4d:71: + fa:86:6b:c0:c4:a8:fd:d1:8e:dc:3b:17:f9:1f:ca:3c:ff:f3 +-----BEGIN CERTIFICATE----- +MIIBkjCCATegAwIBAgIMEVipq2VjRucCj7PrMAoGCCqGSM49BAMCMC4xEDAOBgNV +BAMMB0xpbnQgQ0ExDTALBgNVBAoMBExpbnQxCzAJBgNVBAYTAkRFMB4XDTIzMDkw +MTAwMDAwMFoXDTI0MDkwMTAwMDAwMFowUTEzMDEGCSqGSIb3DQEJARYkemxpbnRA +ZXhhbXBsZS5jb20gc2Vjb25kQGV4YW1wbGUuY29tMQ0wCwYDVQQKDARMaW50MQsw +CQYDVQQGEwJERTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJHuQlDE2kjaYwS9 +4DBUPmW3yBcawThN9KaROwMM0jbP8XLZs0zUOZ6k0LUn0lB0n4CyrNL6r+293os+ +UtcId6KjGDAWMBQGA1UdIAQNMAswCQYHZ4EMAQUBAjAKBggqhkjOPQQDAgNJADBG +AiEAmF//uh8yiGMfzW35+4GCSMHZLfuEW25tdId/YcqjpacCIQDI8lvHlhw8Z7VN +6ydNcfqGa8DEqP3Rjtw7F/kfyjz/8w== +-----END CERTIFICATE-----