-
Notifications
You must be signed in to change notification settings - Fork 110
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Lint to check for invalid KU lengths (#686)
* lint for incorrecty KU length * better code comment * correcting linter * fixing lint to check for combinations with nine possible flags * fixing comments * using cryptobyte * accounting for jumbo sized KUs
- Loading branch information
1 parent
1209017
commit 137e46e
Showing
3 changed files
with
311 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package rfc | ||
|
||
/* | ||
* ZLint Copyright 2022 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 ( | ||
"encoding/asn1" | ||
"fmt" | ||
"math/big" | ||
|
||
"golang.org/x/crypto/cryptobyte" | ||
|
||
"github.com/zmap/zcrypto/x509" | ||
"github.com/zmap/zlint/v3/lint" | ||
"github.com/zmap/zlint/v3/util" | ||
) | ||
|
||
type keyUsageIncorrectLength struct{} | ||
|
||
func init() { | ||
lint.RegisterLint(&lint.Lint{ | ||
Name: "e_key_usage_incorrect_length", | ||
Description: "The key usage is a bit string with exactly nine possible flags", | ||
Citation: "RFC 5280: 4.2.1.3", | ||
Source: lint.RFC5280, | ||
EffectiveDate: util.RFC5280Date, | ||
Lint: NewKeyUsageIncorrectLength, | ||
}) | ||
} | ||
|
||
func NewKeyUsageIncorrectLength() lint.LintInterface { | ||
return &keyUsageIncorrectLength{} | ||
} | ||
|
||
func (l *keyUsageIncorrectLength) CheckApplies(c *x509.Certificate) bool { | ||
return util.IsExtInCert(c, util.KeyUsageOID) | ||
} | ||
|
||
func keyUsageIncorrectLengthBytes(kuBytes []byte) *lint.LintResult { | ||
keyUsageExt := cryptobyte.String(kuBytes) | ||
var keyUsageVal asn1.BitString | ||
ok := keyUsageExt.ReadASN1BitString(&keyUsageVal) | ||
if !ok { | ||
return &lint.LintResult{Status: lint.Error, Details: fmt.Sprintf("the key usage (%v) extension is not parseable.", kuBytes)} | ||
} | ||
unused := kuBytes[2] | ||
kuBig := big.NewInt(0).SetBytes(keyUsageVal.Bytes) | ||
if !kuBig.IsInt64() || kuBig.Int64()>>unused >= 512 { | ||
return &lint.LintResult{Status: lint.Error, Details: fmt.Sprintf("the key usage (%v) contains a value that is out of bounds of the range of possible KU values. (raw ASN: %v)", keyUsageVal.Bytes, kuBytes)} | ||
} | ||
return &lint.LintResult{Status: lint.Pass} | ||
} | ||
|
||
func (l *keyUsageIncorrectLength) Execute(c *x509.Certificate) *lint.LintResult { | ||
return keyUsageIncorrectLengthBytes(util.GetExtFromCert(c, util.KeyUsageOID).Value) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
package rfc | ||
|
||
/* | ||
* ZLint Copyright 2022 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" | ||
"math/big" | ||
"testing" | ||
|
||
"github.com/zmap/zlint/v3/lint" | ||
"github.com/zmap/zlint/v3/test" | ||
) | ||
|
||
func TestIncorrectKeyUsageLength(t *testing.T) { | ||
data := []struct { | ||
file string | ||
want lint.LintStatus | ||
}{ | ||
{ | ||
"incorrect_ku_length.pem", lint.Error, | ||
}, | ||
{ | ||
"facebookOnionV3Address.pem", lint.Pass, | ||
}, | ||
} | ||
for _, testData := range data { | ||
data := testData | ||
t.Run(data.file, func(t *testing.T) { | ||
out := test.TestLint("e_key_usage_incorrect_length", data.file) | ||
if out.Status != data.want { | ||
t.Errorf("%s: expected %s, got %s", data.file, data.want, out.Status) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestIncorrectKeyUsageLengthDirectly(t *testing.T) { | ||
type input struct { | ||
input []byte | ||
want lint.LintStatus | ||
} | ||
data := make([]input, 0) | ||
// We have to do zero by hand because big.Int | ||
// will represent 0 as an empty slice rather than 0. | ||
data = append(data, input{ | ||
input: []byte{3, 2, 0, 0}, | ||
want: lint.Pass, | ||
}) | ||
for i := 1; i < 512; i++ { | ||
b := big.NewInt(int64(i)) | ||
bytes := b.Bytes() | ||
// Padding cannot exceed 7 bits, so even though there are | ||
// eight trailing zeroes, we need to declare them as being used. | ||
var unused byte | ||
if i == 256 { | ||
unused = 0 | ||
} else { | ||
unused = byte(b.TrailingZeroBits()) | ||
} | ||
data = append(data, input{ | ||
input: append([]byte{3, byte(1 + len(bytes)), unused}, bytes...), | ||
want: lint.Pass, | ||
}) | ||
} | ||
data = append(data, []input{ | ||
{ | ||
input: []byte{}, | ||
want: lint.Error, | ||
}, | ||
{ | ||
input: []byte{3}, | ||
want: lint.Error, | ||
}, | ||
{ | ||
input: []byte{1, 2, 0, 0}, | ||
want: lint.Error, | ||
}, | ||
{ | ||
input: []byte{3, 3, 7, 0b10000000, 0b10000000}, | ||
want: lint.Pass, | ||
}, | ||
{ | ||
input: []byte{3, 3, 0, 0b00000011, 0b11111111}, | ||
want: lint.Error, | ||
}, | ||
{ | ||
input: []byte{3, 3, 0, 0b00000001, 0b11111111}, | ||
want: lint.Pass, | ||
}, | ||
{ | ||
input: []byte{3, 3, 1, 0b00000011, 0b11111110}, | ||
want: lint.Pass, | ||
}, | ||
{ | ||
input: []byte{3, 3, 8, 0b00000011, 0b00000000}, | ||
want: lint.Error, | ||
}, | ||
}...) | ||
for _, d := range data { | ||
dd := d | ||
t.Run(fmt.Sprintf("%v", dd.input), func(t *testing.T) { | ||
got := keyUsageIncorrectLengthBytes(d.input) | ||
if got.Status != d.want { | ||
t.Errorf("expected %v, got %v (details:'%s')", dd.want, got.Status, got.Details) | ||
t.Error(got.Details) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
Certificate: | ||
Data: | ||
Version: 3 (0x2) | ||
Serial Number: | ||
9a:14:f8:1a:24:9b:14:eb:e4:39:fe:f5:4a:56:5f:92 | ||
Signature Algorithm: sha256WithRSAEncryption | ||
Issuer: C = FR, ST = Paris, L = Paris, O = Gandi, CN = Gandi Standard SSL CA 2 | ||
Validity | ||
Not Before: Jun 7 00:00:00 2019 GMT | ||
Not After : Jun 7 23:59:59 2020 GMT | ||
Subject: OU = Domain Control Validated, OU = Gandi Standard SSL, CN = 8b31df000871489f84bad670bfecc50b.yatu.ws | ||
Subject Public Key Info: | ||
Public Key Algorithm: id-ecPublicKey | ||
Public-Key: (256 bit) | ||
pub: | ||
04:b9:59:ee:ae:d4:5e:5b:e1:4c:87:ff:99:09:b6: | ||
50:79:c6:e0:dc:d4:73:1f:f3:02:a5:7d:1f:65:90: | ||
95:09:8d:91:a5:8d:bb:7d:52:e6:6f:dd:eb:21:19: | ||
37:8a:c5:97:e0:c5:a6:f2:e4:81:8d:ce:7c:c4:9e: | ||
b4:6c:6d:ee:e8 | ||
ASN1 OID: prime256v1 | ||
NIST CURVE: P-256 | ||
X509v3 extensions: | ||
X509v3 Authority Key Identifier: | ||
keyid:B3:90:A7:D8:C9:AF:4E:CD:61:3C:9F:7C:AD:5D:7F:41:FD:69:30:EA | ||
|
||
X509v3 Subject Key Identifier: | ||
37:8B:A1:D9:96:2C:A7:21:24:0C:FC:67:75:FB:69:EE:E0:AA:9B:47 | ||
X509v3 Key Usage: critical | ||
Digital Signature | ||
X509v3 Basic Constraints: critical | ||
CA:FALSE | ||
X509v3 Extended Key Usage: | ||
TLS Web Server Authentication, TLS Web Client Authentication | ||
X509v3 Certificate Policies: | ||
Policy: 1.3.6.1.4.1.6449.1.2.2.26 | ||
CPS: https://cps.usertrust.com | ||
Policy: 2.23.140.1.2.1 | ||
|
||
X509v3 CRL Distribution Points: | ||
|
||
Full Name: | ||
URI:http://crl.usertrust.com/GandiStandardSSLCA2.crl | ||
|
||
Authority Information Access: | ||
CA Issuers - URI:http://crt.usertrust.com/GandiStandardSSLCA2.crt | ||
OCSP - URI:http://ocsp.usertrust.com | ||
|
||
X509v3 Subject Alternative Name: | ||
DNS:8b31df000871489f84bad670bfecc50b.yatu.ws | ||
CT Precertificate SCTs: | ||
Signed Certificate Timestamp: | ||
Version : v1 (0x0) | ||
Log ID : BB:D9:DF:BC:1F:8A:71:B5:93:94:23:97:AA:92:7B:47: | ||
38:57:95:0A:AB:52:E8:1A:90:96:64:36:8E:1E:D1:85 | ||
Timestamp : Jun 7 20:56:56.189 2019 GMT | ||
Extensions: none | ||
Signature : ecdsa-with-SHA256 | ||
30:46:02:21:00:DB:6B:7E:76:4C:68:37:DC:3F:B8:BE: | ||
01:81:99:D7:27:B9:01:01:E1:F4:E3:72:56:59:28:74: | ||
F6:21:F4:13:75:02:21:00:85:15:C8:55:AB:6B:39:B5: | ||
34:0E:9B:8B:A1:D7:67:F0:F4:07:C4:A1:4C:6D:8D:CF: | ||
1B:90:BD:4D:BD:6C:A6:76 | ||
Signed Certificate Timestamp: | ||
Version : v1 (0x0) | ||
Log ID : 5E:A7:73:F9:DF:56:C0:E7:B5:36:48:7D:D0:49:E0:32: | ||
7A:91:9A:0C:84:A1:12:12:84:18:75:96:81:71:45:58 | ||
Timestamp : Jun 7 20:56:56.221 2019 GMT | ||
Extensions: none | ||
Signature : ecdsa-with-SHA256 | ||
30:45:02:20:47:6A:14:45:EB:31:A9:15:FA:03:58:EE: | ||
C7:C4:23:A2:56:23:EE:5F:F4:7F:14:83:AE:48:C5:B8: | ||
18:94:00:33:02:21:00:B7:7B:2B:10:E6:52:5F:DA:2F: | ||
2B:DE:D7:B0:5C:A4:48:91:A6:1C:D8:6B:4B:50:84:2D: | ||
9C:26:5B:63:74:A2:83 | ||
Signature Algorithm: sha256WithRSAEncryption | ||
2e:c5:52:10:21:20:55:88:7b:c3:67:28:32:81:bc:c2:64:24: | ||
56:b8:3e:1c:da:ef:2b:79:8a:57:c0:55:e4:a2:ee:71:51:d4: | ||
2d:60:e2:9e:7e:fc:7f:71:23:ef:dc:90:e3:aa:5e:ce:13:52: | ||
40:43:58:b7:73:3a:49:7e:6e:40:39:1a:c0:ed:88:87:fb:12: | ||
65:43:14:c5:18:98:ab:0a:e1:40:5c:7f:64:76:6b:6a:82:e9: | ||
85:c4:db:c5:70:f1:fd:18:22:c9:49:4c:04:db:6e:68:66:d1: | ||
de:48:eb:31:c6:56:b6:93:95:09:02:8d:2b:ce:9f:de:cc:e2: | ||
bc:40:ce:80:52:81:b4:51:3d:9f:91:c7:ce:bf:99:53:66:3f: | ||
a7:a6:62:87:20:21:31:7b:3b:77:10:b5:72:62:f5:27:98:a3: | ||
37:4d:4b:84:10:3f:5c:dd:44:3f:f2:44:f2:c1:bc:09:7e:d6: | ||
2c:85:79:46:05:22:5b:63:5f:39:74:fe:be:71:f1:94:b1:18: | ||
7a:40:fa:c8:ad:9e:bf:0e:16:99:77:53:9c:37:4e:4f:bf:1f: | ||
88:a4:79:f6:e0:d4:11:92:ba:e0:54:17:21:31:ec:88:99:95: | ||
d2:3b:13:dd:c9:3f:ac:02:f6:5c:93:14:0e:0e:8e:61:90:ff: | ||
63:25:5c:04 | ||
-----BEGIN CERTIFICATE----- | ||
MIIFWzCCBEOgAwIBAgIRAJoU+BokmxTr5Dn+9UpWX5IwDQYJKoZIhvcNAQELBQAw | ||
XzELMAkGA1UEBhMCRlIxDjAMBgNVBAgTBVBhcmlzMQ4wDAYDVQQHEwVQYXJpczEO | ||
MAwGA1UEChMFR2FuZGkxIDAeBgNVBAMTF0dhbmRpIFN0YW5kYXJkIFNTTCBDQSAy | ||
MB4XDTE5MDYwNzAwMDAwMFoXDTIwMDYwNzIzNTk1OVowczEhMB8GA1UECxMYRG9t | ||
YWluIENvbnRyb2wgVmFsaWRhdGVkMRswGQYDVQQLExJHYW5kaSBTdGFuZGFyZCBT | ||
U0wxMTAvBgNVBAMTKDhiMzFkZjAwMDg3MTQ4OWY4NGJhZDY3MGJmZWNjNTBiLnlh | ||
dHUud3MwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS5We6u1F5b4UyH/5kJtlB5 | ||
xuDc1HMf8wKlfR9lkJUJjZGljbt9UuZv3eshGTeKxZfgxaby5IGNznzEnrRsbe7o | ||
o4ICxzCCAsMwHwYDVR0jBBgwFoAUs5Cn2MmvTs1hPJ98rV1/Qf1pMOowHQYDVR0O | ||
BBYEFDeLodmWLKchJAz8Z3X7ae7gqptHMBEGA1UdDwEB/wQHAwUHgAABgDAMBgNV | ||
HRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBLBgNVHSAE | ||
RDBCMDYGCysGAQQBsjEBAgIaMCcwJQYIKwYBBQUHAgEWGWh0dHBzOi8vY3BzLnVz | ||
ZXJ0cnVzdC5jb20wCAYGZ4EMAQIBMEEGA1UdHwQ6MDgwNqA0oDKGMGh0dHA6Ly9j | ||
cmwudXNlcnRydXN0LmNvbS9HYW5kaVN0YW5kYXJkU1NMQ0EyLmNybDBzBggrBgEF | ||
BQcBAQRnMGUwPAYIKwYBBQUHMAKGMGh0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9H | ||
YW5kaVN0YW5kYXJkU1NMQ0EyLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3Au | ||
dXNlcnRydXN0LmNvbTAzBgNVHREELDAqgig4YjMxZGYwMDA4NzE0ODlmODRiYWQ2 | ||
NzBiZmVjYzUwYi55YXR1LndzMIIBBQYKKwYBBAHWeQIEAgSB9gSB8wDxAHcAu9nf | ||
vB+KcbWTlCOXqpJ7RzhXlQqrUugakJZkNo4e0YUAAAFrM7rqfQAABAMASDBGAiEA | ||
22t+dkxoN9w/uL4BgZnXJ7kBAeH043JWWSh09iH0E3UCIQCFFchVq2s5tTQOm4uh | ||
12fw9AfEoUxtjc8bkL1NvWymdgB2AF6nc/nfVsDntTZIfdBJ4DJ6kZoMhKESEoQY | ||
dZaBcUVYAAABazO66p0AAAQDAEcwRQIgR2oUResxqRX6A1jux8QjolYj7l/0fxSD | ||
rkjFuBiUADMCIQC3eysQ5lJf2i8r3tewXKRIkaYc2GtLUIQtnCZbY3SigzANBgkq | ||
hkiG9w0BAQsFAAOCAQEALsVSECEgVYh7w2coMoG8wmQkVrg+HNrvK3mKV8BV5KLu | ||
cVHULWDinn78f3Ej79yQ46pezhNSQENYt3M6SX5uQDkawO2Ih/sSZUMUxRiYqwrh | ||
QFx/ZHZraoLphcTbxXDx/RgiyUlMBNtuaGbR3kjrMcZWtpOVCQKNK86f3szivEDO | ||
gFKBtFE9n5HHzr+ZU2Y/p6ZihyAhMXs7dxC1cmL1J5ijN01LhBA/XN1EP/JE8sG8 | ||
CX7WLIV5RgUiW2NfOXT+vnHxlLEYekD6yK2evw4WmXdTnDdOT78fiKR59uDUEZK6 | ||
4FQXITHsiJmV0jsT3ck/rAL2XJMUDg6OYZD/YyVcBA== | ||
-----END CERTIFICATE----- | ||
|