Skip to content

Commit

Permalink
deps: backport openssl patch of alt cert chains 1
Browse files Browse the repository at this point in the history
This a backport of da084a5ec6cebd67ae27f2463ebe4a50bb840fa5 in
https://github.com/openssl/openssl by Matt Caswell <[email protected]> as

In certain situations the server provided certificate chain may no
longer be valid. However the issuer of the leaf, or some intermediate
cert is in fact in the trust store.

When building a trust chain if the first attempt fails, then try to
see if alternate chains could be constructed that are trusted.

deps: backport openssl patch of alt cert chains 2

This a backport of 15dba5be6a4482a9ad7e5b846291f31e97e338ca in
https://github.com/openssl/openssl by Matt Caswell <[email protected]> as

Add flag to inhibit checking for alternate certificate chains. Setting this
behaviour will force behaviour as per previous versions of OpenSSL
  • Loading branch information
Shigeki Ohtsu committed Apr 10, 2015
1 parent 752636f commit 0e6fad7
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 70 deletions.
177 changes: 107 additions & 70 deletions deps/openssl/openssl/crypto/x509/x509_vfy.c
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,11 @@ static X509 *lookup_cert_match(X509_STORE_CTX *ctx, X509 *x)

int X509_verify_cert(X509_STORE_CTX *ctx)
{
X509 *x, *xtmp, *chain_ss = NULL;
X509 *x, *xtmp, *xtmp2, *chain_ss = NULL;
int bad_chain = 0;
X509_VERIFY_PARAM *param = ctx->param;
int depth, i, ok = 0;
int num;
int num, j, retry;
int (*cb) (int xok, X509_STORE_CTX *xctx);
STACK_OF(X509) *sktmp = NULL;
if (ctx->cert == NULL) {
Expand Down Expand Up @@ -276,91 +276,128 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
break;
}

/* Remember how many untrusted certs we have */
j = num;
/*
* at this point, chain should contain a list of untrusted certificates.
* We now need to add at least one trusted one, if possible, otherwise we
* complain.
*/

/*
* Examine last certificate in chain and see if it is self signed.
*/

i = sk_X509_num(ctx->chain);
x = sk_X509_value(ctx->chain, i - 1);
if (cert_self_signed(x)) {
/* we have a self signed certificate */
if (sk_X509_num(ctx->chain) == 1) {
/*
* We have a single self signed certificate: see if we can find
* it in the store. We must have an exact match to avoid possible
* impersonation.
*/
ok = ctx->get_issuer(&xtmp, ctx, x);
if ((ok <= 0) || X509_cmp(x, xtmp)) {
ctx->error = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT;
ctx->current_cert = x;
ctx->error_depth = i - 1;
if (ok == 1)
X509_free(xtmp);
bad_chain = 1;
ok = cb(0, ctx);
if (!ok)
goto end;
do {
/*
* Examine last certificate in chain and see if it is self signed.
*/
i = sk_X509_num(ctx->chain);
x = sk_X509_value(ctx->chain, i - 1);
if (cert_self_signed(x)) {
/* we have a self signed certificate */
if (sk_X509_num(ctx->chain) == 1) {
/*
* We have a single self signed certificate: see if we can
* find it in the store. We must have an exact match to avoid
* possible impersonation.
*/
ok = ctx->get_issuer(&xtmp, ctx, x);
if ((ok <= 0) || X509_cmp(x, xtmp)) {
ctx->error = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT;
ctx->current_cert = x;
ctx->error_depth = i - 1;
if (ok == 1)
X509_free(xtmp);
bad_chain = 1;
ok = cb(0, ctx);
if (!ok)
goto end;
} else {
/*
* We have a match: replace certificate with store
* version so we get any trust settings.
*/
X509_free(x);
x = xtmp;
(void)sk_X509_set(ctx->chain, i - 1, x);
ctx->last_untrusted = 0;
}
} else {
/*
* We have a match: replace certificate with store version so
* we get any trust settings.
* extract and save self signed certificate for later use
*/
X509_free(x);
x = xtmp;
(void)sk_X509_set(ctx->chain, i - 1, x);
ctx->last_untrusted = 0;
chain_ss = sk_X509_pop(ctx->chain);
ctx->last_untrusted--;
num--;
j--;
x = sk_X509_value(ctx->chain, num - 1);
}
} else {
/*
* extract and save self signed certificate for later use
*/
chain_ss = sk_X509_pop(ctx->chain);
ctx->last_untrusted--;
num--;
x = sk_X509_value(ctx->chain, num - 1);
}
}

/* We now lookup certs from the certificate store */
for (;;) {
/* If we have enough, we break */
if (depth < num)
break;
/* We now lookup certs from the certificate store */
for (;;) {
/* If we have enough, we break */
if (depth < num)
break;
/* If we are self signed, we break */
if (cert_self_signed(x))
break;
ok = ctx->get_issuer(&xtmp, ctx, x);

/* If we are self signed, we break */
if (cert_self_signed(x))
break;
if (ok < 0)
return ok;
if (ok == 0)
break;
x = xtmp;
if (!sk_X509_push(ctx->chain, x)) {
X509_free(xtmp);
X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
return 0;
}
num++;
}

ok = ctx->get_issuer(&xtmp, ctx, x);
/* we now have our chain, lets check it... */
i = check_trust(ctx);

if (ok < 0)
return ok;
if (ok == 0)
break;
/* If explicitly rejected error */
if (i == X509_TRUST_REJECTED)
goto end;
/*
* If it's not explicitly trusted then check if there is an alternative
* chain that could be used. We only do this if we haven't already
* checked via TRUSTED_FIRST and the user hasn't switched off alternate
* chain checking
*/
retry = 0;
if (i != X509_TRUST_TRUSTED
&& !(ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST)
&& !(ctx->param->flags & X509_V_FLAG_NO_ALT_CHAINS)) {
while (j-- > 1) {
xtmp2 = sk_X509_value(ctx->chain, j - 1);
ok = ctx->get_issuer(&xtmp, ctx, xtmp2);
if (ok < 0)
goto end;
/* Check if we found an alternate chain */
if (ok > 0) {
/*
* Free up the found cert we'll add it again later
*/
X509_free(xtmp);

x = xtmp;
if (!sk_X509_push(ctx->chain, x)) {
X509_free(xtmp);
X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
return 0;
/*
* Dump all the certs above this point - we've found an
* alternate chain
*/
while (num > j) {
xtmp = sk_X509_pop(ctx->chain);
X509_free(xtmp);
num--;
ctx->last_untrusted--;
}
retry = 1;
break;
}
}
}
num++;
}
} while (retry);

/* we now have our chain, lets check it... */

i = check_trust(ctx);

/* If explicitly rejected error */
if (i == X509_TRUST_REJECTED)
goto end;
/*
* If not explicitly trusted then indicate error unless it's a single
* self signed certificate in which case we've indicated an error already
Expand Down
6 changes: 6 additions & 0 deletions deps/openssl/openssl/crypto/x509/x509_vfy.h
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,12 @@ void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth);

/* Allow partial chains if at least one certificate is in trusted store */
# define X509_V_FLAG_PARTIAL_CHAIN 0x80000
/*
* If the initial chain is not trusted, do not attempt to build an alternative
* chain. Alternate chain checking was introduced in 1.1.0. Setting this flag
* will force the behaviour to match that of previous versions.
*/
# define X509_V_FLAG_NO_ALT_CHAINS 0x100000

# define X509_VP_FLAG_DEFAULT 0x1
# define X509_VP_FLAG_OVERWRITE 0x2
Expand Down

0 comments on commit 0e6fad7

Please sign in to comment.