From 778325e022242648e0ccef2f458cba0f1f312138 Mon Sep 17 00:00:00 2001 From: Adam Bender Date: Tue, 20 Feb 2024 16:19:22 -0800 Subject: [PATCH 1/2] Add line for S/MIME BR 7.1.2.3.k. --- .../lint_qc_statements_not_critical.go | 55 +++++++++++++++++++ .../lint_qc_statements_not_critical_test.go | 33 +++++++++++ 2 files changed, 88 insertions(+) create mode 100644 v3/lints/cabf_smime_br/lint_qc_statements_not_critical.go create mode 100644 v3/lints/cabf_smime_br/lint_qc_statements_not_critical_test.go diff --git a/v3/lints/cabf_smime_br/lint_qc_statements_not_critical.go b/v3/lints/cabf_smime_br/lint_qc_statements_not_critical.go new file mode 100644 index 000000000..da37a90be --- /dev/null +++ b/v3/lints/cabf_smime_br/lint_qc_statements_not_critical.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 ( + "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_smime_qc_statements_must_not_be_critical", + Description: "This extension MAY be present and SHALL NOT be marked critical.", + Citation: "7.1.2.3.k", + Source: lint.CABFSMIMEBaselineRequirements, + EffectiveDate: util.CABF_SMIME_BRs_1_0_0_Date, + }, + Lint: NewQCStatementNotCritical, + }) +} + +type qcStatementNotCritical struct{} + +func NewQCStatementNotCritical() lint.LintInterface { + return &qcStatementNotCritical{} +} + +func (l *qcStatementNotCritical) CheckApplies(c *x509.Certificate) bool { + return util.IsSubscriberCert(c) && util.IsExtInCert(c, util.QcStateOid) && util.IsSMIMEBRCertificate(c) +} + +func (l *qcStatementNotCritical) Execute(c *x509.Certificate) *lint.LintResult { + san := util.GetExtFromCert(c, util.QcStateOid) + if san.Critical { + return &lint.LintResult{ + Status: lint.Error, + Details: "qc statements extension is marked critical", + } + } + return &lint.LintResult{Status: lint.Pass} +} diff --git a/v3/lints/cabf_smime_br/lint_qc_statements_not_critical_test.go b/v3/lints/cabf_smime_br/lint_qc_statements_not_critical_test.go new file mode 100644 index 000000000..a978a587d --- /dev/null +++ b/v3/lints/cabf_smime_br/lint_qc_statements_not_critical_test.go @@ -0,0 +1,33 @@ +package cabf_smime_br + +import ( + "testing" + + "github.com/zmap/zlint/v3/lint" + "github.com/zmap/zlint/v3/test" +) + +func TestSMIMEQCStatementsNotCritical(t *testing.T) { + testCases := []struct { + Name string + InputFilename string + ExpectedResult lint.LintStatus + }{ + { + Name: "N/A - no qcStatements extension", + InputFilename: "smime/legacyAiaOneHTTPOneLdap.pem", + ExpectedResult: lint.NA, + }, + // Test cases are hard to construct because: + // - while the zcrypto x509.Certificate struct has an QCStatements field, it is ignored when creating a certificate + // - OpenSSL doesn't support writing the qcStatements extension. + } + for _, tc := range testCases { + t.Run(tc.Name, func(t *testing.T) { + result := test.TestLint("e_smime_qc_statements_must_not_be_critical", tc.InputFilename) + if result.Status != tc.ExpectedResult { + t.Errorf("expected result %v was %v - details: %v", tc.ExpectedResult, result.Status, result.Details) + } + }) + } +} From a8930a6653d7b1e5eb03a285eb6f38179077875f Mon Sep 17 00:00:00 2001 From: Adam Bender Date: Mon, 26 Feb 2024 13:58:43 -0800 Subject: [PATCH 2/2] Add tests generated by christopher-henderson --- .../lint_qc_statements_not_critical_test.go | 13 ++++-- ...c_statements_must_not_be_critical_fail.pem | 40 +++++++++++++++++++ ...c_statements_must_not_be_critical_pass.pem | 40 +++++++++++++++++++ 3 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 v3/testdata/smime/e_smime_qc_statements_must_not_be_critical_fail.pem create mode 100644 v3/testdata/smime/e_smime_qc_statements_must_not_be_critical_pass.pem diff --git a/v3/lints/cabf_smime_br/lint_qc_statements_not_critical_test.go b/v3/lints/cabf_smime_br/lint_qc_statements_not_critical_test.go index a978a587d..9b3d94131 100644 --- a/v3/lints/cabf_smime_br/lint_qc_statements_not_critical_test.go +++ b/v3/lints/cabf_smime_br/lint_qc_statements_not_critical_test.go @@ -18,9 +18,16 @@ func TestSMIMEQCStatementsNotCritical(t *testing.T) { InputFilename: "smime/legacyAiaOneHTTPOneLdap.pem", ExpectedResult: lint.NA, }, - // Test cases are hard to construct because: - // - while the zcrypto x509.Certificate struct has an QCStatements field, it is ignored when creating a certificate - // - OpenSSL doesn't support writing the qcStatements extension. + { + Name: "Pass - qcStatements not critical", + InputFilename: "smime/e_smime_qc_statements_must_not_be_critical_pass.pem", + ExpectedResult: lint.Pass, + }, + { + Name: "Fail - qcStatements critical", + InputFilename: "smime/e_smime_qc_statements_must_not_be_critical_fail.pem", + ExpectedResult: lint.Error, + }, } for _, tc := range testCases { t.Run(tc.Name, func(t *testing.T) { diff --git a/v3/testdata/smime/e_smime_qc_statements_must_not_be_critical_fail.pem b/v3/testdata/smime/e_smime_qc_statements_must_not_be_critical_fail.pem new file mode 100644 index 000000000..8f1655c0d --- /dev/null +++ b/v3/testdata/smime/e_smime_qc_statements_must_not_be_critical_fail.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: + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:51:a4:d5:79:b9:32:be:a9:71:c1:d3:6c:9a:19: + 94:d0:70:1f:64:bc:61:4e:a6:fc:5e:9f:ba:fb:4d: + b6:8a:a4:a0:2f:e6:13:16:f1:39:65:9c:02:ae:36: + 22:a4:b6:59:49:02:ad:ec:3f:18:9c:93:32:42:6c: + 9d:f8:9d:3a:bf + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Certificate Policies: + Policy: 2.23.140.1.5.4.3 + qcStatements: critical + 0. + Signature Algorithm: ecdsa-with-SHA256 + Signature Value: + 30:44:02:20:17:97:15:1f:4f:72:1a:48:91:9d:b8:14:b7:61: + 96:cc:12:e1:5d:7a:47:4a:b2:98:31:81:70:fe:f4:1a:c9:a2: + 02:20:3d:1d:9c:00:cc:76:94:22:bb:37:cc:5c:5e:91:53:f9: + 1d:7b:0b:e9:01:54:38:16:85:3f:c0:10:3e:5d:df:bc +-----BEGIN CERTIFICATE----- +MIIBGjCBwqADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMwOTAxMDAwMDAwWhgP +OTk5ODExMzAwMDAwMDBaMAAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARRpNV5 +uTK+qXHB02yaGZTQcB9kvGFOpvxen7r7TbaKpKAv5hMW8TllnAKuNiKktllJAq3s +PxickzJCbJ34nTq/oyswKTAUBgNVHSAEDTALMAkGB2eBDAEFBAMwEQYIKwYBBQUH +AQMBAf8EAjAAMAoGCCqGSM49BAMCA0cAMEQCIBeXFR9PchpIkZ24FLdhlswS4V16 +R0qymDGBcP70GsmiAiA9HZwAzHaUIrs3zFxekVP5HXsL6QFUOBaFP8AQPl3fvA== +-----END CERTIFICATE----- diff --git a/v3/testdata/smime/e_smime_qc_statements_must_not_be_critical_pass.pem b/v3/testdata/smime/e_smime_qc_statements_must_not_be_critical_pass.pem new file mode 100644 index 000000000..16a82ffb4 --- /dev/null +++ b/v3/testdata/smime/e_smime_qc_statements_must_not_be_critical_pass.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: + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:11:d1:b5:e6:9a:aa:67:7c:06:39:35:96:c1:1a: + 8e:8e:15:7b:af:a2:ab:72:e0:0c:8e:b4:56:1e:3c: + 61:16:1d:a0:19:b9:66:03:77:0b:0d:10:18:19:6e: + 43:57:3d:8d:2b:5a:2f:73:64:21:40:3c:b8:b5:bc: + 7f:3e:1a:d2:98 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Certificate Policies: + Policy: 2.23.140.1.5.4.3 + qcStatements: + 0. + Signature Algorithm: ecdsa-with-SHA256 + Signature Value: + 30:44:02:20:04:cf:50:3e:11:20:5c:01:14:70:5d:a3:f9:16: + 2a:1a:49:ad:c0:8c:2f:27:97:17:c2:c2:d3:db:88:2a:ac:1e: + 02:20:02:d7:1c:fc:e2:6f:93:c5:39:92:e1:3a:75:86:06:d8: + 46:a8:af:6b:44:77:98:a4:ad:a8:29:5b:45:c9:11:0d +-----BEGIN CERTIFICATE----- +MIIBFzCBv6ADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMwOTAxMDAwMDAwWhgP +OTk5ODExMzAwMDAwMDBaMAAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQR0bXm +mqpnfAY5NZbBGo6OFXuvoqty4AyOtFYePGEWHaAZuWYDdwsNEBgZbkNXPY0rWi9z +ZCFAPLi1vH8+GtKYoygwJjAUBgNVHSAEDTALMAkGB2eBDAEFBAMwDgYIKwYBBQUH +AQMEAjAAMAoGCCqGSM49BAMCA0cAMEQCIATPUD4RIFwBFHBdo/kWKhpJrcCMLyeX +F8LC09uIKqweAiAC1xz84m+TxTmS4Tp1hgbYRqiva0R3mKStqClbRckRDQ== +-----END CERTIFICATE-----