Skip to content

Commit ae8831f

Browse files
author
Shigeki Ohtsu
committed
deps: backport openssl patch of alt cert chains 1
This a backport of da084a5ec6cebd67ae27f2463ebe4a50bb840fa5 in https://github.com/openssl/openssl by Matt Caswell <matt@openssl.org> 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 <matt@openssl.org> as Add flag to inhibit checking for alternate certificate chains. Setting this behaviour will force behaviour as per previous versions of OpenSSL Fixes: #589 PR-URL: #1389 Reviewed-By: Fedor Indutny <fedor@indutny.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
1 parent 71316c4 commit ae8831f

File tree

2 files changed

+113
-70
lines changed

2 files changed

+113
-70
lines changed

deps/openssl/openssl/crypto/x509/x509_vfy.c

+107-70
Original file line numberDiff line numberDiff line change
@@ -187,11 +187,11 @@ static X509 *lookup_cert_match(X509_STORE_CTX *ctx, X509 *x)
187187

188188
int X509_verify_cert(X509_STORE_CTX *ctx)
189189
{
190-
X509 *x, *xtmp, *chain_ss = NULL;
190+
X509 *x, *xtmp, *xtmp2, *chain_ss = NULL;
191191
int bad_chain = 0;
192192
X509_VERIFY_PARAM *param = ctx->param;
193193
int depth, i, ok = 0;
194-
int num;
194+
int num, j, retry;
195195
int (*cb) (int xok, X509_STORE_CTX *xctx);
196196
STACK_OF(X509) *sktmp = NULL;
197197
if (ctx->cert == NULL) {
@@ -276,91 +276,128 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
276276
break;
277277
}
278278

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

285-
/*
286-
* Examine last certificate in chain and see if it is self signed.
287-
*/
288-
289-
i = sk_X509_num(ctx->chain);
290-
x = sk_X509_value(ctx->chain, i - 1);
291-
if (cert_self_signed(x)) {
292-
/* we have a self signed certificate */
293-
if (sk_X509_num(ctx->chain) == 1) {
294-
/*
295-
* We have a single self signed certificate: see if we can find
296-
* it in the store. We must have an exact match to avoid possible
297-
* impersonation.
298-
*/
299-
ok = ctx->get_issuer(&xtmp, ctx, x);
300-
if ((ok <= 0) || X509_cmp(x, xtmp)) {
301-
ctx->error = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT;
302-
ctx->current_cert = x;
303-
ctx->error_depth = i - 1;
304-
if (ok == 1)
305-
X509_free(xtmp);
306-
bad_chain = 1;
307-
ok = cb(0, ctx);
308-
if (!ok)
309-
goto end;
287+
do {
288+
/*
289+
* Examine last certificate in chain and see if it is self signed.
290+
*/
291+
i = sk_X509_num(ctx->chain);
292+
x = sk_X509_value(ctx->chain, i - 1);
293+
if (cert_self_signed(x)) {
294+
/* we have a self signed certificate */
295+
if (sk_X509_num(ctx->chain) == 1) {
296+
/*
297+
* We have a single self signed certificate: see if we can
298+
* find it in the store. We must have an exact match to avoid
299+
* possible impersonation.
300+
*/
301+
ok = ctx->get_issuer(&xtmp, ctx, x);
302+
if ((ok <= 0) || X509_cmp(x, xtmp)) {
303+
ctx->error = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT;
304+
ctx->current_cert = x;
305+
ctx->error_depth = i - 1;
306+
if (ok == 1)
307+
X509_free(xtmp);
308+
bad_chain = 1;
309+
ok = cb(0, ctx);
310+
if (!ok)
311+
goto end;
312+
} else {
313+
/*
314+
* We have a match: replace certificate with store
315+
* version so we get any trust settings.
316+
*/
317+
X509_free(x);
318+
x = xtmp;
319+
(void)sk_X509_set(ctx->chain, i - 1, x);
320+
ctx->last_untrusted = 0;
321+
}
310322
} else {
311323
/*
312-
* We have a match: replace certificate with store version so
313-
* we get any trust settings.
324+
* extract and save self signed certificate for later use
314325
*/
315-
X509_free(x);
316-
x = xtmp;
317-
(void)sk_X509_set(ctx->chain, i - 1, x);
318-
ctx->last_untrusted = 0;
326+
chain_ss = sk_X509_pop(ctx->chain);
327+
ctx->last_untrusted--;
328+
num--;
329+
j--;
330+
x = sk_X509_value(ctx->chain, num - 1);
319331
}
320-
} else {
321-
/*
322-
* extract and save self signed certificate for later use
323-
*/
324-
chain_ss = sk_X509_pop(ctx->chain);
325-
ctx->last_untrusted--;
326-
num--;
327-
x = sk_X509_value(ctx->chain, num - 1);
328332
}
329-
}
330-
331-
/* We now lookup certs from the certificate store */
332-
for (;;) {
333-
/* If we have enough, we break */
334-
if (depth < num)
335-
break;
333+
/* We now lookup certs from the certificate store */
334+
for (;;) {
335+
/* If we have enough, we break */
336+
if (depth < num)
337+
break;
338+
/* If we are self signed, we break */
339+
if (cert_self_signed(x))
340+
break;
341+
ok = ctx->get_issuer(&xtmp, ctx, x);
336342

337-
/* If we are self signed, we break */
338-
if (cert_self_signed(x))
339-
break;
343+
if (ok < 0)
344+
return ok;
345+
if (ok == 0)
346+
break;
347+
x = xtmp;
348+
if (!sk_X509_push(ctx->chain, x)) {
349+
X509_free(xtmp);
350+
X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
351+
return 0;
352+
}
353+
num++;
354+
}
340355

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

343-
if (ok < 0)
344-
return ok;
345-
if (ok == 0)
346-
break;
359+
/* If explicitly rejected error */
360+
if (i == X509_TRUST_REJECTED)
361+
goto end;
362+
/*
363+
* If it's not explicitly trusted then check if there is an alternative
364+
* chain that could be used. We only do this if we haven't already
365+
* checked via TRUSTED_FIRST and the user hasn't switched off alternate
366+
* chain checking
367+
*/
368+
retry = 0;
369+
if (i != X509_TRUST_TRUSTED
370+
&& !(ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST)
371+
&& !(ctx->param->flags & X509_V_FLAG_NO_ALT_CHAINS)) {
372+
while (j-- > 1) {
373+
xtmp2 = sk_X509_value(ctx->chain, j - 1);
374+
ok = ctx->get_issuer(&xtmp, ctx, xtmp2);
375+
if (ok < 0)
376+
goto end;
377+
/* Check if we found an alternate chain */
378+
if (ok > 0) {
379+
/*
380+
* Free up the found cert we'll add it again later
381+
*/
382+
X509_free(xtmp);
347383

348-
x = xtmp;
349-
if (!sk_X509_push(ctx->chain, x)) {
350-
X509_free(xtmp);
351-
X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
352-
return 0;
384+
/*
385+
* Dump all the certs above this point - we've found an
386+
* alternate chain
387+
*/
388+
while (num > j) {
389+
xtmp = sk_X509_pop(ctx->chain);
390+
X509_free(xtmp);
391+
num--;
392+
ctx->last_untrusted--;
393+
}
394+
retry = 1;
395+
break;
396+
}
397+
}
353398
}
354-
num++;
355-
}
399+
} while (retry);
356400

357-
/* we now have our chain, lets check it... */
358-
359-
i = check_trust(ctx);
360-
361-
/* If explicitly rejected error */
362-
if (i == X509_TRUST_REJECTED)
363-
goto end;
364401
/*
365402
* If not explicitly trusted then indicate error unless it's a single
366403
* self signed certificate in which case we've indicated an error already

deps/openssl/openssl/crypto/x509/x509_vfy.h

+6
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,12 @@ void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth);
432432

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

436442
# define X509_VP_FLAG_DEFAULT 0x1
437443
# define X509_VP_FLAG_OVERWRITE 0x2

0 commit comments

Comments
 (0)