OpenSSL 1.0.2c Alternative chains certificate forgery Vulnerability

ID 1337DAY-ID-23861
Type zdt
Reporter Google Security Research
Modified 2015-07-11T00:00:00


Exploit for multiple platform in category remote exploits

                                            The function X509_verify_cert checks the value of |ctx->chain| at the beginning, and if it is NULL then it initialises it, along with the value of ctx->untrusted. The normal way to use X509_verify_cert() is to first call X509_STORE_CTX_init(); then set up various parameters etc; then call X509_verify_cert(); then check the results; and finally call X509_STORE_CTX_cleanup(). The initial call to X509_STORE_CTX_init() sets |ctx->chain| to NULL. The only place in the OpenSSL codebase where |ctx->chain| is set to anything other than a non NULL value is in X509_verify_cert itself. Therefore the only ways that |ctx->chain| could be non NULL on entry to X509_verify_cert is if one of the following occurs:
1) An application calls X509_verify_cert() twice without re-initialising in between.
2) An application reaches inside the X509_STORE_CTX structure and changes the value of |ctx->chain| directly.

With regards to the second of these, we should discount this - it should not be supported to allow this.

With regards to the first of these, the documentation is not exactly crystal clear, but the implication is that you must call X509_STORE_CTX_init() before each call to X509_verify_cert(). If you fail to do this then, at best, the results would be undefined.

Calling X509_verify_cert() with |ctx->chain| set to a non NULL value is likely to have unexpected results, and could be dangerous. This commit changes the behaviour of X509_verify_cert() so that it causes an error if |ctx->chain| is anything other than NULL (because this indicates that we have not been initialised properly). It also clarifies the associated documentation. This is a follow up commit to CVE-2015-1793. Alternative chains certificate forgery (CVE-2015-1793)

Severity: High

During certificate verification, OpenSSL (starting from version 1.0.1n and 1.0.2b) will attempt to find an alternative certificate chain if the first attempt to build such a chain fails. An error in the implementation of this logic can mean that an attacker could cause certain checks on untrusted certificates to be bypassed, such as the CA flag, enabling them to use a valid leaf certificate to act as a CA and "issue" an invalid certificate.

This issue will impact any application that verifies certificates including SSL/TLS/DTLS clients and SSL/TLS/DTLS servers using client authentication.

This issue affects OpenSSL versions 1.0.2c, 1.0.2b, 1.0.1n and 1.0.1o.

OpenSSL 1.0.2b/1.0.2c users should upgrade to 1.0.2d
OpenSSL 1.0.1n/1.0.1o users should upgrade to 1.0.1p

This issue was reported to OpenSSL on 24th June 2015 by Adam Langley/David Benjamin (Google/BoringSSL). The fix was developed by the BoringSSL project.


As per our previous announcements and our Release Strategy
(, support for OpenSSL versions
1.0.0 and 0.9.8 will cease on 31st December 2015. No security updates for these
releases will be provided after that date. Users of these releases are advised
to upgrade.

@@ -193,6 +193,14 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
return -1;
+ if (ctx->chain != NULL) {
+ /*
+ * This X509_STORE_CTX has already been used to verify a cert. We
+ * cannot do another one.
+ */
+ return -1;
+ }

cb = ctx->verify_cb;

@@ -200,15 +208,13 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
* first we make sure the chain we are going to build is present and that
* the first entry is in place
- if (ctx->chain == NULL) {
- if (((ctx->chain = sk_X509_new_null()) == NULL) ||
- (!sk_X509_push(ctx->chain, ctx->cert))) {
- goto end;
- }
- CRYPTO_add(&ctx->cert->references, 1, CRYPTO_LOCK_X509);
- ctx->last_untrusted = 1;
+ if (((ctx->chain = sk_X509_new_null()) == NULL) ||
+ (!sk_X509_push(ctx->chain, ctx->cert))) {
+ goto end;
+ CRYPTO_add(&ctx->cert->references, 1, CRYPTO_LOCK_X509);
+ ctx->last_untrusted = 1;

/* We use a temporary STACK so we can chop and hack at it */
if (ctx->untrusted != NULL


URL for this Security Advisory:

Note: the online version of the advisory may be updated with additional details over time.

For details of OpenSSL severity classifications please see:

# [2018-01-09]  #