Skip to content

Commit

Permalink
Lint for S/MIME BR 7.1.2.3.g (#797)
Browse files Browse the repository at this point in the history
* Lint for S/MIME BR 7.1.2.3.g

* Remove printf

* Addresss rewview comments. Check for presence of AuthkeyOID extension. Use error details.

---------

Co-authored-by: Zakir Durumeric <zakird@gmail.com>
Co-authored-by: Christopher Henderson <chris@chenderson.org>
  • Loading branch information
3 people committed Feb 20, 2024
1 parent a4b46ef commit 060b385
Show file tree
Hide file tree
Showing 4 changed files with 288 additions and 0 deletions.
85 changes: 85 additions & 0 deletions v3/lints/cabf_smime_br/lint_authority_key_identifier.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package cabf_smime_br

/*
* 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.
*/

import (
"fmt"

"github.com/zmap/zcrypto/encoding/asn1"
"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/v3/lint"
"github.com/zmap/zlint/v3/util"
)

type keyIdentifier struct {
KeyIdentifier asn1.RawValue `asn1:"optional,tag:0"`
AuthorityCertIssuer asn1.RawValue `asn1:"optional,tag:1"`
AuthorityCertSerialNumber asn1.RawValue `asn1:"optional,tag:2"`
}

type authorityKeyIdentifierCorrect struct{}

func init() {
lint.RegisterCertificateLint(&lint.CertificateLint{
LintMetadata: lint.LintMetadata{
Name: "e_authority_key_identifier_correct",
Description: "authorityKeyIdentifier SHALL be present. This extension SHALL NOT be marked critical. The keyIdentifier field SHALL be present. authorityCertIssuer and authorityCertSerialNumber fields SHALL NOT be present.",
Citation: "7.1.2.3.g",
Source: lint.CABFSMIMEBaselineRequirements,
EffectiveDate: util.CABF_SMIME_BRs_1_0_0_Date,
},
Lint: NewAuthorityKeyIdentifierCorrect,
})
}

func NewAuthorityKeyIdentifierCorrect() lint.LintInterface {
return &authorityKeyIdentifierCorrect{}
}

func (l *authorityKeyIdentifierCorrect) CheckApplies(c *x509.Certificate) bool {
return util.IsSubscriberCert(c) && util.IsSMIMEBRCertificate(c)
}

func (l *authorityKeyIdentifierCorrect) Execute(c *x509.Certificate) *lint.LintResult {
ext := util.GetExtFromCert(c, util.AuthkeyOID)
if ext == nil {
return &lint.LintResult{Status: lint.Error, Details: "missing authorityKeyIdentifier"}
}
if ext.Critical {
return &lint.LintResult{Status: lint.Error, Details: "authorityKeyIdentifier is critical"}
}

var keyID keyIdentifier
if _, err := asn1.Unmarshal(ext.Value, &keyID); err != nil {
return &lint.LintResult{
Status: lint.Fatal,
Details: fmt.Sprintf("error unmarshalling authority key identifier extension: %v", err),
}
}

hasKeyID := len(keyID.KeyIdentifier.Bytes) > 0
hasCertIssuer := len(keyID.AuthorityCertIssuer.Bytes) > 0
hasCertSerial := len(keyID.AuthorityCertSerialNumber.Bytes) > 0
if !hasKeyID {
return &lint.LintResult{Status: lint.Error, Details: "keyIdentifier not present"}
}
if hasCertIssuer {
return &lint.LintResult{Status: lint.Error, Details: "authorityCertIssuer is present"}
}
if hasCertSerial {
return &lint.LintResult{Status: lint.Error, Details: "authorityCertSerialNumber is present"}
}
return &lint.LintResult{Status: lint.Pass}
}
34 changes: 34 additions & 0 deletions v3/lints/cabf_smime_br/lint_authority_key_identifier_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package cabf_smime_br

import (
"testing"

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

func TestAuthorityKeyInfoCorrect(t *testing.T) {
testCases := []struct {
Name string
InputFilename string
ExpectedResult lint.LintStatus
}{
{
Name: "pass - cert has keyIdentifier",
InputFilename: "smime/authority_key_identifier_valid.pem",
ExpectedResult: lint.Pass,
},
{
Name: "Error - cert has serial and DirName",
InputFilename: "smime/authority_key_identifier_invalid.pem",
ExpectedResult: lint.Error,
}}
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
result := test.TestLint("e_authority_key_identifier_correct", tc.InputFilename)
if result.Status != tc.ExpectedResult {
t.Errorf("expected result %v was %v - details: %v", tc.ExpectedResult, result.Status, result.Details)
}
})
}
}
125 changes: 125 additions & 0 deletions v3/testdata/smime/authority_key_identifier_invalid.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
5f:18:90:8f:43:3e:aa:41:26:31:d1:92:c0:70:a8:1e:b1:71:4f:9f
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = US
Validity
Not Before: Feb 20 20:25:42 2024 GMT
Not After : Feb 19 20:25:42 2025 GMT
Subject: C = US
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (4096 bit)
Modulus:
00:c5:2b:72:8f:9c:31:e6:93:ea:d9:69:fc:6c:91:
66:71:d0:2e:25:c1:6d:14:78:c5:4a:18:f7:07:56:
43:63:d1:f1:42:fa:82:c3:a6:21:a5:37:cd:e7:48:
68:b5:42:3f:88:5c:38:91:1a:38:00:71:2f:a6:0d:
cb:ed:40:e3:78:86:af:04:0b:b4:f9:61:01:ab:be:
b9:2a:47:44:26:b1:ad:18:e0:60:bf:72:c9:d4:53:
8c:73:09:40:8f:a3:48:66:ae:1b:b0:49:0e:8b:0c:
3e:1c:88:1c:61:cb:df:34:b6:c2:f0:41:27:b1:52:
33:32:ce:41:53:e4:ca:43:73:1a:eb:0c:29:3c:2f:
c0:16:90:f2:78:7a:99:01:1b:2c:96:2c:73:a8:bd:
0d:fa:b1:65:c0:14:14:4b:5f:a8:42:17:3e:84:29:
22:99:0b:e9:62:15:6d:c7:b5:45:36:48:a9:4d:b1:
cd:b9:0f:c7:c3:d9:ef:33:ee:a2:d9:2b:c5:aa:12:
51:72:8a:f4:13:64:c7:c1:05:a7:69:34:30:3f:1a:
ac:ee:ed:c5:fe:31:4a:7d:ef:87:f7:56:aa:3b:1d:
ad:58:8e:bf:bc:65:5d:f3:3c:ad:bd:37:be:81:13:
99:f8:4b:d8:d4:f2:bc:56:c1:19:4f:f9:49:78:5e:
8d:02:da:c4:13:26:8f:19:17:bb:f1:ef:fe:bc:6f:
90:06:ea:9d:b8:29:b6:c1:6b:91:7d:e8:00:48:75:
83:26:35:f3:f9:78:f9:0e:f9:96:aa:16:bf:b9:58:
d7:cd:0e:e6:e0:04:a0:40:79:a5:6d:9c:65:f5:82:
97:10:86:de:fe:74:60:ea:1b:35:f5:ca:e4:75:97:
1c:e8:c0:d0:b3:e5:15:b4:ea:fa:c0:17:5a:cf:9d:
71:40:d8:66:87:20:2a:de:c6:ce:8b:0d:40:3c:19:
c1:ac:18:bd:4a:2a:5e:69:28:3e:4e:44:66:0c:ee:
0f:52:fb:06:64:3f:a7:14:14:6f:27:67:26:33:ba:
2f:66:c9:f0:31:8d:c9:21:cf:1a:63:b3:f4:d0:f4:
70:7f:30:68:ea:20:76:76:a2:2f:50:c5:a2:23:ed:
1a:9d:a4:46:c9:35:05:f6:68:1e:ae:d8:39:95:82:
31:56:72:45:4a:73:f4:a5:c4:1f:2c:32:8e:cc:0c:
50:7d:c3:4e:7e:cc:f6:93:3b:15:53:f0:a1:a9:21:
99:ec:25:1d:28:c8:ad:18:cd:e2:17:ab:80:7c:96:
f7:af:fe:e7:aa:8c:20:e3:bc:90:70:a2:cc:21:fd:
8c:32:26:10:2d:2b:41:89:31:5f:49:be:3d:a9:f4:
1d:5c:df
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
58:30:87:CF:96:C6:91:64:3D:C9:28:D0:8E:45:5C:E5:D5:67:D9:B4
X509v3 Authority Key Identifier:
DirName:/C=US
serial:20:AB:CA:DC:2E:98:A1:29:50:AE:53:45:0D:07:8E:EB:F9:A7:DE:E6
X509v3 Extended Key Usage:
E-mail Protection
X509v3 Certificate Policies:
Policy: 2.23.140.1.5.1.3
X509v3 Subject Alternative Name:
email:user@example.com
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
84:da:7f:98:34:49:6b:54:3e:31:88:26:60:ea:dd:76:a3:8c:
4d:a3:ca:de:dc:44:21:35:f5:11:c0:71:c5:b6:02:be:9e:dc:
d1:de:95:08:6b:8f:b1:5c:2d:bc:b6:39:cb:50:38:08:5e:1b:
7a:32:49:46:c4:70:ae:87:ed:53:21:25:8a:81:ff:81:28:08:
63:b5:5a:27:77:77:aa:da:a3:6b:50:b8:ac:4e:76:0e:e4:e4:
7d:d8:eb:91:bc:d5:d1:a4:a1:a3:10:b4:ee:b1:44:b2:aa:59:
ff:ae:11:57:af:8c:1e:ce:a0:3f:67:e8:34:3e:82:db:be:74:
e1:e0:8c:17:8d:1b:eb:cf:f5:1b:6a:4c:da:5a:44:3f:fb:86:
22:50:ff:65:c3:14:0b:eb:b6:73:32:b8:f8:ab:f6:d3:d0:01:
ff:98:fb:26:8b:0c:41:f4:5e:f8:b9:a9:5e:3e:bc:8b:5a:f9:
63:f0:81:7e:3d:77:d1:ce:38:4d:b8:5c:61:89:38:b2:bc:ad:
a2:6b:f6:16:fe:e0:a3:ee:a4:13:68:17:65:3d:54:53:59:3b:
92:86:dc:d0:1d:0f:c7:36:d7:23:73:72:94:fa:4c:bd:2f:4b:
5c:bb:bd:8a:27:0e:50:1f:2a:87:3c:5e:d2:99:87:87:c5:01:
43:3c:a7:a4:c0:79:7f:cf:b3:49:8d:98:2b:46:4f:21:a1:68:
c6:ae:07:19:56:1b:5c:5b:9d:71:73:bb:e9:97:da:1f:96:ca:
d3:bb:87:d6:40:c0:27:f4:58:40:81:61:4e:4c:4a:1c:6a:ec:
3d:d4:0e:e6:42:3e:aa:41:ac:a4:8c:0f:60:25:9c:77:d4:8e:
fc:40:b0:23:39:09:c7:20:40:b0:a7:8b:1a:dd:7b:f1:79:c7:
be:10:42:76:a4:e2:6e:16:8f:46:44:16:e4:9d:c1:2e:6f:e0:
82:2a:6a:a4:3f:ae:6b:26:0d:de:6e:01:04:ab:0c:35:5f:a1:
17:b0:c0:ca:aa:44:85:bd:8d:68:41:77:27:03:4e:fd:4c:fc:
a9:e0:d1:49:b9:da:03:c4:a7:83:29:1e:ad:be:f4:13:9d:d1:
e8:bb:ca:ca:41:d3:9a:da:3c:3b:42:b3:71:69:01:c0:bd:8b:
6b:24:d3:be:21:9c:b7:af:8c:fa:0b:e1:c3:d0:fa:02:9c:cf:
bd:2d:95:76:59:86:80:e5:96:36:a2:82:f8:f0:9c:8c:d6:50:
65:42:58:c2:25:7c:94:52:4a:25:74:a7:7e:57:4c:32:a9:7f:
bb:dc:af:54:a4:07:86:83:a2:0e:7b:e8:0b:1f:ab:5f:12:19:
67:49:27:3e:27:d5:91:ac
-----BEGIN CERTIFICATE-----
MIIFRzCCAy+gAwIBAgIUXxiQj0M+qkEmMdGSwHCoHrFxT58wDQYJKoZIhvcNAQEL
BQAwDTELMAkGA1UEBhMCVVMwHhcNMjQwMjIwMjAyNTQyWhcNMjUwMjE5MjAyNTQy
WjANMQswCQYDVQQGEwJVUzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
AMUrco+cMeaT6tlp/GyRZnHQLiXBbRR4xUoY9wdWQ2PR8UL6gsOmIaU3zedIaLVC
P4hcOJEaOABxL6YNy+1A43iGrwQLtPlhAau+uSpHRCaxrRjgYL9yydRTjHMJQI+j
SGauG7BJDosMPhyIHGHL3zS2wvBBJ7FSMzLOQVPkykNzGusMKTwvwBaQ8nh6mQEb
LJYsc6i9DfqxZcAUFEtfqEIXPoQpIpkL6WIVbce1RTZIqU2xzbkPx8PZ7zPuotkr
xaoSUXKK9BNkx8EFp2k0MD8arO7txf4xSn3vh/dWqjsdrViOv7xlXfM8rb03voET
mfhL2NTyvFbBGU/5SXhejQLaxBMmjxkXu/Hv/rxvkAbqnbgptsFrkX3oAEh1gyY1
8/l4+Q75lqoWv7lY180O5uAEoEB5pW2cZfWClxCG3v50YOobNfXK5HWXHOjA0LPl
FbTq+sAXWs+dcUDYZocgKt7GzosNQDwZwawYvUoqXmkoPk5EZgzuD1L7BmQ/pxQU
bydnJjO6L2bJ8DGNySHPGmOz9ND0cH8waOogdnaiL1DFoiPtGp2kRsk1BfZoHq7Y
OZWCMVZyRUpz9KXEHywyjswMUH3DTn7M9pM7FVPwoakhmewlHSjIrRjN4hergHyW
96/+56qMIOO8kHCizCH9jDImEC0rQYkxX0m+Pan0HVzfAgMBAAGjgZ4wgZswHQYD
VR0OBBYEFFgwh8+WxpFkPcko0I5FXOXVZ9m0MDIGA1UdIwQrMCmhEaQPMA0xCzAJ
BgNVBAYTAlVTghQgq8rcLpihKVCuU0UNB47r+afe5jATBgNVHSUEDDAKBggrBgEF
BQcDBDAUBgNVHSAEDTALMAkGB2eBDAEFAQMwGwYDVR0RBBQwEoEQdXNlckBleGFt
cGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAgEAhNp/mDRJa1Q+MYgmYOrddqOMTaPK
3txEITX1EcBxxbYCvp7c0d6VCGuPsVwtvLY5y1A4CF4bejJJRsRwroftUyElioH/
gSgIY7VaJ3d3qtqja1C4rE52DuTkfdjrkbzV0aShoxC07rFEsqpZ/64RV6+MHs6g
P2foND6C27504eCMF40b68/1G2pM2lpEP/uGIlD/ZcMUC+u2czK4+Kv209AB/5j7
JosMQfRe+LmpXj68i1r5Y/CBfj130c44TbhcYYk4srytomv2Fv7go+6kE2gXZT1U
U1k7kobc0B0PxzbXI3NylPpMvS9LXLu9iicOUB8qhzxe0pmHh8UBQzynpMB5f8+z
SY2YK0ZPIaFoxq4HGVYbXFudcXO76ZfaH5bK07uH1kDAJ/RYQIFhTkxKHGrsPdQO
5kI+qkGspIwPYCWcd9SO/ECwIzkJxyBAsKeLGt178XnHvhBCdqTibhaPRkQW5J3B
Lm/ggipqpD+uayYN3m4BBKsMNV+hF7DAyqpEhb2NaEF3JwNO/Uz8qeDRSbnaA8Sn
gykerb70E53R6LvKykHTmto8O0KzcWkBwL2LayTTviGct6+M+gvhw9D6ApzPvS2V
dlmGgOWWNqKC+PCcjNZQZUJYwiV8lFJKJXSnfldMMql/u9yvVKQHhoOiDnvoCx+r
XxIZZ0knPifVkaw=
-----END CERTIFICATE-----
44 changes: 44 additions & 0 deletions v3/testdata/smime/authority_key_identifier_valid.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
ertificate:
Data:
Version: 3 (0x2)
Serial Number: 3 (0x3)
Signature Algorithm: ecdsa-with-SHA256
Issuer:
Validity
Not Before: Feb 13 22:41:43 2024 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:60:39:4c:31:a8:73:c7:9f:0e:eb:42:8c:ee:dc:
4a:99:ff:f6:16:2b:d9:da:a0:70:56:7c:d8:19:55:
73:8a:c9:1a:1c:5f:63:94:fd:45:6a:bf:7c:8d:63:
05:25:cf:66:28:9e:e0:61:42:6a:15:87:b4:5d:be:
f9:90:14:90:38
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Extended Key Usage:
E-mail Protection
X509v3 Authority Key Identifier:
30:3D:13:3B:33:44:3A:44:33:3A:35:30:3A:41:35:3A:44:36:3A:41:30:3A:41:44:3A:45:45:3A:46:33:3A:34:41:3A:36:30:3A:30:41:3A:36:35:3A:44:33:3A:32:31:3A:44:34:3A:46:38:3A:46:38:3A:44:36:3A:30:46
X509v3 Certificate Policies:
Policy: 2.23.140.1.5.1.3
Signature Algorithm: ecdsa-with-SHA256
Signature Value:
30:46:02:21:00:f1:95:21:f6:11:f5:ec:e1:75:22:72:dc:3a:
af:5a:79:97:64:50:5e:bf:c3:67:93:61:74:cb:a8:29:42:5f:
e7:02:21:00:ae:6b:4e:55:27:64:6e:5f:a9:a5:13:1d:ec:ca:
df:7d:76:ab:6e:ed:ab:6e:a5:87:2d:19:69:7f:59:0e:d1:b4
-----BEGIN CERTIFICATE-----
MIIBazCCARCgAwIBAgIBAzAKBggqhkjOPQQDAjAAMCAXDTI0MDIxMzIyNDE0M1oY
Dzk5OTgxMTMwMDAwMDAwWjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYDlM
Mahzx58O60KM7txKmf/2FivZ2qBwVnzYGVVziskaHF9jlP1Far98jWMFJc9mKJ7g
YUJqFYe0Xb75kBSQOKN5MHcwEwYDVR0lBAwwCgYIKwYBBQUHAwQwSgYDVR0jBEMw
QYA/MD0TOzNEOkQzOjUwOkE1OkQ2OkEwOkFEOkVFOkYzOjRBOjYwOjBBOjY1OkQz
OjIxOkQ0OkY4OkY4OkQ2OjBGMBQGA1UdIAQNMAswCQYHZ4EMAQUBAzAKBggqhkjO
PQQDAgNJADBGAiEA8ZUh9hH17OF1InLcOq9aeZdkUF6/w2eTYXTLqClCX+cCIQCu
a05VJ2RuX6mlEx3syt99dqtu7atupYctGWl/WQ7RtA==
-----END CERTIFICATE-----

0 comments on commit 060b385

Please sign in to comment.