Skip to content

Commit

Permalink
Lint to check for invalid KU lengths (#686)
Browse files Browse the repository at this point in the history
* 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
christopher-henderson authored Sep 18, 2022
1 parent 1209017 commit 137e46e
Show file tree
Hide file tree
Showing 3 changed files with 311 additions and 0 deletions.
67 changes: 67 additions & 0 deletions v3/lints/rfc/lint_key_usage_incorrect_length.go
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)
}
121 changes: 121 additions & 0 deletions v3/lints/rfc/lint_key_usage_incorrect_length_test.go
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)
}
})
}
}
123 changes: 123 additions & 0 deletions v3/testdata/incorrect_ku_length.pem
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-----

0 comments on commit 137e46e

Please sign in to comment.