Skip to content

Commit

Permalink
CABF SMIME BR 7.1.2.3.m - Adobe Extensions (#763)
Browse files Browse the repository at this point in the history
* add lints for adobe extensions presence and criticality in smime certs

* move adobe extensions to preserve alphabetical order

* update timestamp references and use new CertificateLint type

* Update v3/lints/cabf_smime_br/lint_adobe_extensions_legacy_multipurpose_criticality.go

Co-authored-by: Rob <3725956+robplee@users.noreply.github.com>

* Update v3/lints/cabf_smime_br/lint_adobe_extensions_strict_presence.go

Co-authored-by: Rob <3725956+robplee@users.noreply.github.com>

* Update v3/lints/cabf_smime_br/lint_adobe_extensions_legacy_multipurpose_criticality.go

Co-authored-by: Rob <3725956+robplee@users.noreply.github.com>

* update comments

---------

Co-authored-by: marahrehorciuc <mara.hrehorciuc@globalsign.com>
Co-authored-by: Rob <3725956+robplee@users.noreply.github.com>
Co-authored-by: Christopher Henderson <chris@chenderson.org>
  • Loading branch information
4 people committed Nov 19, 2023
1 parent 45e6204 commit a08efa8
Show file tree
Hide file tree
Showing 13 changed files with 580 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* 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 (
"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_adobe_extensions_legacy_multipurpose_criticality",
Description: "If present, Adobe Time‐stamp X509 extension (1.2.840.113583.1.1.9.1) or the Adobe ArchiveRevInfo extension (1.2.840.113583.1.1.9.2) SHALL NOT be marked as critical for multipurpose/legacy SMIME certificates",
Citation: "7.1.2.3.m",
Source: lint.CABFSMIMEBaselineRequirements,
EffectiveDate: util.CABF_SMIME_BRs_1_0_0_Date,
},
Lint: NewAdobeExtensionsLegacyMultipurposeCriticality,
})
}

type adobeExtensionsLegacyMultipurposeCriticality struct{}

// NewAdobeExtensionsLegacyMultipurposeCriticality creates a new linter to enforce adobe x509 extensions requirements for multipurpose or legacy SMIME certs
func NewAdobeExtensionsLegacyMultipurposeCriticality() lint.CertificateLintInterface {
return &adobeExtensionsLegacyMultipurposeCriticality{}
}

// CheckApplies returns true if for any subscriber certificate the certificate's policies assert that it conforms to the multipurpose or legacy policy requirements defined in the SMIME BRs
// and the certificate contains one of the adobe x509 extensions
func (l *adobeExtensionsLegacyMultipurposeCriticality) CheckApplies(c *x509.Certificate) bool {
return util.IsSubscriberCert(c) && (util.IsLegacySMIMECertificate(c) || util.IsMultipurposeSMIMECertificate(c)) && hasAdobeX509Extensions(c)
}

// Execute applies the requirements of adobe x509 extensions not being marked as critical, if present, for multipurpose or legacy SMIME certificates
func (l *adobeExtensionsLegacyMultipurposeCriticality) Execute(c *x509.Certificate) *lint.LintResult {
adobeTimeStampExt := util.GetExtFromCert(c, util.AdobeTimeStampOID)
if adobeTimeStampExt != nil && adobeTimeStampExt.Critical {
return &lint.LintResult{Status: lint.Error}
}

adobeArchRevInfoExt := util.GetExtFromCert(c, util.AdobeArchiveRevInfoOID)
if adobeArchRevInfoExt != nil && adobeArchRevInfoExt.Critical {
return &lint.LintResult{Status: lint.Error}
}

return &lint.LintResult{Status: lint.Pass}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package cabf_smime_br

import (
"testing"

"github.com/zmap/zlint/v3/lint"
"github.com/zmap/zlint/v3/test"
)

func TestAdobeExtensionsLegacyMultipurposeCriticality(t *testing.T) {
testCases := []struct {
Name string
InputFilename string
ExpectedResult lint.LintStatus
}{
{
Name: "pass - mailbox legacy cert with non critical adobe time-stamp extension",
InputFilename: "smime/mailboxValidatedLegacyWithNonCriticalAdobeTimeStampExtension.pem",
ExpectedResult: lint.Pass,
},
{
Name: "pass - organization multipurpose cert with non critical adobe archive rev info extension",
InputFilename: "smime/organizationValidatedMultipurposeWithNonCriticalAdobeArchRevInfoExtension.pem",
ExpectedResult: lint.Pass,
},
{
Name: "NA - non-SMIME BR cert",
InputFilename: "smime/domainValidatedWithEmailCommonName.pem",
ExpectedResult: lint.NA,
},
{
Name: "NA - non-legacy/multipurpose SMIME BR cert",
InputFilename: "smime/organizationValidatedStrictWithAdobeTimeStampExtension.pem",
ExpectedResult: lint.NA,
},
{
Name: "NE - certificate dated before effective date",
InputFilename: "smime/organizationValidatedLegacyWithAdobeTimeStampExtensionMay2023.pem",
ExpectedResult: lint.NE,
},
{
Name: "Error - sponsor multipurpose certificate with adobe time-stamp extension marked as critical",
InputFilename: "smime/sponsorValidatedMultipurposeWithCriticalAdobeTimeStampExtension.pem",
ExpectedResult: lint.Error,
},
{
Name: "Error - legacy certificate with adobe archive rev info extension marked as critical",
InputFilename: "smime/individualValidatedLegacyWithCriticalAdobeArchRevInfoExtension.pem",
ExpectedResult: lint.Error,
},
}
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
result := test.TestLint("e_adobe_extensions_legacy_multipurpose_criticality", tc.InputFilename)
if result.Status != tc.ExpectedResult {
t.Errorf("expected result %v was %v - details: %v", tc.ExpectedResult, result.Status, result.Details)
}
})
}
}
60 changes: 60 additions & 0 deletions v3/lints/cabf_smime_br/lint_adobe_extensions_strict_presence.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* 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 (
"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_adobe_extensions_strict_presence",
Description: "Adobe Time‐stamp X509 extension (1.2.840.113583.1.1.9.1) and the Adobe ArchiveRevInfo extension (1.2.840.113583.1.1.9.2) are prohibited for strict SMIME certificates",
Citation: "7.1.2.3.m",
Source: lint.CABFSMIMEBaselineRequirements,
EffectiveDate: util.CABF_SMIME_BRs_1_0_0_Date,
},
Lint: NewAdobeExtensionsStrictPresence,
})
}

type adobeExtensionsStrictPresence struct{}

// NewAdobeExtensionsStrictPresence creates a new linter to enforce adobe x509 extensions requirements for strict SMIME certs
func NewAdobeExtensionsStrictPresence() lint.CertificateLintInterface {
return &adobeExtensionsStrictPresence{}
}

// CheckApplies returns true if for any subscriber certificate the certificate's policies assert that it conforms to the strict policy requirements defined in the SMIME BRs
func (l *adobeExtensionsStrictPresence) CheckApplies(c *x509.Certificate) bool {
return util.IsSubscriberCert(c) && util.IsStrictSMIMECertificate(c)
}

// Execute applies the requirements of adobe x509 extensions not being allowed for strict SMIME certificates
func (l *adobeExtensionsStrictPresence) Execute(c *x509.Certificate) *lint.LintResult {
if hasAdobeX509Extensions(c) {
return &lint.LintResult{Status: lint.Error}
}

return &lint.LintResult{Status: lint.Pass}
}

func hasAdobeX509Extensions(c *x509.Certificate) bool {
return util.IsExtInCert(c, util.AdobeTimeStampOID) || util.IsExtInCert(c, util.AdobeArchiveRevInfoOID)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* 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 (
"testing"

"github.com/zmap/zlint/v3/lint"
"github.com/zmap/zlint/v3/test"
)

func TestAdobeExtensionsStrictPresence(t *testing.T) {
testCases := []struct {
Name string
InputFilename string
ExpectedResult lint.LintStatus
}{
{
Name: "pass - cert without adobe extensions",
InputFilename: "smime/mailboxValidatedStrictWithoutAdobeExtensions.pem",
ExpectedResult: lint.Pass,
},
{
Name: "NA - non-SMIME BR cert",
InputFilename: "smime/domainValidatedWithEmailCommonName.pem",
ExpectedResult: lint.NA,
},
{
Name: "NA - non-strict SMIME BR cert",
InputFilename: "smime/mailboxValidatedLegacyWithCommonName.pem",
ExpectedResult: lint.NA,
},
{
Name: "NE - certificate dated before effective date",
InputFilename: "smime/mailboxValidatedStrictMay2023.pem",
ExpectedResult: lint.NE,
},
{
Name: "Error - certificate with adobe time-stamp extension",
InputFilename: "smime/organizationValidatedStrictWithAdobeTimeStampExtension.pem",
ExpectedResult: lint.Error,
},
{
Name: "Error - certificate with adobe archive rev info extension",
InputFilename: "smime/sponsorValidatedStrictWithAdobeArchRevInfoExtension.pem",
ExpectedResult: lint.Error,
},
}
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
result := test.TestLint("e_adobe_extensions_strict_presence", tc.InputFilename)
if result.Status != tc.ExpectedResult {
t.Errorf("expected result %v was %v - details: %v", tc.ExpectedResult, result.Status, result.Details)
}
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
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 = johnsmith@example.com
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:20:15:8f:1c:cc:42:e2:21:d2:67:3e:33:3f:dd:
4c:c0:60:06:fc:71:36:4a:8c:aa:32:20:c4:3b:63:
2d:fe:aa:90:35:c6:92:5a:df:b8:ca:8b:c9:93:cf:
7e:1c:df:99:50:ba:7c:23:2a:15:06:80:ac:6b:9f:
14:21:93:8e:e9
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Certificate Policies:
Policy: 2.23.140.1.5.4.1
1.2.840.113583.1.1.9.2: critical
test
Signature Algorithm: ecdsa-with-SHA256
Signature Value:
30:45:02:21:00:82:27:50:f6:c0:c5:36:4c:73:ba:fc:53:71:
db:db:57:fc:80:b4:6d:60:4e:21:e9:6d:e8:01:06:ea:bc:ab:
26:02:20:2c:45:95:97:a5:e3:cc:89:88:cf:70:47:94:94:8e:
6c:df:03:ac:4e:49:00:19:53:a0:f8:11:de:a5:e3:5b:a7
-----BEGIN CERTIFICATE-----
MIIBPzCB5qADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMwOTAxMDAwMDAwWhgP
OTk5ODExMzAwMDAwMDBaMCAxHjAcBgNVBAMMFWpvaG5zbWl0aEBleGFtcGxlLmNv
bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCAVjxzMQuIh0mc+Mz/dTMBgBvxx
NkqMqjIgxDtjLf6qkDXGklrfuMqLyZPPfhzfmVC6fCMqFQaArGufFCGTjumjLzAt
MBQGA1UdIAQNMAswCQYHZ4EMAQUEATAVBgoqhkiG9y8BAQkCAQH/BAR0ZXN0MAoG
CCqGSM49BAMCA0gAMEUCIQCCJ1D2wMU2THO6/FNx29tX/IC0bWBOIelt6AEG6ryr
JgIgLEWVl6XjzImIz3BHlJSObN8DrE5JABlToPgR3qXjW6c=
-----END CERTIFICATE-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
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 = johnsmith@example.com
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:bf:fe:7d:bd:d9:c5:7c:d2:16:d5:5b:d0:ac:a1:
61:25:90:f3:da:2b:a4:5f:ab:6b:a6:72:64:6e:37:
29:3f:be:4d:f0:91:e1:b5:9d:12:b9:24:26:40:4e:
b2:6b:57:d7:d7:f2:94:1e:e3:1b:1b:8f:8b:ed:84:
43:a4:84:13:f0
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Certificate Policies:
Policy: 2.23.140.1.5.1.1
1.2.840.113583.1.1.9.1:
test
Signature Algorithm: ecdsa-with-SHA256
Signature Value:
30:46:02:21:00:a5:ad:3b:a8:8a:d0:0e:3d:d0:79:b0:e0:c1:
cf:20:02:67:9b:dd:5e:b6:7a:2b:a4:d9:c0:f1:c3:9c:b3:96:
bc:02:21:00:9b:c6:ca:a6:7b:16:6f:97:3a:01:9d:c6:c5:dc:
a2:ec:56:dd:2c:e8:a6:e8:9d:f3:a7:99:e7:b3:a7:ac:6a:e5
-----BEGIN CERTIFICATE-----
MIIBPTCB46ADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMwOTAxMDAwMDAwWhgP
OTk5ODExMzAwMDAwMDBaMCAxHjAcBgNVBAMMFWpvaG5zbWl0aEBleGFtcGxlLmNv
bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABL/+fb3ZxXzSFtVb0KyhYSWQ89or
pF+ra6ZyZG43KT++TfCR4bWdErkkJkBOsmtX19fylB7jGxuPi+2EQ6SEE/CjLDAq
MBQGA1UdIAQNMAswCQYHZ4EMAQUBATASBgoqhkiG9y8BAQkBBAR0ZXN0MAoGCCqG
SM49BAMCA0kAMEYCIQClrTuoitAOPdB5sODBzyACZ5vdXrZ6K6TZwPHDnLOWvAIh
AJvGyqZ7Fm+XOgGdxsXcouxW3Szopuid86eZ57OnrGrl
-----END CERTIFICATE-----
39 changes: 39 additions & 0 deletions v3/testdata/smime/mailboxValidatedStrictWithoutAdobeExtensions.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
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 = johnsmith@example.com
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:04:24:34:bb:ef:b9:85:d0:eb:ba:6e:a8:3c:98:
48:45:b1:29:3e:99:42:f5:ce:0f:43:55:11:35:68:
d9:44:ee:5a:25:d9:24:e9:47:b1:bf:e5:12:92:6d:
cc:46:58:46:f7:3e:17:e7:d2:01:a8:ba:09:69:e2:
01:88:0e:d8:33
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Certificate Policies:
Policy: 2.23.140.1.5.1.3
Signature Algorithm: ecdsa-with-SHA256
Signature Value:
30:45:02:20:2b:20:74:33:3e:f4:2d:49:4b:ef:9a:47:1c:f6:
45:59:d0:4d:47:5c:83:5c:f8:5f:34:1a:96:1f:27:1f:fd:d8:
02:21:00:9d:40:17:4a:8d:ee:ad:fd:77:0b:52:cb:fb:99:40:
fb:55:41:13:10:b8:58:be:ea:9b:42:78:21:55:6d:08:67
-----BEGIN CERTIFICATE-----
MIIBKDCBz6ADAgECAgEDMAoGCCqGSM49BAMCMAAwIBcNMjMwOTAxMDAwMDAwWhgP
OTk5ODExMzAwMDAwMDBaMCAxHjAcBgNVBAMMFWpvaG5zbWl0aEBleGFtcGxlLmNv
bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAQkNLvvuYXQ67puqDyYSEWxKT6Z
QvXOD0NVETVo2UTuWiXZJOlHsb/lEpJtzEZYRvc+F+fSAai6CWniAYgO2DOjGDAW
MBQGA1UdIAQNMAswCQYHZ4EMAQUBAzAKBggqhkjOPQQDAgNIADBFAiArIHQzPvQt
SUvvmkcc9kVZ0E1HXINc+F80GpYfJx/92AIhAJ1AF0qN7q39dwtSy/uZQPtVQRMQ
uFi+6ptCeCFVbQhn
-----END CERTIFICATE-----
Loading

0 comments on commit a08efa8

Please sign in to comment.