Fix x509v3_cache_extensions error-handling.

This imports https://github.com/openssl/openssl/pull/10756 from upstream
with a number of changes:

- Add tests.

- Rather than blindly return false in cert_self_signed, make that
  function a tri-state return. This gives better error-reporting when the
  leaf certificate has a bad extension and reduces the risk of confusing
  the verifier.

- Give x509v3_cache_extensions a return value rather than expecting
  everyone to check EXFLAG_INVALID. Switch X509_check_purpose calls to
  it when applicable.

- Rather than setting EXFLAG_INVALID on bad CRLs, fail the parse
  altogether. We're already in the d2i callback. (Nothing checks
  EXFLAG_INVALID on CRLs.)

- I've intentionally left the error unchecked in X509_cmp. OpenSSL's
  strategy is to return -2, but that's not a consistent comparison
  and may mess up sorts that depend on transitivity. This retains the
  current behavior where we consider all undigestable certs as equal
  to each other (modulo the opportunistic TBSCertificate double-check
  which should work most of the time). This is terrible, so I've filed
  https://crbug.com/boringssl/355 to track fixes here.

That last fix caught that I misread the spec when I generated
kKnownCriticalCRL and kUnknownCriticalCRL2. This fixes those and uses
the old kKnownCriticalCRL as a test for invalid extensions. (Those CRLs
were assembled by hand, so they don't indicate any software has been
encoding them wrong.)

Update-Note: The X.509 verifier now correctly rejects syntax errors in
important certificate extensions. This may break some malformed
certificates which were incorrectly accepted before.

Bug: 345
Change-Id: Ifb3a98ba62cd296920546bc718fda524bd55c024
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/41745
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/crypto/err/x509.errordata b/crypto/err/x509.errordata
index 6ed8fa3..1426fbf 100644
--- a/crypto/err/x509.errordata
+++ b/crypto/err/x509.errordata
@@ -6,6 +6,7 @@
 X509,105,CERT_ALREADY_IN_HASH_TABLE
 X509,106,CRL_ALREADY_DELTA
 X509,107,CRL_VERIFY_FAILURE
+X509,138,DELTA_CRL_WITHOUT_CRL_NUMBER
 X509,108,IDP_MISMATCH
 X509,109,INVALID_BIT_STRING_BITS_LEFT
 X509,110,INVALID_DIRECTORY
diff --git a/crypto/x509/test/invalid_extension_intermediate.pem b/crypto/x509/test/invalid_extension_intermediate.pem
new file mode 100644
index 0000000..b86865f
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_intermediate.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBdTCCARugAwIBAgIBAjAKBggqhkjOPQQDAjAiMSAwHgYDVQQDExdJbnZhbGlk
+IEV4dGVuc2lvbnMgUm9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAw
+MFowKjEoMCYGA1UEAxMfSW52YWxpZCBFeHRlbnNpb25zIEludGVybWVkaWF0ZTBZ
+MBMGByqGSM49AgEGCCqGSM49AwEHA0IABOI6fKiM3jFLkLyAn88cvlw4SwxuygRj
+opP3FFBKHyUQvh3VVvfqSpSCSmp50QiajQ6Dg7CTpVZVVH+bguT7JTCjODA2MA4G
+A1UdDwEB/wQEAwICBDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTAD
+AQH/MAoGCCqGSM49BAMCA0gAMEUCIDkCS9RrLeO556C9apswg90ZdI2kn3ru31bp
+a4Rqp82BAiEAqJn5GbUzqjVaI5UthWdcu1zmpdTJntbheeNstXa7k+E=
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/invalid_extension_intermediate_authority_key_identifier.pem b/crypto/x509/test/invalid_extension_intermediate_authority_key_identifier.pem
new file mode 100644
index 0000000..595703c
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_intermediate_authority_key_identifier.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBhTCCASugAwIBAgIBAjAKBggqhkjOPQQDAjAiMSAwHgYDVQQDExdJbnZhbGlk
+IEV4dGVuc2lvbnMgUm9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAw
+MFowKjEoMCYGA1UEAxMfSW52YWxpZCBFeHRlbnNpb25zIEludGVybWVkaWF0ZTBZ
+MBMGByqGSM49AgEGCCqGSM49AwEHA0IABOI6fKiM3jFLkLyAn88cvlw4SwxuygRj
+opP3FFBKHyUQvh3VVvfqSpSCSmp50QiajQ6Dg7CTpVZVVH+bguT7JTCjSDBGMA4G
+A1UdDwEB/wQEAwICBDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdIwQHSU5WQUxJRDAKBggqhkjOPQQDAgNIADBFAiEAl5TMKihFw6jD
+ajc1I7R177t3d4HyW7qCB/M3PHu9HDsCIDI0oBBsuXAHX43N1Jx8LO0sMAzujYom
+/NZn/qBanQnZ
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/invalid_extension_intermediate_basic_constraints.pem b/crypto/x509/test/invalid_extension_intermediate_basic_constraints.pem
new file mode 100644
index 0000000..32f09f5
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_intermediate_basic_constraints.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBdTCCARqgAwIBAgIBAjAKBggqhkjOPQQDAjAiMSAwHgYDVQQDExdJbnZhbGlk
+IEV4dGVuc2lvbnMgUm9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAw
+MFowKjEoMCYGA1UEAxMfSW52YWxpZCBFeHRlbnNpb25zIEludGVybWVkaWF0ZTBZ
+MBMGByqGSM49AgEGCCqGSM49AwEHA0IABOI6fKiM3jFLkLyAn88cvlw4SwxuygRj
+opP3FFBKHyUQvh3VVvfqSpSCSmp50QiajQ6Dg7CTpVZVVH+bguT7JTCjNzA1MA4G
+A1UdDwEB/wQEAwICBDATBgNVHSUEDDAKBggrBgEFBQcDATAOBgNVHRMEB0lOVkFM
+SUQwCgYIKoZIzj0EAwIDSQAwRgIhAK/zCwmg3s63Ndeg9piiBbMsUF6ZPcNFltEa
+3cKSMPthAiEAkMq/CmljQigMgXVWOhacYeRLyzZyi2i9hOjrCeKFuno=
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/invalid_extension_intermediate_ext_key_usage.pem b/crypto/x509/test/invalid_extension_intermediate_ext_key_usage.pem
new file mode 100644
index 0000000..20ff382
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_intermediate_ext_key_usage.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBbzCCARagAwIBAgIBAjAKBggqhkjOPQQDAjAiMSAwHgYDVQQDExdJbnZhbGlk
+IEV4dGVuc2lvbnMgUm9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAw
+MFowKjEoMCYGA1UEAxMfSW52YWxpZCBFeHRlbnNpb25zIEludGVybWVkaWF0ZTBZ
+MBMGByqGSM49AgEGCCqGSM49AwEHA0IABOI6fKiM3jFLkLyAn88cvlw4SwxuygRj
+opP3FFBKHyUQvh3VVvfqSpSCSmp50QiajQ6Dg7CTpVZVVH+bguT7JTCjMzAxMA4G
+A1UdDwEB/wQEAwICBDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdJQQHSU5WQUxJRDAK
+BggqhkjOPQQDAgNHADBEAiAGr6/3ad6TX4h/HgD5oFiifT7SsRzYVD1yvfyHEYRI
+qgIgYDbO0XKLN9kSUF8ZBaLPyC1AIbw+m9cQy4/GaJuzxH4=
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/invalid_extension_intermediate_key_usage.pem b/crypto/x509/test/invalid_extension_intermediate_key_usage.pem
new file mode 100644
index 0000000..c31596c
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_intermediate_key_usage.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBdDCCARugAwIBAgIBAjAKBggqhkjOPQQDAjAiMSAwHgYDVQQDExdJbnZhbGlk
+IEV4dGVuc2lvbnMgUm9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAw
+MFowKjEoMCYGA1UEAxMfSW52YWxpZCBFeHRlbnNpb25zIEludGVybWVkaWF0ZTBZ
+MBMGByqGSM49AgEGCCqGSM49AwEHA0IABOI6fKiM3jFLkLyAn88cvlw4SwxuygRj
+opP3FFBKHyUQvh3VVvfqSpSCSmp50QiajQ6Dg7CTpVZVVH+bguT7JTCjODA2MBMG
+A1UdJQQMMAoGCCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PBAdJTlZB
+TElEMAoGCCqGSM49BAMCA0cAMEQCIE1gJ4wr8D0UPRfhQ5sx1WJWEOc+IEtktigk
+giSupcouAiBFa441h0NvODAwsb39sQ/uaUhucb11vwKSZItwViMp/w==
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/invalid_extension_intermediate_name_constraints.pem b/crypto/x509/test/invalid_extension_intermediate_name_constraints.pem
new file mode 100644
index 0000000..82c83a9
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_intermediate_name_constraints.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBhTCCASugAwIBAgIBAjAKBggqhkjOPQQDAjAiMSAwHgYDVQQDExdJbnZhbGlk
+IEV4dGVuc2lvbnMgUm9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAw
+MFowKjEoMCYGA1UEAxMfSW52YWxpZCBFeHRlbnNpb25zIEludGVybWVkaWF0ZTBZ
+MBMGByqGSM49AgEGCCqGSM49AwEHA0IABOI6fKiM3jFLkLyAn88cvlw4SwxuygRj
+opP3FFBKHyUQvh3VVvfqSpSCSmp50QiajQ6Dg7CTpVZVVH+bguT7JTCjSDBGMA4G
+A1UdDwEB/wQEAwICBDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdHgQHSU5WQUxJRDAKBggqhkjOPQQDAgNIADBFAiB7QedoT6bEccGY
+/Pofovdtfdzl/AXCtbJjiu59Yt3UTAIhANdfkR5PShTke3o9diKz6G/cVvL9jkF2
+SKzPRxnRVxNo
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/invalid_extension_intermediate_subject_alt_name.pem b/crypto/x509/test/invalid_extension_intermediate_subject_alt_name.pem
new file mode 100644
index 0000000..6fd9bf6
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_intermediate_subject_alt_name.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBhDCCASugAwIBAgIBAjAKBggqhkjOPQQDAjAiMSAwHgYDVQQDExdJbnZhbGlk
+IEV4dGVuc2lvbnMgUm9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAw
+MFowKjEoMCYGA1UEAxMfSW52YWxpZCBFeHRlbnNpb25zIEludGVybWVkaWF0ZTBZ
+MBMGByqGSM49AgEGCCqGSM49AwEHA0IABOI6fKiM3jFLkLyAn88cvlw4SwxuygRj
+opP3FFBKHyUQvh3VVvfqSpSCSmp50QiajQ6Dg7CTpVZVVH+bguT7JTCjSDBGMA4G
+A1UdDwEB/wQEAwICBDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdEQQHSU5WQUxJRDAKBggqhkjOPQQDAgNHADBEAiA4J8X4tb775IOP
+gBZ8BjlQZXPaRAgO/0d8a5Bgb5j0awIgN1i84TX34Dm8SjArcZLN38mm0zbrvEY0
+wILouqC75wI=
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/invalid_extension_intermediate_subject_key_identifier.pem b/crypto/x509/test/invalid_extension_intermediate_subject_key_identifier.pem
new file mode 100644
index 0000000..a440757
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_intermediate_subject_key_identifier.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBhTCCASugAwIBAgIBAjAKBggqhkjOPQQDAjAiMSAwHgYDVQQDExdJbnZhbGlk
+IEV4dGVuc2lvbnMgUm9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAw
+MFowKjEoMCYGA1UEAxMfSW52YWxpZCBFeHRlbnNpb25zIEludGVybWVkaWF0ZTBZ
+MBMGByqGSM49AgEGCCqGSM49AwEHA0IABOI6fKiM3jFLkLyAn88cvlw4SwxuygRj
+opP3FFBKHyUQvh3VVvfqSpSCSmp50QiajQ6Dg7CTpVZVVH+bguT7JTCjSDBGMA4G
+A1UdDwEB/wQEAwICBDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdDgQHSU5WQUxJRDAKBggqhkjOPQQDAgNIADBFAiBXToga6ILFNSXj
+FiwI/ZaZvJubBHzMcrEXtIv85ybV3wIhAL3DMOezrq+dSjf+RdshlTDKwvTY8QYX
+ehvRzctnYHTd
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/invalid_extension_leaf.pem b/crypto/x509/test/invalid_extension_leaf.pem
new file mode 100644
index 0000000..14bcb5a
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_leaf.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBhzCCASygAwIBAgIBAzAKBggqhkjOPQQDAjAqMSgwJgYDVQQDEx9JbnZhbGlk
+IEV4dGVuc2lvbnMgSW50ZXJtZWRpYXRlMCAXDTAwMDEwMTAwMDAwMFoYDzIxMDAw
+MTAxMDAwMDAwWjAaMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wWTATBgcqhkjO
+PQIBBggqhkjOPQMBBwNCAASRKti8VW2Rkma+Kt9jQkMNitlCs0l5w8u3SSwm7HZR
+EvmcBCJBjVIREacRqI0umhzR2V5NLzBBP9yPD/A+Ch5Xo1EwTzAOBgNVHQ8BAf8E
+BAMCAgQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAaBgNVHREE
+EzARgg93d3cuZXhhbXBsZS5jb20wCgYIKoZIzj0EAwIDSQAwRgIhAJ1DkyH6QYsM
+bxN/aXhKYGFc1upPpxfHrzmVrVrYq34GAiEAgzAn1bws7mwi4fTBJ4XY44OisCi6
+gPDLe2H4Esop38o=
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/invalid_extension_leaf_authority_key_identifier.pem b/crypto/x509/test/invalid_extension_leaf_authority_key_identifier.pem
new file mode 100644
index 0000000..166b89c
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_leaf_authority_key_identifier.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBljCCATygAwIBAgIBAzAKBggqhkjOPQQDAjAqMSgwJgYDVQQDEx9JbnZhbGlk
+IEV4dGVuc2lvbnMgSW50ZXJtZWRpYXRlMCAXDTAwMDEwMTAwMDAwMFoYDzIxMDAw
+MTAxMDAwMDAwWjAaMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wWTATBgcqhkjO
+PQIBBggqhkjOPQMBBwNCAASRKti8VW2Rkma+Kt9jQkMNitlCs0l5w8u3SSwm7HZR
+EvmcBCJBjVIREacRqI0umhzR2V5NLzBBP9yPD/A+Ch5Xo2EwXzAOBgNVHQ8BAf8E
+BAMCAgQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAaBgNVHREE
+EzARgg93d3cuZXhhbXBsZS5jb20wDgYDVR0jBAdJTlZBTElEMAoGCCqGSM49BAMC
+A0gAMEUCIDCqsRJC3IrUHxm5txOfnjrpGmoeSvr1EhVFDhHCuV6GAiEAwJ15sf7y
++CGw0rzYTLUHw4nc5aJC9oKOhypg3SrQeGw=
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/invalid_extension_leaf_basic_constraints.pem b/crypto/x509/test/invalid_extension_leaf_basic_constraints.pem
new file mode 100644
index 0000000..611f7cb
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_leaf_basic_constraints.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBiDCCAS6gAwIBAgIBAzAKBggqhkjOPQQDAjAqMSgwJgYDVQQDEx9JbnZhbGlk
+IEV4dGVuc2lvbnMgSW50ZXJtZWRpYXRlMCAXDTAwMDEwMTAwMDAwMFoYDzIxMDAw
+MTAxMDAwMDAwWjAaMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wWTATBgcqhkjO
+PQIBBggqhkjOPQMBBwNCAASRKti8VW2Rkma+Kt9jQkMNitlCs0l5w8u3SSwm7HZR
+EvmcBCJBjVIREacRqI0umhzR2V5NLzBBP9yPD/A+Ch5Xo1MwUTAOBgNVHQ8BAf8E
+BAMCAgQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwGgYDVR0RBBMwEYIPd3d3LmV4YW1w
+bGUuY29tMA4GA1UdEwQHSU5WQUxJRDAKBggqhkjOPQQDAgNIADBFAiEA6btgd6HI
+SCvxfnaHqhAiBjLl665JJC/wpSejPlxFmI0CIGZ7pLkRuQKv132ffDBmobAsBBnT
+YXmJWAHc4rsJCYEx
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/invalid_extension_leaf_ext_key_usage.pem b/crypto/x509/test/invalid_extension_leaf_ext_key_usage.pem
new file mode 100644
index 0000000..2fa34ee
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_leaf_ext_key_usage.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBgTCCASegAwIBAgIBAzAKBggqhkjOPQQDAjAqMSgwJgYDVQQDEx9JbnZhbGlk
+IEV4dGVuc2lvbnMgSW50ZXJtZWRpYXRlMCAXDTAwMDEwMTAwMDAwMFoYDzIxMDAw
+MTAxMDAwMDAwWjAaMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wWTATBgcqhkjO
+PQIBBggqhkjOPQMBBwNCAASRKti8VW2Rkma+Kt9jQkMNitlCs0l5w8u3SSwm7HZR
+EvmcBCJBjVIREacRqI0umhzR2V5NLzBBP9yPD/A+Ch5Xo0wwSjAOBgNVHQ8BAf8E
+BAMCAgQwDAYDVR0TAQH/BAIwADAaBgNVHREEEzARgg93d3cuZXhhbXBsZS5jb20w
+DgYDVR0lBAdJTlZBTElEMAoGCCqGSM49BAMCA0gAMEUCIH3jx0mZhPAY2QZHYVPQ
+ld6RNFGris9CFCD8AMOaZTR+AiEAgr4hSxoIm3g/CVeQkDORqgSrXU0AuVvQL2KO
+NM5UG1Q=
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/invalid_extension_leaf_key_usage.pem b/crypto/x509/test/invalid_extension_leaf_key_usage.pem
new file mode 100644
index 0000000..82c7cf0
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_leaf_key_usage.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBhjCCASygAwIBAgIBAzAKBggqhkjOPQQDAjAqMSgwJgYDVQQDEx9JbnZhbGlk
+IEV4dGVuc2lvbnMgSW50ZXJtZWRpYXRlMCAXDTAwMDEwMTAwMDAwMFoYDzIxMDAw
+MTAxMDAwMDAwWjAaMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wWTATBgcqhkjO
+PQIBBggqhkjOPQMBBwNCAASRKti8VW2Rkma+Kt9jQkMNitlCs0l5w8u3SSwm7HZR
+EvmcBCJBjVIREacRqI0umhzR2V5NLzBBP9yPD/A+Ch5Xo1EwTzATBgNVHSUEDDAK
+BggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBoGA1UdEQQTMBGCD3d3dy5leGFtcGxl
+LmNvbTAOBgNVHQ8EB0lOVkFMSUQwCgYIKoZIzj0EAwIDSAAwRQIgPoSLUcWwjnDx
+3N+DJPzpgHRRSZtJz6w5njQ+zcyQvrQCIQDThWHI9F5s6xQN42stFw0sasdWFc/9
+No9QQf1zbGfGDw==
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/invalid_extension_leaf_name_constraints.pem b/crypto/x509/test/invalid_extension_leaf_name_constraints.pem
new file mode 100644
index 0000000..f4e6105
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_leaf_name_constraints.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBljCCATygAwIBAgIBAzAKBggqhkjOPQQDAjAqMSgwJgYDVQQDEx9JbnZhbGlk
+IEV4dGVuc2lvbnMgSW50ZXJtZWRpYXRlMCAXDTAwMDEwMTAwMDAwMFoYDzIxMDAw
+MTAxMDAwMDAwWjAaMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wWTATBgcqhkjO
+PQIBBggqhkjOPQMBBwNCAASRKti8VW2Rkma+Kt9jQkMNitlCs0l5w8u3SSwm7HZR
+EvmcBCJBjVIREacRqI0umhzR2V5NLzBBP9yPD/A+Ch5Xo2EwXzAOBgNVHQ8BAf8E
+BAMCAgQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAaBgNVHREE
+EzARgg93d3cuZXhhbXBsZS5jb20wDgYDVR0eBAdJTlZBTElEMAoGCCqGSM49BAMC
+A0gAMEUCIQCYofdTDXH2HIpc/ZSI6IQVCM0L0/QbKbEOGeAwDtikGAIgV48ECoAt
+8maDdh8y9qj/TZe6XA39BzkjtsLKhecCuV8=
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/invalid_extension_leaf_subject_alt_name.pem b/crypto/x509/test/invalid_extension_leaf_subject_alt_name.pem
new file mode 100644
index 0000000..eae65f4
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_leaf_subject_alt_name.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBeTCCASCgAwIBAgIBAzAKBggqhkjOPQQDAjAqMSgwJgYDVQQDEx9JbnZhbGlk
+IEV4dGVuc2lvbnMgSW50ZXJtZWRpYXRlMCAXDTAwMDEwMTAwMDAwMFoYDzIxMDAw
+MTAxMDAwMDAwWjAaMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wWTATBgcqhkjO
+PQIBBggqhkjOPQMBBwNCAASRKti8VW2Rkma+Kt9jQkMNitlCs0l5w8u3SSwm7HZR
+EvmcBCJBjVIREacRqI0umhzR2V5NLzBBP9yPD/A+Ch5Xo0UwQzAOBgNVHQ8BAf8E
+BAMCAgQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAOBgNVHREE
+B0lOVkFMSUQwCgYIKoZIzj0EAwIDRwAwRAIgDatlhmjkW4lgYc/eyrqJp1kxKrL8
+0WkPsmdUZmXiI1QCIC1bl+3ponxSaCvn81xKrQzuIq2OzWxy2PTHyNbPnGcz
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/invalid_extension_leaf_subject_key_identifier.pem b/crypto/x509/test/invalid_extension_leaf_subject_key_identifier.pem
new file mode 100644
index 0000000..d082bf8
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_leaf_subject_key_identifier.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBlzCCATygAwIBAgIBAzAKBggqhkjOPQQDAjAqMSgwJgYDVQQDEx9JbnZhbGlk
+IEV4dGVuc2lvbnMgSW50ZXJtZWRpYXRlMCAXDTAwMDEwMTAwMDAwMFoYDzIxMDAw
+MTAxMDAwMDAwWjAaMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wWTATBgcqhkjO
+PQIBBggqhkjOPQMBBwNCAASRKti8VW2Rkma+Kt9jQkMNitlCs0l5w8u3SSwm7HZR
+EvmcBCJBjVIREacRqI0umhzR2V5NLzBBP9yPD/A+Ch5Xo2EwXzAOBgNVHQ8BAf8E
+BAMCAgQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAaBgNVHREE
+EzARgg93d3cuZXhhbXBsZS5jb20wDgYDVR0OBAdJTlZBTElEMAoGCCqGSM49BAMC
+A0kAMEYCIQDNfoYMjJUzrw2qxHKwopCt9lTQIfOCJDzndJwHLSI97gIhAIDRRWkU
+OpOxpzO5zJtvsPSuFJTPtFi6dKwyZA0VVX5m
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/invalid_extension_root.pem b/crypto/x509/test/invalid_extension_root.pem
new file mode 100644
index 0000000..9236111
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_root.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBbjCCAROgAwIBAgIBATAKBggqhkjOPQQDAjAiMSAwHgYDVQQDExdJbnZhbGlk
+IEV4dGVuc2lvbnMgUm9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAw
+MFowIjEgMB4GA1UEAxMXSW52YWxpZCBFeHRlbnNpb25zIFJvb3QwWTATBgcqhkjO
+PQIBBggqhkjOPQMBBwNCAAQmdqXYl1GvY7y3jcTTK6MVXIQr44TqChRYI6IeV9tI
+B6jIsOY+Qol1bk8x/7A5FGOnUWFVLEAPEPSJwPndjoltozgwNjAOBgNVHQ8BAf8E
+BAMCAgQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUwAwEB/zAKBggq
+hkjOPQQDAgNJADBGAiEAkLonK/c0Wai8LSe6Nhf3ln+dpPxIQD9z0e2bXzgp3ZgC
+IQDUjv8fhl6szNN6cV4NElVrsuFRigAvt6Z5M132Ybgavw==
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/invalid_extension_root_authority_key_identifier.pem b/crypto/x509/test/invalid_extension_root_authority_key_identifier.pem
new file mode 100644
index 0000000..c2321b7
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_root_authority_key_identifier.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBfTCCASOgAwIBAgIBATAKBggqhkjOPQQDAjAiMSAwHgYDVQQDExdJbnZhbGlk
+IEV4dGVuc2lvbnMgUm9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAw
+MFowIjEgMB4GA1UEAxMXSW52YWxpZCBFeHRlbnNpb25zIFJvb3QwWTATBgcqhkjO
+PQIBBggqhkjOPQMBBwNCAAQmdqXYl1GvY7y3jcTTK6MVXIQr44TqChRYI6IeV9tI
+B6jIsOY+Qol1bk8x/7A5FGOnUWFVLEAPEPSJwPndjolto0gwRjAOBgNVHQ8BAf8E
+BAMCAgQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
+HSMEB0lOVkFMSUQwCgYIKoZIzj0EAwIDSAAwRQIgO/L4Oi8esLDZ5HQgVYd/GUey
+8yPPRUkfr8+ZH5YJ724CIQCToZDd4kEPRmwjS6R20n5qrDElE4SDBq8cmJEToh57
+3Q==
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/invalid_extension_root_basic_constraints.pem b/crypto/x509/test/invalid_extension_root_basic_constraints.pem
new file mode 100644
index 0000000..4e507b3
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_root_basic_constraints.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBazCCARKgAwIBAgIBATAKBggqhkjOPQQDAjAiMSAwHgYDVQQDExdJbnZhbGlk
+IEV4dGVuc2lvbnMgUm9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAw
+MFowIjEgMB4GA1UEAxMXSW52YWxpZCBFeHRlbnNpb25zIFJvb3QwWTATBgcqhkjO
+PQIBBggqhkjOPQMBBwNCAAQmdqXYl1GvY7y3jcTTK6MVXIQr44TqChRYI6IeV9tI
+B6jIsOY+Qol1bk8x/7A5FGOnUWFVLEAPEPSJwPndjoltozcwNTAOBgNVHQ8BAf8E
+BAMCAgQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDgYDVR0TBAdJTlZBTElEMAoGCCqG
+SM49BAMCA0cAMEQCICRNoNJx8TOSe4FKoB7EdfvG56/zvzVK8F4SDV35nbfTAiAF
+QjSD7CDdbaRQymgX3ojBbAP3hj1fFbCzopKR7UUvxQ==
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/invalid_extension_root_ext_key_usage.pem b/crypto/x509/test/invalid_extension_root_ext_key_usage.pem
new file mode 100644
index 0000000..17ac3a2
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_root_ext_key_usage.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBaDCCAQ6gAwIBAgIBATAKBggqhkjOPQQDAjAiMSAwHgYDVQQDExdJbnZhbGlk
+IEV4dGVuc2lvbnMgUm9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAw
+MFowIjEgMB4GA1UEAxMXSW52YWxpZCBFeHRlbnNpb25zIFJvb3QwWTATBgcqhkjO
+PQIBBggqhkjOPQMBBwNCAAQmdqXYl1GvY7y3jcTTK6MVXIQr44TqChRYI6IeV9tI
+B6jIsOY+Qol1bk8x/7A5FGOnUWFVLEAPEPSJwPndjoltozMwMTAOBgNVHQ8BAf8E
+BAMCAgQwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHSUEB0lOVkFMSUQwCgYIKoZIzj0E
+AwIDSAAwRQIgVjuDRpd+kVlqUDJcX899ZsAoIvkSPxo/lCVJ+ae28BkCIQD/9Aig
+0CaivgJ8Z6mUW9ozp6ClMPfSpCEUtrhm/dg2og==
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/invalid_extension_root_key_usage.pem b/crypto/x509/test/invalid_extension_root_key_usage.pem
new file mode 100644
index 0000000..92ac0c6
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_root_key_usage.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBbjCCAROgAwIBAgIBATAKBggqhkjOPQQDAjAiMSAwHgYDVQQDExdJbnZhbGlk
+IEV4dGVuc2lvbnMgUm9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAw
+MFowIjEgMB4GA1UEAxMXSW52YWxpZCBFeHRlbnNpb25zIFJvb3QwWTATBgcqhkjO
+PQIBBggqhkjOPQMBBwNCAAQmdqXYl1GvY7y3jcTTK6MVXIQr44TqChRYI6IeV9tI
+B6jIsOY+Qol1bk8x/7A5FGOnUWFVLEAPEPSJwPndjoltozgwNjATBgNVHSUEDDAK
+BggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwQHSU5WQUxJRDAKBggq
+hkjOPQQDAgNJADBGAiEAmX21h0WJPZ8VjGRaGwYWAh2q7iS0Wzm+besT06qgnPwC
+IQCEF2G9d/DaDL7H9aw51xA0B+WwHBN5r1kx6b9A5pJVtg==
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/invalid_extension_root_name_constraints.pem b/crypto/x509/test/invalid_extension_root_name_constraints.pem
new file mode 100644
index 0000000..3511236
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_root_name_constraints.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBfTCCASOgAwIBAgIBATAKBggqhkjOPQQDAjAiMSAwHgYDVQQDExdJbnZhbGlk
+IEV4dGVuc2lvbnMgUm9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAw
+MFowIjEgMB4GA1UEAxMXSW52YWxpZCBFeHRlbnNpb25zIFJvb3QwWTATBgcqhkjO
+PQIBBggqhkjOPQMBBwNCAAQmdqXYl1GvY7y3jcTTK6MVXIQr44TqChRYI6IeV9tI
+B6jIsOY+Qol1bk8x/7A5FGOnUWFVLEAPEPSJwPndjolto0gwRjAOBgNVHQ8BAf8E
+BAMCAgQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
+HR4EB0lOVkFMSUQwCgYIKoZIzj0EAwIDSAAwRQIhALYRk6SPzWoKF3wLI6N+bWh/
+iap7zpRrAZqmL3EDTlitAiB0CFMk9r5h/RDkvrP4Z+JZKum9ZVbGew73cdjDVBA3
+dA==
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/invalid_extension_root_subject_alt_name.pem b/crypto/x509/test/invalid_extension_root_subject_alt_name.pem
new file mode 100644
index 0000000..0604bf6
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_root_subject_alt_name.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBfDCCASOgAwIBAgIBATAKBggqhkjOPQQDAjAiMSAwHgYDVQQDExdJbnZhbGlk
+IEV4dGVuc2lvbnMgUm9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAw
+MFowIjEgMB4GA1UEAxMXSW52YWxpZCBFeHRlbnNpb25zIFJvb3QwWTATBgcqhkjO
+PQIBBggqhkjOPQMBBwNCAAQmdqXYl1GvY7y3jcTTK6MVXIQr44TqChRYI6IeV9tI
+B6jIsOY+Qol1bk8x/7A5FGOnUWFVLEAPEPSJwPndjolto0gwRjAOBgNVHQ8BAf8E
+BAMCAgQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
+HREEB0lOVkFMSUQwCgYIKoZIzj0EAwIDRwAwRAIgZKRMQGAIoUuzwYQS8UNkuTI5
+H9kJYpOGZhZ3esyfvC4CIAsJGY8kgzzFpLwd3e9Zp6WAPK/snDzF9Tb4KL+GB85n
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/invalid_extension_root_subject_key_identifier.pem b/crypto/x509/test/invalid_extension_root_subject_key_identifier.pem
new file mode 100644
index 0000000..eb17a7e
--- /dev/null
+++ b/crypto/x509/test/invalid_extension_root_subject_key_identifier.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBfjCCASOgAwIBAgIBATAKBggqhkjOPQQDAjAiMSAwHgYDVQQDExdJbnZhbGlk
+IEV4dGVuc2lvbnMgUm9vdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAw
+MFowIjEgMB4GA1UEAxMXSW52YWxpZCBFeHRlbnNpb25zIFJvb3QwWTATBgcqhkjO
+PQIBBggqhkjOPQMBBwNCAAQmdqXYl1GvY7y3jcTTK6MVXIQr44TqChRYI6IeV9tI
+B6jIsOY+Qol1bk8x/7A5FGOnUWFVLEAPEPSJwPndjolto0gwRjAOBgNVHQ8BAf8E
+BAMCAgQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
+HQ4EB0lOVkFMSUQwCgYIKoZIzj0EAwIDSQAwRgIhAJbUNO8zfK439VpI2rrG9gTl
+fjunP2fKsz3EK8NUtS12AiEA1m9Uzb+sUTCGhAlGEsDkjFbp3SCbvbWn7YhzqJkR
+xvQ=
+-----END CERTIFICATE-----
diff --git a/crypto/x509/test/make_invalid_extensions.go b/crypto/x509/test/make_invalid_extensions.go
new file mode 100644
index 0000000..3d20942
--- /dev/null
+++ b/crypto/x509/test/make_invalid_extensions.go
@@ -0,0 +1,184 @@
+/* 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_invalid_extensions.go generates a number of certificate chains with
+// invalid extension encodings.
+package main
+
+import (
+	"crypto/ecdsa"
+	"crypto/rand"
+	"crypto/x509"
+	"crypto/x509/pkix"
+	"encoding/pem"
+	"fmt"
+	"math/big"
+	"os"
+	"time"
+)
+
+type extension struct {
+	// The name of the extension, in a form suitable for including in a
+	// filename.
+	name string
+	// The extension's OID.
+	oid []int
+}
+
+var extensions = []extension{
+	{name: "authority_key_identifier", oid: []int{2, 5, 29, 35}},
+	{name: "basic_constraints", oid: []int{2, 5, 29, 19}},
+	{name: "ext_key_usage", oid: []int{2, 5, 29, 37}},
+	{name: "key_usage", oid: []int{2, 5, 29, 15}},
+	{name: "name_constraints", oid: []int{2, 5, 29, 30}},
+	{name: "subject_alt_name", oid: []int{2, 5, 29, 17}},
+	{name: "subject_key_identifier", oid: []int{2, 5, 29, 14}},
+}
+
+var leafKey, intermediateKey, rootKey *ecdsa.PrivateKey
+
+func init() {
+	leafKey = ecdsaKeyFromPEMOrPanic(leafKeyPEM)
+	intermediateKey = ecdsaKeyFromPEMOrPanic(intermediateKeyPEM)
+	rootKey = ecdsaKeyFromPEMOrPanic(rootKeyPEM)
+}
+
+type templateAndKey struct {
+	template x509.Certificate
+	key      *ecdsa.PrivateKey
+}
+
+func generateCertificateOrPanic(path string, subject, issuer *templateAndKey) {
+	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)
+	}
+}
+
+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: "Invalid Extensions 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: "Invalid Extensions Intermediate"},
+			NotBefore:             notBefore,
+			NotAfter:              notAfter,
+			BasicConstraintsValid: true,
+			IsCA:                  true,
+			ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+			KeyUsage:              x509.KeyUsageCertSign,
+			SignatureAlgorithm:    x509.ECDSAWithSHA256,
+		},
+		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"},
+		},
+		key: leafKey,
+	}
+
+	// Generate a valid certificate chain from the templates.
+	generateCertificateOrPanic("invalid_extension_root.pem", &root, &root)
+	generateCertificateOrPanic("invalid_extension_intermediate.pem", &intermediate, &root)
+	generateCertificateOrPanic("invalid_extension_leaf.pem", &leaf, &intermediate)
+
+	// Make copies of each of the three certificates with invalid extensions.
+	// These copies may be substituted into the valid chain.
+	for _, ext := range extensions {
+		invalidExtension := []pkix.Extension{{Id: ext.oid, Value: []byte("INVALID")}}
+
+		rootInvalid := root
+		rootInvalid.template.ExtraExtensions = invalidExtension
+		generateCertificateOrPanic(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)
+
+		leafInvalid := leaf
+		leafInvalid.template.ExtraExtensions = invalidExtension
+		generateCertificateOrPanic(fmt.Sprintf("invalid_extension_leaf_%s.pem", ext.name), &leafInvalid, &intermediate)
+	}
+}
+
+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 ecdsaKeyFromPEMOrPanic(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/x509_cmp.c b/crypto/x509/x509_cmp.c
index 28f2e95..cd025ab 100644
--- a/crypto/x509/x509_cmp.c
+++ b/crypto/x509/x509_cmp.c
@@ -67,6 +67,7 @@
 #include <openssl/x509v3.h>
 
 #include "../internal.h"
+#include "../x509v3/internal.h"
 
 
 int X509_issuer_and_serial_cmp(const X509 *a, const X509 *b)
@@ -175,12 +176,18 @@
  */
 int X509_cmp(const X509 *a, const X509 *b)
 {
-    int rv;
-    /* ensure hash is valid */
-    X509_check_purpose((X509 *)a, -1, 0);
-    X509_check_purpose((X509 *)b, -1, 0);
+    /* Fill in the |sha1_hash| fields.
+     *
+     * TODO(davidben): This may fail, in which case the the hash will be all
+     * zeros. This produces a consistent comparison (failures are sticky), but
+     * not a good one. OpenSSL now returns -2, but this is not a consistent
+     * comparison and may cause misbehaving sorts by transitivity. For now, we
+     * retain the old OpenSSL behavior, which was to ignore the error. See
+     * https://crbug.com/boringssl/355. */
+    x509v3_cache_extensions((X509 *)a);
+    x509v3_cache_extensions((X509 *)b);
 
-    rv = OPENSSL_memcmp(a->sha1_hash, b->sha1_hash, SHA_DIGEST_LENGTH);
+    int rv = OPENSSL_memcmp(a->sha1_hash, b->sha1_hash, SHA_DIGEST_LENGTH);
     if (rv)
         return rv;
     /* Check for match against stored encoding too */
diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc
index e0e2ec6..957c0b8 100644
--- a/crypto/x509/x509_test.cc
+++ b/crypto/x509/x509_test.cc
@@ -354,16 +354,16 @@
 // extension.
 static const char kKnownCriticalCRL[] =
     "-----BEGIN X509 CRL-----\n"
-    "MIIBujCBowIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE\n"
+    "MIIBuDCBoQIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE\n"
     "CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJ\n"
-    "Qm9yaW5nU1NMFw0xNjA5MjYxNTEwNTVaFw0xNjEwMjYxNTEwNTVaoCEwHzAKBgNV\n"
-    "HRQEAwIBATARBgNVHRwBAf8EBzAFoQMBAf8wDQYJKoZIhvcNAQELBQADggEBAA+3\n"
-    "i+5e5Ub8sccfgOBs6WVJFI9c8gvJjrJ8/dYfFIAuCyeocs7DFXn1n13CRZ+URR/Q\n"
-    "mVWgU28+xeusuSPYFpd9cyYTcVyNUGNTI3lwgcE/yVjPaOmzSZKdPakApRxtpKKQ\n"
-    "NN/56aQz3bnT/ZSHQNciRB8U6jiD9V30t0w+FDTpGaG+7bzzUH3UVF9xf9Ctp60A\n"
-    "3mfLe0scas7owSt4AEFuj2SPvcE7yvdOXbu+IEv21cEJUVExJAbhvIweHXh6yRW+\n"
-    "7VVeiNzdIjkZjyTmAzoXGha4+wbxXyBRbfH+XWcO/H+8nwyG8Gktdu2QB9S9nnIp\n"
-    "o/1TpfOMSGhMyMoyPrk=\n"
+    "Qm9yaW5nU1NMFw0xNjA5MjYxNTEwNTVaFw0xNjEwMjYxNTEwNTVaoB8wHTAKBgNV\n"
+    "HRQEAwIBATAPBgNVHRwBAf8EBTADgQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAs37Jq\n"
+    "3Htcehm6C2PKXOHekwTqTLOPWsYHfF68kYhdzcopDZBeoKE7jLRkRRGFDaR/tfUs\n"
+    "kwLSDNSQ8EwPb9PT1X8kmFn9QmJgWD6f6BzaH5ZZ9iBUwOcvrydlb/jnjdIZHQxs\n"
+    "fKOAceW5XX3f7DANC3qwYLsQZR/APkfV8nXjPYVUz1kKj04uq/BbQviInjyUYixN\n"
+    "xDx+GDWVVXccehcwAu983kAqP+JDaVQPBVksLuBXz2adrEWwvbLCnZeL3zH1IY9h\n"
+    "6MFO6echpvGbU/H+dRX9UkhdJ7gdwKVD3RjfJl+DRVox9lz8Pbo5H699Tkv9/DQP\n"
+    "9dMWxqhQlv23osLp\n"
     "-----END X509 CRL-----\n";
 
 // kUnknownCriticalCRL is kBasicCRL but with an unknown critical extension.
@@ -385,16 +385,32 @@
 // point extension followed by an unknown critical extension
 static const char kUnknownCriticalCRL2[] =
     "-----BEGIN X509 CRL-----\n"
-    "MIIBzzCBuAIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE\n"
+    "MIIBzTCBtgIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE\n"
     "CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJ\n"
-    "Qm9yaW5nU1NMFw0xNjA5MjYxNTEwNTVaFw0xNjEwMjYxNTEwNTVaoDYwNDAKBgNV\n"
-    "HRQEAwIBATARBgNVHRwBAf8EBzAFoQMBAf8wEwYMKoZIhvcSBAGEtwkAAQH/BAAw\n"
-    "DQYJKoZIhvcNAQELBQADggEBACTcpQC8jXL12JN5YzOcQ64ubQIe0XxRAd30p7qB\n"
-    "BTXGpgqBjrjxRfLms7EBYodEXB2oXMsDq3km0vT1MfYdsDD05S+SQ9CDsq/pUfaC\n"
-    "E2WNI5p8WircRnroYvbN2vkjlRbMd1+yNITohXYXCJwjEOAWOx3XIM10bwPYBv4R\n"
-    "rDobuLHoMgL3yHgMHmAkP7YpkBucNqeBV8cCdeAZLuhXFWi6yfr3r/X18yWbC/r2\n"
-    "2xXdkrSqXLFo7ToyP8YKTgiXpya4x6m53biEYwa2ULlas0igL6DK7wjYZX95Uy7H\n"
-    "GKljn9weIYiMPV/BzGymwfv2EW0preLwtyJNJPaxbdin6Jc=\n"
+    "Qm9yaW5nU1NMFw0xNjA5MjYxNTEwNTVaFw0xNjEwMjYxNTEwNTVaoDQwMjAKBgNV\n"
+    "HRQEAwIBATAPBgNVHRwBAf8EBTADgQH/MBMGDCqGSIb3EgQBhLcJAAEB/wQAMA0G\n"
+    "CSqGSIb3DQEBCwUAA4IBAQBgSogsC5kf2wzr+0hmZtmLXYd0itAiYO0Gh9AyaEOO\n"
+    "myJFuqICHBSLXXUgwNkTUa2x2I/ivyReVFV756VOlWoaV2wJUs0zeCeVBgC9ZFsq\n"
+    "5a+8OGgXwgoYESFV5Y3QRF2a1Ytzfbw/o6xLXzTngvMsLOs12D4B5SkopyEZibF4\n"
+    "tXlRZyvEudTg3CCrjNP+p/GV07nZ3wcMmKJwQeilgzFUV7NaVCCo9jvPBGp0RxAN\n"
+    "KNif7jmjK4hD5mswo/Eq5kxQIc+mTfuUFdgHuAu1hfLYe0YK+Hr4RFf6Qy4hl7Ne\n"
+    "YjqkkSVIcr87u+8AznwdstnQzsyD27Jt7SjVORkYRywi\n"
+    "-----END X509 CRL-----\n";
+
+// kBadExtensionCRL is kBasicCRL but with an incorrectly-encoded issuing
+// distribution point extension.
+static const char kBadExtensionCRL[] =
+    "-----BEGIN X509 CRL-----\n"
+    "MIIBujCBowIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE\n"
+    "CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJ\n"
+    "Qm9yaW5nU1NMFw0xNjA5MjYxNTEwNTVaFw0xNjEwMjYxNTEwNTVaoCEwHzAKBgNV\n"
+    "HRQEAwIBATARBgNVHRwBAf8EBzAFoQMBAf8wDQYJKoZIhvcNAQELBQADggEBAA+3\n"
+    "i+5e5Ub8sccfgOBs6WVJFI9c8gvJjrJ8/dYfFIAuCyeocs7DFXn1n13CRZ+URR/Q\n"
+    "mVWgU28+xeusuSPYFpd9cyYTcVyNUGNTI3lwgcE/yVjPaOmzSZKdPakApRxtpKKQ\n"
+    "NN/56aQz3bnT/ZSHQNciRB8U6jiD9V30t0w+FDTpGaG+7bzzUH3UVF9xf9Ctp60A\n"
+    "3mfLe0scas7owSt4AEFuj2SPvcE7yvdOXbu+IEv21cEJUVExJAbhvIweHXh6yRW+\n"
+    "7VVeiNzdIjkZjyTmAzoXGha4+wbxXyBRbfH+XWcO/H+8nwyG8Gktdu2QB9S9nnIp\n"
+    "o/1TpfOMSGhMyMoyPrk=\n"
     "-----END X509 CRL-----\n";
 
 // kEd25519Cert is a self-signed Ed25519 certificate.
@@ -1314,6 +1330,9 @@
   ASSERT_EQ(X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION,
             Verify(leaf.get(), {root.get()}, {root.get()},
                    {unknown_critical_crl2.get()}, X509_V_FLAG_CRL_CHECK));
+
+  // Parsing kBadExtensionCRL should fail.
+  EXPECT_FALSE(CRLFromPEM(kBadExtensionCRL));
 }
 
 TEST(X509Test, ManyNamesAndConstraints) {
@@ -2226,3 +2245,70 @@
     EXPECT_EQ(X509_V_OK, verify_cert(leaf));
   }
 }
+
+// Test that invalid extensions are rejected by, if not the parser, at least the
+// verifier.
+TEST(X509Test, InvalidExtensions) {
+  bssl::UniquePtr<X509> root = CertFromPEM(
+      GetTestData("crypto/x509/test/invalid_extension_root.pem").c_str());
+  ASSERT_TRUE(root);
+  bssl::UniquePtr<X509> intermediate = CertFromPEM(
+      GetTestData("crypto/x509/test/invalid_extension_intermediate.pem")
+          .c_str());
+  ASSERT_TRUE(intermediate);
+  bssl::UniquePtr<X509> leaf = CertFromPEM(
+      GetTestData("crypto/x509/test/invalid_extension_leaf.pem").c_str());
+  ASSERT_TRUE(leaf);
+
+  // Sanity-check that the baseline chain is accepted.
+  EXPECT_EQ(X509_V_OK,
+            Verify(leaf.get(), {root.get()}, {intermediate.get()}, {}));
+
+  static const char *kExtensions[] = {
+      "authority_key_identifier",
+      "basic_constraints",
+      "ext_key_usage",
+      "key_usage",
+      "name_constraints",
+      "subject_alt_name",
+      "subject_key_identifier",
+  };
+  for (const char *ext : kExtensions) {
+    SCOPED_TRACE(ext);
+    bssl::UniquePtr<X509> invalid_root = CertFromPEM(
+        GetTestData((std::string("crypto/x509/test/invalid_extension_root_") +
+                     ext + ".pem")
+                        .c_str())
+            .c_str());
+    ASSERT_TRUE(invalid_root);
+
+    bssl::UniquePtr<X509> invalid_intermediate = CertFromPEM(
+        GetTestData(
+            (std::string("crypto/x509/test/invalid_extension_intermediate_") +
+             ext + ".pem")
+                .c_str())
+            .c_str());
+    ASSERT_TRUE(invalid_intermediate);
+
+    bssl::UniquePtr<X509> invalid_leaf = CertFromPEM(
+        GetTestData((std::string("crypto/x509/test/invalid_extension_leaf_") +
+                     ext + ".pem")
+                        .c_str())
+            .c_str());
+    ASSERT_TRUE(invalid_leaf);
+
+    EXPECT_EQ(
+        X509_V_ERR_INVALID_EXTENSION,
+        Verify(invalid_leaf.get(), {root.get()}, {intermediate.get()}, {}));
+
+    // If the invalid extension is on an intermediate or root,
+    // |X509_verify_cert| notices by way of being unable to build a path to
+    // a valid issuer.
+    EXPECT_EQ(
+        X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
+        Verify(leaf.get(), {root.get()}, {invalid_intermediate.get()}, {}));
+    EXPECT_EQ(
+        X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
+        Verify(leaf.get(), {invalid_root.get()}, {intermediate.get()}, {}));
+  }
+}
diff --git a/crypto/x509/x509_trs.c b/crypto/x509/x509_trs.c
index 18ac883..019301a 100644
--- a/crypto/x509/x509_trs.c
+++ b/crypto/x509/x509_trs.c
@@ -59,6 +59,8 @@
 #include <openssl/obj.h>
 #include <openssl/x509v3.h>
 
+#include "../x509v3/internal.h"
+
 static int tr_cmp(const X509_TRUST **a, const X509_TRUST **b);
 static void trtable_free(X509_TRUST *p);
 
@@ -293,7 +295,8 @@
 
 static int trust_compat(X509_TRUST *trust, X509 *x, int flags)
 {
-    X509_check_purpose(x, -1, 0);
+    if (!x509v3_cache_extensions(x))
+        return X509_TRUST_UNTRUSTED;
     if (x->ex_flags & EXFLAG_SS)
         return X509_TRUST_TRUSTED;
     else
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c
index 87dcb47..308ebbc 100644
--- a/crypto/x509/x509_vfy.c
+++ b/crypto/x509/x509_vfy.c
@@ -146,14 +146,16 @@
     return ok;
 }
 
-/* Return 1 is a certificate is self signed */
-static int cert_self_signed(X509 *x)
+/* cert_self_signed checks if |x| is self-signed. If |x| is valid, it returns
+ * one and sets |*out_is_self_signed| to the result. If |x| is invalid, it
+ * returns zero. */
+static int cert_self_signed(X509 *x, int *out_is_self_signed)
 {
-    X509_check_purpose(x, -1, 0);
-    if (x->ex_flags & EXFLAG_SS)
-        return 1;
-    else
+    if (!x509v3_cache_extensions(x)) {
         return 0;
+    }
+    *out_is_self_signed = (x->ex_flags & EXFLAG_SS) != 0;
+    return 1;
 }
 
 /* Given a certificate try and find an exact match in the store */
@@ -263,8 +265,14 @@
                                  * X509_V_ERR_CERT_CHAIN_TOO_LONG error code
                                  * later. */
 
+        int is_self_signed;
+        if (!cert_self_signed(x, &is_self_signed)) {
+            ctx->error = X509_V_ERR_INVALID_EXTENSION;
+            goto end;
+        }
+
         /* If we are self signed, we break */
-        if (cert_self_signed(x))
+        if (is_self_signed)
             break;
         /*
          * If asked see if we can find issuer in trusted store first
@@ -323,7 +331,14 @@
          */
         i = sk_X509_num(ctx->chain);
         x = sk_X509_value(ctx->chain, i - 1);
-        if (cert_self_signed(x)) {
+
+        int is_self_signed;
+        if (!cert_self_signed(x, &is_self_signed)) {
+            ctx->error = X509_V_ERR_INVALID_EXTENSION;
+            goto end;
+        }
+
+        if (is_self_signed) {
             /* we have a self signed certificate */
             if (sk_X509_num(ctx->chain) == 1) {
                 /*
@@ -368,8 +383,12 @@
             /* If we have enough, we break */
             if (depth < num)
                 break;
+            if (!cert_self_signed(x, &is_self_signed)) {
+                ctx->error = X509_V_ERR_INVALID_EXTENSION;
+                goto end;
+            }
             /* If we are self signed, we break */
-            if (cert_self_signed(x))
+            if (is_self_signed)
                 break;
             ok = ctx->get_issuer(&xtmp, ctx, x);
 
diff --git a/crypto/x509/x_crl.c b/crypto/x509/x_crl.c
index 6450e84..47e0ba5 100644
--- a/crypto/x509/x_crl.c
+++ b/crypto/x509/x_crl.c
@@ -86,7 +86,7 @@
 };
 
 static int X509_REVOKED_cmp(const X509_REVOKED **a, const X509_REVOKED **b);
-static void setup_idp(X509_CRL *crl, ISSUING_DIST_POINT *idp);
+static int setup_idp(X509_CRL *crl, ISSUING_DIST_POINT *idp);
 
 ASN1_SEQUENCE(X509_REVOKED) = {
         ASN1_SIMPLE(X509_REVOKED,serialNumber, ASN1_INTEGER),
@@ -226,6 +226,7 @@
     STACK_OF(X509_EXTENSION) *exts;
     X509_EXTENSION *ext;
     size_t idx;
+    int i;
 
     switch (operation) {
     case ASN1_OP_NEW_POST:
@@ -242,26 +243,44 @@
         break;
 
     case ASN1_OP_D2I_POST:
-        X509_CRL_digest(crl, EVP_sha1(), crl->sha1_hash, NULL);
+        if (!X509_CRL_digest(crl, EVP_sha1(), crl->sha1_hash, NULL)) {
+            return 0;
+        }
+
         crl->idp = X509_CRL_get_ext_d2i(crl,
-                                        NID_issuing_distribution_point, NULL,
+                                        NID_issuing_distribution_point, &i,
                                         NULL);
-        if (crl->idp)
-            setup_idp(crl, crl->idp);
+        if (crl->idp != NULL) {
+            if (!setup_idp(crl, crl->idp)) {
+                return 0;
+            }
+        } else if (i != -1) {
+            return 0;
+        }
 
         crl->akid = X509_CRL_get_ext_d2i(crl,
-                                         NID_authority_key_identifier, NULL,
+                                         NID_authority_key_identifier, &i,
                                          NULL);
+        if (crl->akid == NULL && i != -1) {
+            return 0;
+        }
 
         crl->crl_number = X509_CRL_get_ext_d2i(crl,
-                                               NID_crl_number, NULL, NULL);
+                                               NID_crl_number, &i, NULL);
+        if (crl->crl_number == NULL && i != -1) {
+            return 0;
+        }
 
-        crl->base_crl_number = X509_CRL_get_ext_d2i(crl,
-                                                    NID_delta_crl, NULL,
+        crl->base_crl_number = X509_CRL_get_ext_d2i(crl, NID_delta_crl, &i,
                                                     NULL);
+        if (crl->base_crl_number == NULL && i != -1) {
+            return 0;
+        }
         /* Delta CRLs must have CRL number */
-        if (crl->base_crl_number && !crl->crl_number)
-            crl->flags |= EXFLAG_INVALID;
+        if (crl->base_crl_number && !crl->crl_number) {
+            OPENSSL_PUT_ERROR(X509, X509_R_DELTA_CRL_WITHOUT_CRL_NUMBER);
+            return 0;
+        }
 
         /*
          * See if we have any unhandled critical CRL extensions and indicate
@@ -319,7 +338,7 @@
 
 /* Convert IDP into a more convenient form */
 
-static void setup_idp(X509_CRL *crl, ISSUING_DIST_POINT *idp)
+static int setup_idp(X509_CRL *crl, ISSUING_DIST_POINT *idp)
 {
     int idp_only = 0;
     /* Set various flags according to IDP */
@@ -352,7 +371,7 @@
         crl->idp_reasons &= CRLDP_ALL_REASONS;
     }
 
-    DIST_POINT_set_dpname(idp->distpoint, X509_CRL_get_issuer(crl));
+    return DIST_POINT_set_dpname(idp->distpoint, X509_CRL_get_issuer(crl));
 }
 
 ASN1_SEQUENCE_ref(X509_CRL, crl_cb) = {
diff --git a/crypto/x509v3/internal.h b/crypto/x509v3/internal.h
index c143d73..245a5d1 100644
--- a/crypto/x509v3/internal.h
+++ b/crypto/x509v3/internal.h
@@ -48,6 +48,11 @@
 OPENSSL_EXPORT int x509v3_looks_like_dns_name(const unsigned char *in,
                                               size_t len);
 
+// x509v3_cache_extensions fills in a number of fields relating to X.509
+// extensions in |x|. It returns one on success and zero if some extensions were
+// invalid.
+int x509v3_cache_extensions(X509 *x);
+
 
 #if defined(__cplusplus)
 }  /* extern C */
diff --git a/crypto/x509v3/v3_purp.c b/crypto/x509v3/v3_purp.c
index d9d105e..e41b657 100644
--- a/crypto/x509v3/v3_purp.c
+++ b/crypto/x509v3/v3_purp.c
@@ -68,6 +68,7 @@
 #include <openssl/x509v3.h>
 
 #include "../internal.h"
+#include "internal.h"
 
 #define V1_ROOT (EXFLAG_V1|EXFLAG_SS)
 #define ku_reject(x, usage) \
@@ -77,8 +78,6 @@
 #define ns_reject(x, usage) \
         (((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage)))
 
-static void x509v3_cache_extensions(X509 *x);
-
 static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x,
                                     int ca);
 static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x,
@@ -144,7 +143,10 @@
 {
     int idx;
     const X509_PURPOSE *pt;
-    x509v3_cache_extensions(x);
+    if (!x509v3_cache_extensions(x)) {
+        return -1;
+    }
+
     if (id == -1)
         return 1;
     idx = X509_PURPOSE_get_by_id(id);
@@ -368,7 +370,7 @@
     return 0;
 }
 
-static void setup_dp(X509 *x, DIST_POINT *dp)
+static int setup_dp(X509 *x, DIST_POINT *dp)
 {
     X509_NAME *iname = NULL;
     size_t i;
@@ -381,7 +383,7 @@
     } else
         dp->dp_reasons = CRLDP_ALL_REASONS;
     if (!dp->distpoint || (dp->distpoint->type != 1))
-        return;
+        return 1;
     for (i = 0; i < sk_GENERAL_NAME_num(dp->CRLissuer); i++) {
         GENERAL_NAME *gen = sk_GENERAL_NAME_value(dp->CRLissuer, i);
         if (gen->type == GEN_DIRNAME) {
@@ -392,19 +394,25 @@
     if (!iname)
         iname = X509_get_issuer_name(x);
 
-    DIST_POINT_set_dpname(dp->distpoint, iname);
-
+    return DIST_POINT_set_dpname(dp->distpoint, iname);
 }
 
-static void setup_crldp(X509 *x)
+static int setup_crldp(X509 *x)
 {
-    size_t i;
-    x->crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, NULL, NULL);
-    for (i = 0; i < sk_DIST_POINT_num(x->crldp); i++)
-        setup_dp(x, sk_DIST_POINT_value(x->crldp, i));
+    int j;
+    x->crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, &j, NULL);
+    if (x->crldp == NULL && j != -1) {
+        return 0;
+    }
+    for (size_t i = 0; i < sk_DIST_POINT_num(x->crldp); i++) {
+        if (!setup_dp(x, sk_DIST_POINT_value(x->crldp, i))) {
+            return 0;
+        }
+    }
+    return 1;
 }
 
-static void x509v3_cache_extensions(X509 *x)
+int x509v3_cache_extensions(X509 *x)
 {
     BASIC_CONSTRAINTS *bs;
     PROXY_CERT_INFO_EXTENSION *pci;
@@ -420,21 +428,22 @@
     CRYPTO_MUTEX_unlock_read(&x->lock);
 
     if (is_set) {
-        return;
+        return (x->ex_flags & EXFLAG_INVALID) == 0;
     }
 
     CRYPTO_MUTEX_lock_write(&x->lock);
     if (x->ex_flags & EXFLAG_SET) {
         CRYPTO_MUTEX_unlock_write(&x->lock);
-        return;
+        return (x->ex_flags & EXFLAG_INVALID) == 0;
     }
 
-    X509_digest(x, EVP_sha1(), x->sha1_hash, NULL);
+    if (!X509_digest(x, EVP_sha1(), x->sha1_hash, NULL))
+        x->ex_flags |= EXFLAG_INVALID;
     /* V1 should mean no extensions ... */
     if (!X509_get_version(x))
         x->ex_flags |= EXFLAG_V1;
     /* Handle basic constraints */
-    if ((bs = X509_get_ext_d2i(x, NID_basic_constraints, NULL, NULL))) {
+    if ((bs = X509_get_ext_d2i(x, NID_basic_constraints, &j, NULL))) {
         if (bs->ca)
             x->ex_flags |= EXFLAG_CA;
         if (bs->pathlen) {
@@ -448,9 +457,11 @@
             x->ex_pathlen = -1;
         BASIC_CONSTRAINTS_free(bs);
         x->ex_flags |= EXFLAG_BCONS;
+    } else if (j != -1) {
+        x->ex_flags |= EXFLAG_INVALID;
     }
     /* Handle proxy certificates */
-    if ((pci = X509_get_ext_d2i(x, NID_proxyCertInfo, NULL, NULL))) {
+    if ((pci = X509_get_ext_d2i(x, NID_proxyCertInfo, &j, NULL))) {
         if (x->ex_flags & EXFLAG_CA
             || X509_get_ext_by_NID(x, NID_subject_alt_name, -1) >= 0
             || X509_get_ext_by_NID(x, NID_issuer_alt_name, -1) >= 0) {
@@ -462,9 +473,11 @@
             x->ex_pcpathlen = -1;
         PROXY_CERT_INFO_EXTENSION_free(pci);
         x->ex_flags |= EXFLAG_PROXY;
+    } else if (j != -1) {
+        x->ex_flags |= EXFLAG_INVALID;
     }
     /* Handle key usage */
-    if ((usage = X509_get_ext_d2i(x, NID_key_usage, NULL, NULL))) {
+    if ((usage = X509_get_ext_d2i(x, NID_key_usage, &j, NULL))) {
         if (usage->length > 0) {
             x->ex_kusage = usage->data[0];
             if (usage->length > 1)
@@ -473,9 +486,11 @@
             x->ex_kusage = 0;
         x->ex_flags |= EXFLAG_KUSAGE;
         ASN1_BIT_STRING_free(usage);
+    } else if (j != -1) {
+        x->ex_flags |= EXFLAG_INVALID;
     }
     x->ex_xkusage = 0;
-    if ((extusage = X509_get_ext_d2i(x, NID_ext_key_usage, NULL, NULL))) {
+    if ((extusage = X509_get_ext_d2i(x, NID_ext_key_usage, &j, NULL))) {
         x->ex_flags |= EXFLAG_XKUSAGE;
         for (i = 0; i < sk_ASN1_OBJECT_num(extusage); i++) {
             switch (OBJ_obj2nid(sk_ASN1_OBJECT_value(extusage, i))) {
@@ -518,18 +533,28 @@
             }
         }
         sk_ASN1_OBJECT_pop_free(extusage, ASN1_OBJECT_free);
+    } else if (j != -1) {
+        x->ex_flags |= EXFLAG_INVALID;
     }
 
-    if ((ns = X509_get_ext_d2i(x, NID_netscape_cert_type, NULL, NULL))) {
+    if ((ns = X509_get_ext_d2i(x, NID_netscape_cert_type, &j, NULL))) {
         if (ns->length > 0)
             x->ex_nscert = ns->data[0];
         else
             x->ex_nscert = 0;
         x->ex_flags |= EXFLAG_NSCERT;
         ASN1_BIT_STRING_free(ns);
+    } else if (j != -1) {
+        x->ex_flags |= EXFLAG_INVALID;
     }
-    x->skid = X509_get_ext_d2i(x, NID_subject_key_identifier, NULL, NULL);
-    x->akid = X509_get_ext_d2i(x, NID_authority_key_identifier, NULL, NULL);
+    x->skid = X509_get_ext_d2i(x, NID_subject_key_identifier, &j, NULL);
+    if (x->skid == NULL && j != -1) {
+        x->ex_flags |= EXFLAG_INVALID;
+    }
+    x->akid = X509_get_ext_d2i(x, NID_authority_key_identifier, &j, NULL);
+    if (x->akid == NULL && j != -1) {
+        x->ex_flags |= EXFLAG_INVALID;
+    }
     /* Does subject name match issuer ? */
     if (!X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x))) {
         x->ex_flags |= EXFLAG_SI;
@@ -538,11 +563,17 @@
             !ku_reject(x, KU_KEY_CERT_SIGN))
             x->ex_flags |= EXFLAG_SS;
     }
-    x->altname = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
-    x->nc = X509_get_ext_d2i(x, NID_name_constraints, &j, NULL);
-    if (!x->nc && (j != -1))
+    x->altname = X509_get_ext_d2i(x, NID_subject_alt_name, &j, NULL);
+    if (x->altname == NULL && j != -1) {
         x->ex_flags |= EXFLAG_INVALID;
-    setup_crldp(x);
+    }
+    x->nc = X509_get_ext_d2i(x, NID_name_constraints, &j, NULL);
+    if (x->nc == NULL && j != -1) {
+        x->ex_flags |= EXFLAG_INVALID;
+    }
+    if (!setup_crldp(x)) {
+        x->ex_flags |= EXFLAG_INVALID;
+    }
 
     for (j = 0; j < X509_get_ext_count(x); j++) {
         ex = X509_get_ext(x, j);
@@ -559,6 +590,7 @@
     x->ex_flags |= EXFLAG_SET;
 
     CRYPTO_MUTEX_unlock_write(&x->lock);
+    return (x->ex_flags & EXFLAG_INVALID) == 0;
 }
 
 /* check_ca returns one if |x| should be considered a CA certificate and zero
@@ -579,7 +611,9 @@
 
 int X509_check_ca(X509 *x)
 {
-    x509v3_cache_extensions(x);
+    if (!x509v3_cache_extensions(x)) {
+        return 0;
+    }
     return check_ca(x);
 }
 
@@ -761,8 +795,10 @@
     if (X509_NAME_cmp(X509_get_subject_name(issuer),
                       X509_get_issuer_name(subject)))
         return X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
-    x509v3_cache_extensions(issuer);
-    x509v3_cache_extensions(subject);
+    if (!x509v3_cache_extensions(issuer) ||
+        !x509v3_cache_extensions(subject)) {
+        return X509_V_ERR_UNSPECIFIED;
+    }
 
     if (subject->akid) {
         int ret = X509_check_akid(issuer, subject->akid);
@@ -819,15 +855,17 @@
 
 uint32_t X509_get_extension_flags(X509 *x)
 {
-    /* Call for side-effect of computing hash and caching extensions */
-    X509_check_purpose(x, -1, -1);
+    if (!x509v3_cache_extensions(x)) {
+        return 0;
+    }
     return x->ex_flags;
 }
 
 uint32_t X509_get_key_usage(X509 *x)
 {
-    /* Call for side-effect of computing hash and caching extensions */
-    X509_check_purpose(x, -1, -1);
+    if (!x509v3_cache_extensions(x)) {
+        return 0;
+    }
     if (x->ex_flags & EXFLAG_KUSAGE)
         return x->ex_kusage;
     return UINT32_MAX;
@@ -835,8 +873,9 @@
 
 uint32_t X509_get_extended_key_usage(X509 *x)
 {
-    /* Call for side-effect of computing hash and caching extensions */
-    X509_check_purpose(x, -1, -1);
+    if (!x509v3_cache_extensions(x)) {
+        return 0;
+    }
     if (x->ex_flags & EXFLAG_XKUSAGE)
         return x->ex_xkusage;
     return UINT32_MAX;
diff --git a/include/openssl/x509.h b/include/openssl/x509.h
index 7bf4923..252946f 100644
--- a/include/openssl/x509.h
+++ b/include/openssl/x509.h
@@ -1203,5 +1203,6 @@
 #define X509_R_NAME_TOO_LONG 135
 #define X509_R_INVALID_PARAMETER 136
 #define X509_R_SIGNATURE_ALGORITHM_MISMATCH 137
+#define X509_R_DELTA_CRL_WITHOUT_CRL_NUMBER 138
 
 #endif
diff --git a/sources.cmake b/sources.cmake
index 5454dde..a5f2d21 100644
--- a/sources.cmake
+++ b/sources.cmake
@@ -57,6 +57,30 @@
   crypto/hmac_extra/hmac_tests.txt
   crypto/poly1305/poly1305_tests.txt
   crypto/siphash/siphash_tests.txt
+  crypto/x509/test/invalid_extension_intermediate.pem
+  crypto/x509/test/invalid_extension_intermediate_authority_key_identifier.pem
+  crypto/x509/test/invalid_extension_intermediate_basic_constraints.pem
+  crypto/x509/test/invalid_extension_intermediate_ext_key_usage.pem
+  crypto/x509/test/invalid_extension_intermediate_key_usage.pem
+  crypto/x509/test/invalid_extension_intermediate_name_constraints.pem
+  crypto/x509/test/invalid_extension_intermediate_subject_alt_name.pem
+  crypto/x509/test/invalid_extension_intermediate_subject_key_identifier.pem
+  crypto/x509/test/invalid_extension_leaf.pem
+  crypto/x509/test/invalid_extension_leaf_authority_key_identifier.pem
+  crypto/x509/test/invalid_extension_leaf_basic_constraints.pem
+  crypto/x509/test/invalid_extension_leaf_ext_key_usage.pem
+  crypto/x509/test/invalid_extension_leaf_key_usage.pem
+  crypto/x509/test/invalid_extension_leaf_name_constraints.pem
+  crypto/x509/test/invalid_extension_leaf_subject_alt_name.pem
+  crypto/x509/test/invalid_extension_leaf_subject_key_identifier.pem
+  crypto/x509/test/invalid_extension_root.pem
+  crypto/x509/test/invalid_extension_root_authority_key_identifier.pem
+  crypto/x509/test/invalid_extension_root_basic_constraints.pem
+  crypto/x509/test/invalid_extension_root_ext_key_usage.pem
+  crypto/x509/test/invalid_extension_root_key_usage.pem
+  crypto/x509/test/invalid_extension_root_name_constraints.pem
+  crypto/x509/test/invalid_extension_root_subject_alt_name.pem
+  crypto/x509/test/invalid_extension_root_subject_key_identifier.pem
   crypto/x509/test/many_constraints.pem
   crypto/x509/test/many_names1.pem
   crypto/x509/test/many_names2.pem