diff --git a/v3/lints/cabf_smime_br/lint_subject_country_name.go b/v3/lints/cabf_smime_br/lint_subject_country_name.go new file mode 100644 index 000000000..07a7dfd02 --- /dev/null +++ b/v3/lints/cabf_smime_br/lint_subject_country_name.go @@ -0,0 +1,55 @@ +/* + * 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 ( + "strings" + + "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_subject_country_name", + Description: "If present, the subject:countryName SHALL contain the two‐letter ISO 3166‐1 country code associated with the location of the Subject", + Citation: "S/MIME BRs: 7.1.4.2.2n", + Source: lint.CABFSMIMEBaselineRequirements, + EffectiveDate: util.CABF_SMIME_BRs_1_0_0_Date, + }, + Lint: NewSubjectCountryName, + }) +} + +type subjectCountryName struct{} + +func NewSubjectCountryName() lint.LintInterface { + return &subjectCountryName{} +} + +func (l *subjectCountryName) CheckApplies(c *x509.Certificate) bool { + return util.IsMailboxValidatedCertificate(c) +} + +func (l *subjectCountryName) Execute(c *x509.Certificate) *lint.LintResult { + for _, cc := range c.Subject.Country { + if !util.IsISOCountryCode(cc) && strings.ToUpper(cc) != "XX" { + return &lint.LintResult{Status: lint.Error} + } + } + return &lint.LintResult{Status: lint.Pass} +} diff --git a/v3/lints/cabf_smime_br/lint_subject_country_name_test.go b/v3/lints/cabf_smime_br/lint_subject_country_name_test.go new file mode 100644 index 000000000..641d27028 --- /dev/null +++ b/v3/lints/cabf_smime_br/lint_subject_country_name_test.go @@ -0,0 +1,49 @@ +/* + * 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 ( + "testing" + + "github.com/zmap/zlint/v3/lint" + "github.com/zmap/zlint/v3/test" +) + +func TestSubjectCountryName(t *testing.T) { + testCases := []struct { + Name string + InputFilename string + ExpectedResult lint.LintStatus + }{ + { + Name: "pass - valid email in commonName", + InputFilename: "smime/subject_country_name_valid.pem", + ExpectedResult: lint.Pass, + }, + { + Name: "fail - invalid email in commonName", + InputFilename: "smime/subject_country_name_invalid.pem", + ExpectedResult: lint.Error, + }, + } + for _, tc := range testCases { + t.Run(tc.Name, func(t *testing.T) { + result := test.TestLint("e_subject_country_name", 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/subject_country_name_invalid.pem b/v3/testdata/smime/subject_country_name_invalid.pem new file mode 100644 index 000000000..95644a8ab --- /dev/null +++ b/v3/testdata/smime/subject_country_name_invalid.pem @@ -0,0 +1,42 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: + Validity + Not Before: Feb 28 22:55:50 2024 GMT + Not After : Nov 30 00:00:00 9998 GMT + Subject: C = ZZ + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:29:28:3a:a6:4e:3f:5c:33:ad:7e:fe:04:60:b8: + e8:26:9f:49:b6:32:22:29:61:6f:6d:5f:d6:30:d7: + 68:5e:9d:ea:ad:6c:2d:09:b5:43:ad:93:27:2b:4d: + 29:d2:02:29:57:e0:44:a1:7a:05:e4:9d:a4:20:de: + 72:18:ae:87:54 + 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 + Signature Value: + 30:44:02:20:3b:61:1d:fe:f7:49:9d:e2:8a:b7:96:39:47:91: + d8:c3:b8:f5:28:d4:6e:65:73:bf:04:a5:8a:30:7c:89:d8:d3: + 02:20:4e:f6:22:b9:e7:ee:c2:ef:0a:e9:5c:03:22:c9:b5:e7: + 46:8d:f8:f1:cf:f0:a6:0b:1a:12:35:fe:d2:c5:42:97 +-----BEGIN CERTIFICATE----- +MIIBKTCB0aADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjQwMjI4MjI1NTUwWhgP +OTk5ODExMzAwMDAwMDBaMA0xCzAJBgNVBAYTAlpaMFkwEwYHKoZIzj0CAQYIKoZI +zj0DAQcDQgAEKSg6pk4/XDOtfv4EYLjoJp9JtjIiKWFvbV/WMNdoXp3qrWwtCbVD +rZMnK00p0gIpV+BEoXoF5J2kIN5yGK6HVKMtMCswEwYDVR0lBAwwCgYIKwYBBQUH +AwQwFAYDVR0gBA0wCzAJBgdngQwBBQEDMAoGCCqGSM49BAMCA0cAMEQCIDthHf73 +SZ3iireWOUeR2MO49SjUbmVzvwSlijB8idjTAiBO9iK55+7C7wrpXAMiybXnRo34 +8c/wpgsaEjX+0sVClw== +-----END CERTIFICATE----- + diff --git a/v3/testdata/smime/subject_country_name_valid.pem b/v3/testdata/smime/subject_country_name_valid.pem new file mode 100644 index 000000000..083203897 --- /dev/null +++ b/v3/testdata/smime/subject_country_name_valid.pem @@ -0,0 +1,42 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: + Validity + Not Before: Feb 28 22:56:13 2024 GMT + Not After : Nov 30 00:00:00 9998 GMT + Subject: C = US + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:f1:df:0e:55:30:da:76:fa:00:c8:d6:ef:08:0b: + 56:85:67:71:87:8b:c2:08:cb:57:fe:1c:87:b5:ef: + aa:56:07:c5:4f:1a:f3:69:ff:4a:3c:70:65:92:49: + 78:1d:e0:65:2b:c3:08:6e:23:d6:8d:7a:bd:d2:1a: + 78:0c:fe:bf:a9 + 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 + Signature Value: + 30:46:02:21:00:d1:18:a6:4c:fc:25:c1:28:13:0f:c8:99:2b: + ec:4b:49:dd:19:c3:e8:d3:4a:4f:97:d8:80:eb:9c:05:75:f6: + d4:02:21:00:dc:bd:d5:e1:d7:dd:f9:b1:2b:80:75:84:60:82: + 45:27:eb:0f:5f:4c:83:8c:a9:42:8f:3e:63:4b:a7:1b:70:d9 +-----BEGIN CERTIFICATE----- +MIIBKzCB0aADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjQwMjI4MjI1NjEzWhgP +OTk5ODExMzAwMDAwMDBaMA0xCzAJBgNVBAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZI +zj0DAQcDQgAE8d8OVTDadvoAyNbvCAtWhWdxh4vCCMtX/hyHte+qVgfFTxrzaf9K +PHBlkkl4HeBlK8MIbiPWjXq90hp4DP6/qaMtMCswEwYDVR0lBAwwCgYIKwYBBQUH +AwQwFAYDVR0gBA0wCzAJBgdngQwBBQEDMAoGCCqGSM49BAMCA0kAMEYCIQDRGKZM +/CXBKBMPyJkr7EtJ3RnD6NNKT5fYgOucBXX21AIhANy91eHX3fmxK4B1hGCCRSfr +D19Mg4ypQo8+Y0unG3DZ +-----END CERTIFICATE----- +