Fix handling of EXFLAG_INVALID_POLICY on the leaf.
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>
diff --git a/crypto/x509/test/make_invalid_extensions.go b/crypto/x509/test/make_invalid_extensions.go
index d0c2cee..aba2d71 100644
--- a/crypto/x509/test/make_invalid_extensions.go
+++ b/crypto/x509/test/make_invalid_extensions.go
@@ -49,9 +49,9 @@
var leafKey, intermediateKey, rootKey *ecdsa.PrivateKey
func init() {
- leafKey = ecdsaKeyFromPEMOrPanic(leafKeyPEM)
- intermediateKey = ecdsaKeyFromPEMOrPanic(intermediateKeyPEM)
- rootKey = ecdsaKeyFromPEMOrPanic(rootKeyPEM)
+ leafKey = mustParseECDSAKey(leafKeyPEM)
+ intermediateKey = mustParseECDSAKey(intermediateKeyPEM)
+ rootKey = mustParseECDSAKey(rootKeyPEM)
}
type templateAndKey struct {
@@ -59,7 +59,7 @@
key *ecdsa.PrivateKey
}
-func generateCertificateOrPanic(path string, subject, issuer *templateAndKey) []byte {
+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)
@@ -135,9 +135,9 @@
}
// Generate a valid certificate chain from the templates.
- generateCertificateOrPanic("invalid_extension_root.pem", &root, &root)
- generateCertificateOrPanic("invalid_extension_intermediate.pem", &intermediate, &root)
- leafDER := generateCertificateOrPanic("invalid_extension_leaf.pem", &leaf, &intermediate)
+ mustGenerateCertificate("invalid_extension_root.pem", &root, &root)
+ mustGenerateCertificate("invalid_extension_intermediate.pem", &intermediate, &root)
+ leafDER := mustGenerateCertificate("invalid_extension_leaf.pem", &leaf, &intermediate)
leafCert, err := x509.ParseCertificate(leafDER)
if err != nil {
@@ -151,15 +151,15 @@
rootInvalid := root
rootInvalid.template.ExtraExtensions = invalidExtension
- generateCertificateOrPanic(fmt.Sprintf("invalid_extension_root_%s.pem", ext.name), &rootInvalid, &rootInvalid)
+ mustGenerateCertificate(fmt.Sprintf("invalid_extension_root_%s.pem", ext.name), &rootInvalid, &rootInvalid)
intermediateInvalid := intermediate
intermediateInvalid.template.ExtraExtensions = invalidExtension
- generateCertificateOrPanic(fmt.Sprintf("invalid_extension_intermediate_%s.pem", ext.name), &intermediateInvalid, &root)
+ mustGenerateCertificate(fmt.Sprintf("invalid_extension_intermediate_%s.pem", ext.name), &intermediateInvalid, &root)
leafInvalid := leaf
leafInvalid.template.ExtraExtensions = invalidExtension
- generateCertificateOrPanic(fmt.Sprintf("invalid_extension_leaf_%s.pem", ext.name), &leafInvalid, &intermediate)
+ mustGenerateCertificate(fmt.Sprintf("invalid_extension_leaf_%s.pem", ext.name), &leafInvalid, &intermediate)
// Additionally generate a copy of the leaf certificate with extra data in
// the extension.
@@ -177,7 +177,7 @@
leafTrailingData := leaf
leafTrailingData.template.ExtraExtensions = trailingDataExtension
- generateCertificateOrPanic(fmt.Sprintf("trailing_data_leaf_%s.pem", ext.name), &leafTrailingData, &intermediate)
+ mustGenerateCertificate(fmt.Sprintf("trailing_data_leaf_%s.pem", ext.name), &leafTrailingData, &intermediate)
}
}
@@ -199,7 +199,7 @@
ChRYI6IeV9tIB6jIsOY+Qol1bk8x/7A5FGOnUWFVLEAPEPSJwPndjolt
-----END PRIVATE KEY-----`
-func ecdsaKeyFromPEMOrPanic(in string) *ecdsa.PrivateKey {
+func mustParseECDSAKey(in string) *ecdsa.PrivateKey {
keyBlock, _ := pem.Decode([]byte(in))
if keyBlock == nil || keyBlock.Type != "PRIVATE KEY" {
panic("could not decode private key")
diff --git a/crypto/x509/test/make_policy_certs.go b/crypto/x509/test/make_policy_certs.go
new file mode 100644
index 0000000..18a6ffe
--- /dev/null
+++ b/crypto/x509/test/make_policy_certs.go
@@ -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)
+}
diff --git a/crypto/x509/test/policy_intermediate.pem b/crypto/x509/test/policy_intermediate.pem
new file mode 100644
index 0000000..b36868c
--- /dev/null
+++ b/crypto/x509/test/policy_intermediate.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBrDCCAVGgAwIBAgIBAjAKBggqhkjOPQQDAjAWMRQwEgYDVQQDEwtQb2xpY3kg
+Um9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowHjEcMBoGA1UE
+AxMTUG9saWN5IEludGVybWVkaWF0ZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA
+BOI6fKiM3jFLkLyAn88cvlw4SwxuygRjopP3FFBKHyUQvh3VVvfqSpSCSmp50Qia
+jQ6Dg7CTpVZVVH+bguT7JTCjgYUwgYIwDgYDVR0PAQH/BAQDAgIEMBMGA1UdJQQM
+MAoGCCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJDS9/4O7qhr
+CIRhwsXrPVBagG2uMCsGA1UdIAQkMCIwDwYNKoZIhvcSBAGEtwkCATAPBg0qhkiG
+9xIEAYS3CQICMAoGCCqGSM49BAMCA0kAMEYCIQCcgAbQr/HNdHwPEcWotOqtXXGH
+di6cAJtWaSynP8+UoQIhAPEMK79OO+tJHzmD0N01OdZefAwKlYZvDCQvAfAQVf7j
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/policy_intermediate_invalid.pem b/crypto/x509/test/policy_intermediate_invalid.pem
new file mode 100644
index 0000000..7467317
--- /dev/null
+++ b/crypto/x509/test/policy_intermediate_invalid.pem
@@ -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-----
diff --git a/crypto/x509/test/policy_leaf.pem b/crypto/x509/test/policy_leaf.pem
new file mode 100644
index 0000000..b140704
--- /dev/null
+++ b/crypto/x509/test/policy_leaf.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBpjCCAU2gAwIBAgIBAzAKBggqhkjOPQQDAjAeMRwwGgYDVQQDExNQb2xpY3kg
+SW50ZXJtZWRpYXRlMCAXDTAwMDEwMTAwMDAwMFoYDzIxMDAwMTAxMDAwMDAwWjAa
+MRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMB
+BwNCAASRKti8VW2Rkma+Kt9jQkMNitlCs0l5w8u3SSwm7HZREvmcBCJBjVIREacR
+qI0umhzR2V5NLzBBP9yPD/A+Ch5Xo34wfDAOBgNVHQ8BAf8EBAMCAgQwEwYDVR0l
+BAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAaBgNVHREEEzARgg93d3cuZXhh
+bXBsZS5jb20wKwYDVR0gBCQwIjAPBg0qhkiG9xIEAYS3CQIBMA8GDSqGSIb3EgQB
+hLcJAgIwCgYIKoZIzj0EAwIDRwAwRAIgPTm7NO8gR+z8BqA6gV9FVwrSmOAJVzyu
+5loq9ZTtIS0CIEjBbvBcY4+Y3xWL4SUFQKQk3pNZ37xJoz2v+/yvEE5/
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/policy_leaf_invalid.pem b/crypto/x509/test/policy_leaf_invalid.pem
new file mode 100644
index 0000000..6c0f56f
--- /dev/null
+++ b/crypto/x509/test/policy_leaf_invalid.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBgjCCASigAwIBAgIBAzAKBggqhkjOPQQDAjAWMRQwEgYDVQQDEwtQb2xpY3kg
+Um9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowGjEYMBYGA1UE
+AxMPd3d3LmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkSrY
+vFVtkZJmvirfY0JDDYrZQrNJecPLt0ksJux2URL5nAQiQY1SERGnEaiNLpoc0dle
+TS8wQT/cjw/wPgoeV6NhMF8wDgYDVR0PAQH/BAQDAgIEMBMGA1UdJQQMMAoGCCsG
+AQUFBwMBMAwGA1UdEwEB/wQCMAAwGgYDVR0RBBMwEYIPd3d3LmV4YW1wbGUuY29t
+MA4GA1UdIAQHSU5WQUxJRDAKBggqhkjOPQQDAgNIADBFAiBhnGGMJBM2gTBo9r4C
+NDR89ECTU7dwdvFyOGOIOOZEFgIhAIRIhGdQ9eRRi2qMhN1F19P5VsIUuc4VL1bW
+sXO8fwZM
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/policy_root.pem b/crypto/x509/test/policy_root.pem
new file mode 100644
index 0000000..7bb209a
--- /dev/null
+++ b/crypto/x509/test/policy_root.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBdDCCARqgAwIBAgIBATAKBggqhkjOPQQDAjAWMRQwEgYDVQQDEwtQb2xpY3kg
+Um9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowFjEUMBIGA1UE
+AxMLUG9saWN5IFJvb3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQmdqXYl1Gv
+Y7y3jcTTK6MVXIQr44TqChRYI6IeV9tIB6jIsOY+Qol1bk8x/7A5FGOnUWFVLEAP
+EPSJwPndjolto1cwVTAOBgNVHQ8BAf8EBAMCAgQwEwYDVR0lBAwwCgYIKwYBBQUH
+AwEwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU0GnnoB+yeN63WMthnh6Uh1HH
+dRIwCgYIKoZIzj0EAwIDSAAwRQIgctaVgroxlAkLhPEaTXvsE3ePYM2X+KGOJZXc
+usyO3YkCIQDN1RLJq9vHGjZzDCEehKjxHsV+XSAkdfU7nB7KjVHTKA==
+-----END CERTIFICATE-----
diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc
index e5e1b84..a69b284 100644
--- a/crypto/x509/x509_test.cc
+++ b/crypto/x509/x509_test.cc
@@ -5094,3 +5094,93 @@
ASSERT_TRUE(ASN1_INTEGER_get_int64(&val, X509_get0_serialNumber(root.get())));
EXPECT_EQ(-1, val);
}
+
+TEST(X509Test, Policy) {
+ bssl::UniquePtr<ASN1_OBJECT> oid1(
+ OBJ_txt2obj("1.2.840.113554.4.1.72585.2.1", /*dont_search_names=*/1));
+ ASSERT_TRUE(oid1);
+ bssl::UniquePtr<ASN1_OBJECT> oid2(
+ OBJ_txt2obj("1.2.840.113554.4.1.72585.2.2", /*dont_search_names=*/1));
+ ASSERT_TRUE(oid2);
+ bssl::UniquePtr<ASN1_OBJECT> oid3(
+ OBJ_txt2obj("1.2.840.113554.4.1.72585.2.3", /*dont_search_names=*/1));
+ ASSERT_TRUE(oid3);
+
+ bssl::UniquePtr<X509> root(
+ CertFromPEM(GetTestData("crypto/x509/test/policy_root.pem").c_str()));
+ ASSERT_TRUE(root);
+ bssl::UniquePtr<X509> intermediate(CertFromPEM(
+ GetTestData("crypto/x509/test/policy_intermediate.pem").c_str()));
+ ASSERT_TRUE(intermediate);
+ bssl::UniquePtr<X509> intermediate_invalid(CertFromPEM(
+ GetTestData("crypto/x509/test/policy_intermediate_invalid.pem").c_str()));
+ ASSERT_TRUE(intermediate_invalid);
+ bssl::UniquePtr<X509> leaf(
+ CertFromPEM(GetTestData("crypto/x509/test/policy_leaf.pem").c_str()));
+ ASSERT_TRUE(leaf);
+ bssl::UniquePtr<X509> leaf_invalid(CertFromPEM(
+ GetTestData("crypto/x509/test/policy_leaf_invalid.pem").c_str()));
+ ASSERT_TRUE(leaf_invalid);
+
+ // By default, OpenSSL does not check policies, so even syntax errors in the
+ // certificatePolicies extension go unnoticed. (This is probably not
+ // important.)
+ EXPECT_EQ(X509_V_OK, Verify(leaf.get(), {root.get()},
+ {intermediate.get()}, /*crls=*/{}));
+ EXPECT_EQ(X509_V_OK, Verify(leaf_invalid.get(), {root.get()},
+ {intermediate.get()}, /*crls=*/{}));
+
+ auto set_policies = [](X509_VERIFY_PARAM *param,
+ std::vector<const ASN1_OBJECT *> oids) {
+ for (const ASN1_OBJECT *oid : oids) {
+ bssl::UniquePtr<ASN1_OBJECT> copy(OBJ_dup(oid));
+ ASSERT_TRUE(copy);
+ ASSERT_TRUE(X509_VERIFY_PARAM_add0_policy(param, copy.get()));
+ copy.release(); // |X509_VERIFY_PARAM_add0_policy| takes ownership on
+ // success.
+ }
+ };
+
+ // The chain is good for |oid1| and |oid2|, but not |oid3|.
+ EXPECT_EQ(X509_V_OK,
+ Verify(leaf.get(), {root.get()}, {intermediate.get()}, /*crls=*/{},
+ X509_V_FLAG_EXPLICIT_POLICY, [&](X509_VERIFY_PARAM *param) {
+ set_policies(param, {oid1.get()});
+ }));
+ EXPECT_EQ(X509_V_OK,
+ Verify(leaf.get(), {root.get()}, {intermediate.get()}, /*crls=*/{},
+ X509_V_FLAG_EXPLICIT_POLICY, [&](X509_VERIFY_PARAM *param) {
+ set_policies(param, {oid2.get()});
+ }));
+ EXPECT_EQ(X509_V_ERR_NO_EXPLICIT_POLICY,
+ Verify(leaf.get(), {root.get()}, {intermediate.get()}, /*crls=*/{},
+ X509_V_FLAG_EXPLICIT_POLICY, [&](X509_VERIFY_PARAM *param) {
+ set_policies(param, {oid3.get()});
+ }));
+ EXPECT_EQ(X509_V_OK,
+ Verify(leaf.get(), {root.get()}, {intermediate.get()}, /*crls=*/{},
+ X509_V_FLAG_EXPLICIT_POLICY, [&](X509_VERIFY_PARAM *param) {
+ set_policies(param, {oid1.get(), oid2.get()});
+ }));
+ EXPECT_EQ(X509_V_OK,
+ Verify(leaf.get(), {root.get()}, {intermediate.get()}, /*crls=*/{},
+ X509_V_FLAG_EXPLICIT_POLICY, [&](X509_VERIFY_PARAM *param) {
+ set_policies(param, {oid1.get(), oid3.get()});
+ }));
+
+ // The policy extension in the intermediate cannot be parsed.
+ EXPECT_EQ(X509_V_ERR_INVALID_POLICY_EXTENSION,
+ Verify(leaf.get(), {root.get()}, {intermediate_invalid.get()},
+ /*crls=*/{}, X509_V_FLAG_EXPLICIT_POLICY,
+ [&](X509_VERIFY_PARAM *param) {
+ set_policies(param, {oid1.get()});
+ }));
+
+ // The policy extension in the leaf cannot be parsed.
+ EXPECT_EQ(X509_V_ERR_INVALID_POLICY_EXTENSION,
+ Verify(leaf_invalid.get(), {root.get()}, {intermediate.get()},
+ /*crls=*/{}, X509_V_FLAG_EXPLICIT_POLICY,
+ [&](X509_VERIFY_PARAM *param) {
+ set_policies(param, {oid1.get()});
+ }));
+}
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c
index 7d445f7..ce110e6 100644
--- a/crypto/x509/x509_vfy.c
+++ b/crypto/x509/x509_vfy.c
@@ -1706,10 +1706,8 @@
// Invalid or inconsistent extensions
if (ret == -1) {
// Locate certificates with bad extensions and notify callback.
- X509 *x;
- size_t i;
- for (i = 1; i < sk_X509_num(ctx->chain); i++) {
- x = sk_X509_value(ctx->chain, i);
+ for (size_t i = 0; i < sk_X509_num(ctx->chain); i++) {
+ X509 *x = sk_X509_value(ctx->chain, i);
if (!(x->ex_flags & EXFLAG_INVALID_POLICY)) {
continue;
}
diff --git a/sources.cmake b/sources.cmake
index 294de93..69a1f64 100644
--- a/sources.cmake
+++ b/sources.cmake
@@ -111,6 +111,11 @@
crypto/x509/test/many_names1.pem
crypto/x509/test/many_names2.pem
crypto/x509/test/many_names3.pem
+ crypto/x509/test/policy_root.pem
+ crypto/x509/test/policy_intermediate_invalid.pem
+ crypto/x509/test/policy_intermediate.pem
+ crypto/x509/test/policy_leaf_invalid.pem
+ crypto/x509/test/policy_leaf.pem
crypto/x509/test/pss_sha1_explicit.pem
crypto/x509/test/pss_sha1_mgf1_syntax_error.pem
crypto/x509/test/pss_sha1.pem