Reject calls to X509_verify_cert that have not been reinitialised
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. Reviewed-by: Stephen Henson <steve@openssl.org>
This commit is contained in:
parent
d42d100433
commit
b3b1eb5735
@ -162,6 +162,14 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
|
|||||||
X509err(X509_F_X509_VERIFY_CERT, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY);
|
X509err(X509_F_X509_VERIFY_CERT, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (ctx->chain != NULL) {
|
||||||
|
/*
|
||||||
|
* This X509_STORE_CTX has already been used to verify a cert. We
|
||||||
|
* cannot do another one.
|
||||||
|
*/
|
||||||
|
X509err(X509_F_X509_VERIFY_CERT, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
cb = ctx->verify_cb;
|
cb = ctx->verify_cb;
|
||||||
|
|
||||||
@ -169,7 +177,6 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
|
|||||||
* first we make sure the chain we are going to build is present and that
|
* first we make sure the chain we are going to build is present and that
|
||||||
* the first entry is in place
|
* the first entry is in place
|
||||||
*/
|
*/
|
||||||
if (ctx->chain == NULL) {
|
|
||||||
if (((ctx->chain = sk_X509_new_null()) == NULL) ||
|
if (((ctx->chain = sk_X509_new_null()) == NULL) ||
|
||||||
(!sk_X509_push(ctx->chain, ctx->cert))) {
|
(!sk_X509_push(ctx->chain, ctx->cert))) {
|
||||||
X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
|
X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
|
||||||
@ -177,7 +184,6 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
|
|||||||
}
|
}
|
||||||
CRYPTO_add(&ctx->cert->references, 1, CRYPTO_LOCK_X509);
|
CRYPTO_add(&ctx->cert->references, 1, CRYPTO_LOCK_X509);
|
||||||
ctx->last_untrusted = 1;
|
ctx->last_untrusted = 1;
|
||||||
}
|
|
||||||
|
|
||||||
/* We use a temporary STACK so we can chop and hack at it */
|
/* We use a temporary STACK so we can chop and hack at it */
|
||||||
if (ctx->untrusted != NULL
|
if (ctx->untrusted != NULL
|
||||||
|
@ -39,10 +39,15 @@ X509_STORE_CTX_free() completely frees up B<ctx>. After this call B<ctx>
|
|||||||
is no longer valid.
|
is no longer valid.
|
||||||
|
|
||||||
X509_STORE_CTX_init() sets up B<ctx> for a subsequent verification operation.
|
X509_STORE_CTX_init() sets up B<ctx> for a subsequent verification operation.
|
||||||
The trusted certificate store is set to B<store>, the end entity certificate
|
It must be called before each call to X509_verify_cert(), i.e. a B<ctx> is only
|
||||||
to be verified is set to B<x509> and a set of additional certificates (which
|
good for one call to X509_verify_cert(); if you want to verify a second
|
||||||
will be untrusted but may be used to build the chain) in B<chain>. Any or
|
certificate with the same B<ctx> then you must call X509_XTORE_CTX_cleanup()
|
||||||
all of the B<store>, B<x509> and B<chain> parameters can be B<NULL>.
|
and then X509_STORE_CTX_init() again before the second call to
|
||||||
|
X509_verify_cert(). The trusted certificate store is set to B<store>, the end
|
||||||
|
entity certificate to be verified is set to B<x509> and a set of additional
|
||||||
|
certificates (which will be untrusted but may be used to build the chain) in
|
||||||
|
B<chain>. Any or all of the B<store>, B<x509> and B<chain> parameters can be
|
||||||
|
B<NULL>.
|
||||||
|
|
||||||
X509_STORE_CTX_trusted_stack() sets the set of trusted certificates of B<ctx>
|
X509_STORE_CTX_trusted_stack() sets the set of trusted certificates of B<ctx>
|
||||||
to B<sk>. This is an alternative way of specifying trusted certificates
|
to B<sk>. This is an alternative way of specifying trusted certificates
|
||||||
|
@ -32,7 +32,8 @@ OpenSSL internally for certificate validation, in both the S/MIME and
|
|||||||
SSL/TLS code.
|
SSL/TLS code.
|
||||||
|
|
||||||
The negative return value from X509_verify_cert() can only occur if no
|
The negative return value from X509_verify_cert() can only occur if no
|
||||||
certificate is set in B<ctx> (due to a programming error) or if a retry
|
certificate is set in B<ctx> (due to a programming error); if X509_verify_cert()
|
||||||
|
twice without reinitialising B<ctx> in between; or if a retry
|
||||||
operation is requested during internal lookups (which never happens with
|
operation is requested during internal lookups (which never happens with
|
||||||
standard lookup methods). It is however recommended that application check
|
standard lookup methods). It is however recommended that application check
|
||||||
for <= 0 return value on error.
|
for <= 0 return value on error.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user