X509_policy_check returns -1 if some certificate had an unparseable extension, in which case it sets EXFLAG_INVALID_POLICY on it. The calling code then iterates over the certificates to find the offending one, so the callback has a chance to undo it. But it skips i = 0, the leaf, and instead just silentely returns success. We really should cut down on the callback's ability to mess things up here but, in the meantime, fix this. Also add a test covering this case. While I'm here, I've updated make_invalid_extensions.go, which I pulled some code from, to rename fooOrPanic to mustFoo. That seems to be the convention in the Go standard library. (regexp.MustCompile, etc.) Change-Id: Ib07c9f4175e66483bd7c0f7d49aea931bf36e53f Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/55748 Auto-Submit: David Benjamin <davidben@google.com> Reviewed-by: Bob Beck <bbe@google.com> Commit-Queue: David Benjamin <davidben@google.com>fips-20230428
parent
97dd962a20
commit
d1b20a9580
10 changed files with 337 additions and 16 deletions
@ -0,0 +1,174 @@ |
||||
/* Copyright (c) 2020, Google Inc. |
||||
* |
||||
* Permission to use, copy, modify, and/or distribute this software for any |
||||
* purpose with or without fee is hereby granted, provided that the above |
||||
* copyright notice and this permission notice appear in all copies. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ |
||||
|
||||
// make_policy_certs.go generates certificates for testing policy handling.
|
||||
package main |
||||
|
||||
import ( |
||||
"crypto/ecdsa" |
||||
"crypto/rand" |
||||
"crypto/x509" |
||||
"crypto/x509/pkix" |
||||
"encoding/asn1" |
||||
"encoding/pem" |
||||
"math/big" |
||||
"os" |
||||
"time" |
||||
) |
||||
|
||||
var ( |
||||
// https://davidben.net/oid
|
||||
testOID1 = asn1.ObjectIdentifier([]int{1, 2, 840, 113554, 4, 1, 72585, 2, 1}) |
||||
testOID2 = asn1.ObjectIdentifier([]int{1, 2, 840, 113554, 4, 1, 72585, 2, 2}) |
||||
|
||||
// https://www.rfc-editor.org/rfc/rfc5280.html#section-4.2.1.4
|
||||
certificatePoliciesOID = asn1.ObjectIdentifier([]int{2, 5, 29, 32}) |
||||
) |
||||
|
||||
var leafKey, intermediateKey, rootKey *ecdsa.PrivateKey |
||||
|
||||
func init() { |
||||
leafKey = mustParseECDSAKey(leafKeyPEM) |
||||
intermediateKey = mustParseECDSAKey(intermediateKeyPEM) |
||||
rootKey = mustParseECDSAKey(rootKeyPEM) |
||||
} |
||||
|
||||
type templateAndKey struct { |
||||
template x509.Certificate |
||||
key *ecdsa.PrivateKey |
||||
} |
||||
|
||||
func mustGenerateCertificate(path string, subject, issuer *templateAndKey) []byte { |
||||
cert, err := x509.CreateCertificate(rand.Reader, &subject.template, &issuer.template, &subject.key.PublicKey, issuer.key) |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
file, err := os.Create(path) |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
defer file.Close() |
||||
err = pem.Encode(file, &pem.Block{Type: "CERTIFICATE", Bytes: cert}) |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
return cert |
||||
} |
||||
|
||||
func main() { |
||||
notBefore, err := time.Parse(time.RFC3339, "2000-01-01T00:00:00Z") |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
notAfter, err := time.Parse(time.RFC3339, "2100-01-01T00:00:00Z") |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
|
||||
root := templateAndKey{ |
||||
template: x509.Certificate{ |
||||
SerialNumber: new(big.Int).SetInt64(1), |
||||
Subject: pkix.Name{CommonName: "Policy Root"}, |
||||
NotBefore: notBefore, |
||||
NotAfter: notAfter, |
||||
BasicConstraintsValid: true, |
||||
IsCA: true, |
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, |
||||
KeyUsage: x509.KeyUsageCertSign, |
||||
SignatureAlgorithm: x509.ECDSAWithSHA256, |
||||
}, |
||||
key: rootKey, |
||||
} |
||||
intermediate := templateAndKey{ |
||||
template: x509.Certificate{ |
||||
SerialNumber: new(big.Int).SetInt64(2), |
||||
Subject: pkix.Name{CommonName: "Policy Intermediate"}, |
||||
NotBefore: notBefore, |
||||
NotAfter: notAfter, |
||||
BasicConstraintsValid: true, |
||||
IsCA: true, |
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, |
||||
KeyUsage: x509.KeyUsageCertSign, |
||||
SignatureAlgorithm: x509.ECDSAWithSHA256, |
||||
PolicyIdentifiers: []asn1.ObjectIdentifier{testOID1, testOID2}, |
||||
}, |
||||
key: intermediateKey, |
||||
} |
||||
leaf := templateAndKey{ |
||||
template: x509.Certificate{ |
||||
SerialNumber: new(big.Int).SetInt64(3), |
||||
Subject: pkix.Name{CommonName: "www.example.com"}, |
||||
NotBefore: notBefore, |
||||
NotAfter: notAfter, |
||||
BasicConstraintsValid: true, |
||||
IsCA: false, |
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, |
||||
KeyUsage: x509.KeyUsageCertSign, |
||||
SignatureAlgorithm: x509.ECDSAWithSHA256, |
||||
DNSNames: []string{"www.example.com"}, |
||||
PolicyIdentifiers: []asn1.ObjectIdentifier{testOID1, testOID2}, |
||||
}, |
||||
key: leafKey, |
||||
} |
||||
|
||||
// Generate a valid certificate chain from the templates.
|
||||
mustGenerateCertificate("policy_root.pem", &root, &root) |
||||
mustGenerateCertificate("policy_intermediate.pem", &intermediate, &root) |
||||
mustGenerateCertificate("policy_leaf.pem", &leaf, &intermediate) |
||||
|
||||
// Introduce syntax errors in the leaf and intermediate.
|
||||
leafInvalid := leaf |
||||
leafInvalid.template.PolicyIdentifiers = nil |
||||
leafInvalid.template.ExtraExtensions = []pkix.Extension{{Id: certificatePoliciesOID, Value: []byte("INVALID")}} |
||||
mustGenerateCertificate("policy_leaf_invalid.pem", &leafInvalid, &root) |
||||
|
||||
intermediateInvalid := intermediate |
||||
intermediateInvalid.template.PolicyIdentifiers = nil |
||||
intermediateInvalid.template.ExtraExtensions = []pkix.Extension{{Id: certificatePoliciesOID, Value: []byte("INVALID")}} |
||||
mustGenerateCertificate("policy_intermediate_invalid.pem", &intermediateInvalid, &root) |
||||
|
||||
// TODO(davidben): Generate more certificates to test policy validation more
|
||||
// extensively, including an intermediate with constraints. For now this
|
||||
// just tests the basic case.
|
||||
} |
||||
|
||||
const leafKeyPEM = `-----BEGIN PRIVATE KEY----- |
||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgoPUXNXuH9mgiS/nk |
||||
024SYxryxMa3CyGJldiHymLxSquhRANCAASRKti8VW2Rkma+Kt9jQkMNitlCs0l5 |
||||
w8u3SSwm7HZREvmcBCJBjVIREacRqI0umhzR2V5NLzBBP9yPD/A+Ch5X |
||||
-----END PRIVATE KEY-----` |
||||
|
||||
const intermediateKeyPEM = `-----BEGIN PRIVATE KEY----- |
||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgWHKCKgY058ahE3t6 |
||||
vpxVQgzlycgCVMogwjK0y3XMNfWhRANCAATiOnyojN4xS5C8gJ/PHL5cOEsMbsoE |
||||
Y6KT9xRQSh8lEL4d1Vb36kqUgkpqedEImo0Og4Owk6VWVVR/m4Lk+yUw |
||||
-----END PRIVATE KEY-----` |
||||
|
||||
const rootKeyPEM = `-----BEGIN PRIVATE KEY----- |
||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgBwND/eHytW0I417J |
||||
Hr+qcPlp5N1jM3ACXys57bPujg+hRANCAAQmdqXYl1GvY7y3jcTTK6MVXIQr44Tq |
||||
ChRYI6IeV9tIB6jIsOY+Qol1bk8x/7A5FGOnUWFVLEAPEPSJwPndjolt |
||||
-----END PRIVATE KEY-----` |
||||
|
||||
func mustParseECDSAKey(in string) *ecdsa.PrivateKey { |
||||
keyBlock, _ := pem.Decode([]byte(in)) |
||||
if keyBlock == nil || keyBlock.Type != "PRIVATE KEY" { |
||||
panic("could not decode private key") |
||||
} |
||||
key, err := x509.ParsePKCS8PrivateKey(keyBlock.Bytes) |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
return key.(*ecdsa.PrivateKey) |
||||
} |
@ -0,0 +1,11 @@ |
||||
-----BEGIN CERTIFICATE----- |
||||
MIIBrDCCAVGgAwIBAgIBAjAKBggqhkjOPQQDAjAWMRQwEgYDVQQDEwtQb2xpY3kg |
||||
Um9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowHjEcMBoGA1UE |
||||
AxMTUG9saWN5IEludGVybWVkaWF0ZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA |
||||
BOI6fKiM3jFLkLyAn88cvlw4SwxuygRjopP3FFBKHyUQvh3VVvfqSpSCSmp50Qia |
||||
jQ6Dg7CTpVZVVH+bguT7JTCjgYUwgYIwDgYDVR0PAQH/BAQDAgIEMBMGA1UdJQQM |
||||
MAoGCCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJDS9/4O7qhr |
||||
CIRhwsXrPVBagG2uMCsGA1UdIAQkMCIwDwYNKoZIhvcSBAGEtwkCATAPBg0qhkiG |
||||
9xIEAYS3CQICMAoGCCqGSM49BAMCA0kAMEYCIQCcgAbQr/HNdHwPEcWotOqtXXGH |
||||
di6cAJtWaSynP8+UoQIhAPEMK79OO+tJHzmD0N01OdZefAwKlYZvDCQvAfAQVf7j |
||||
-----END CERTIFICATE----- |
@ -0,0 +1,11 @@ |
||||
-----BEGIN CERTIFICATE----- |
||||
MIIBjDCCATKgAwIBAgIBAjAKBggqhkjOPQQDAjAWMRQwEgYDVQQDEwtQb2xpY3kg |
||||
Um9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowHjEcMBoGA1UE |
||||
AxMTUG9saWN5IEludGVybWVkaWF0ZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA |
||||
BOI6fKiM3jFLkLyAn88cvlw4SwxuygRjopP3FFBKHyUQvh3VVvfqSpSCSmp50Qia |
||||
jQ6Dg7CTpVZVVH+bguT7JTCjZzBlMA4GA1UdDwEB/wQEAwICBDATBgNVHSUEDDAK |
||||
BggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSQ0vf+Du6oawiE |
||||
YcLF6z1QWoBtrjAOBgNVHSAEB0lOVkFMSUQwCgYIKoZIzj0EAwIDSAAwRQIgf9Jt |
||||
wpHxfA3j6Z8+h88MSh2MHkDGhWcnRY9VboMR/RoCIQDiSiaPGISK/31JBhNVvNnK |
||||
IBo822QHPPMWDR/K/nyWiA== |
||||
-----END CERTIFICATE----- |
@ -0,0 +1,11 @@ |
||||
-----BEGIN CERTIFICATE----- |
||||
MIIBpjCCAU2gAwIBAgIBAzAKBggqhkjOPQQDAjAeMRwwGgYDVQQDExNQb2xpY3kg |
||||
SW50ZXJtZWRpYXRlMCAXDTAwMDEwMTAwMDAwMFoYDzIxMDAwMTAxMDAwMDAwWjAa |
||||
MRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMB |
||||
BwNCAASRKti8VW2Rkma+Kt9jQkMNitlCs0l5w8u3SSwm7HZREvmcBCJBjVIREacR |
||||
qI0umhzR2V5NLzBBP9yPD/A+Ch5Xo34wfDAOBgNVHQ8BAf8EBAMCAgQwEwYDVR0l |
||||
BAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAaBgNVHREEEzARgg93d3cuZXhh |
||||
bXBsZS5jb20wKwYDVR0gBCQwIjAPBg0qhkiG9xIEAYS3CQIBMA8GDSqGSIb3EgQB |
||||
hLcJAgIwCgYIKoZIzj0EAwIDRwAwRAIgPTm7NO8gR+z8BqA6gV9FVwrSmOAJVzyu |
||||
5loq9ZTtIS0CIEjBbvBcY4+Y3xWL4SUFQKQk3pNZ37xJoz2v+/yvEE5/ |
||||
-----END CERTIFICATE----- |
@ -0,0 +1,11 @@ |
||||
-----BEGIN CERTIFICATE----- |
||||
MIIBgjCCASigAwIBAgIBAzAKBggqhkjOPQQDAjAWMRQwEgYDVQQDEwtQb2xpY3kg |
||||
Um9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowGjEYMBYGA1UE |
||||
AxMPd3d3LmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkSrY |
||||
vFVtkZJmvirfY0JDDYrZQrNJecPLt0ksJux2URL5nAQiQY1SERGnEaiNLpoc0dle |
||||
TS8wQT/cjw/wPgoeV6NhMF8wDgYDVR0PAQH/BAQDAgIEMBMGA1UdJQQMMAoGCCsG |
||||
AQUFBwMBMAwGA1UdEwEB/wQCMAAwGgYDVR0RBBMwEYIPd3d3LmV4YW1wbGUuY29t |
||||
MA4GA1UdIAQHSU5WQUxJRDAKBggqhkjOPQQDAgNIADBFAiBhnGGMJBM2gTBo9r4C |
||||
NDR89ECTU7dwdvFyOGOIOOZEFgIhAIRIhGdQ9eRRi2qMhN1F19P5VsIUuc4VL1bW |
||||
sXO8fwZM |
||||
-----END CERTIFICATE----- |
@ -0,0 +1,10 @@ |
||||
-----BEGIN CERTIFICATE----- |
||||
MIIBdDCCARqgAwIBAgIBATAKBggqhkjOPQQDAjAWMRQwEgYDVQQDEwtQb2xpY3kg |
||||
Um9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowFjEUMBIGA1UE |
||||
AxMLUG9saWN5IFJvb3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQmdqXYl1Gv |
||||
Y7y3jcTTK6MVXIQr44TqChRYI6IeV9tIB6jIsOY+Qol1bk8x/7A5FGOnUWFVLEAP |
||||
EPSJwPndjolto1cwVTAOBgNVHQ8BAf8EBAMCAgQwEwYDVR0lBAwwCgYIKwYBBQUH |
||||
AwEwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU0GnnoB+yeN63WMthnh6Uh1HH |
||||
dRIwCgYIKoZIzj0EAwIDSAAwRQIgctaVgroxlAkLhPEaTXvsE3ePYM2X+KGOJZXc |
||||
usyO3YkCIQDN1RLJq9vHGjZzDCEehKjxHsV+XSAkdfU7nB7KjVHTKA== |
||||
-----END CERTIFICATE----- |
Loading…
Reference in new issue