Skip to content

Commit f7bf8e0

Browse files
mattcaswellkroeckx
authored andcommitted
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. RT3637 RT3621 Reviewed-by: Kurt Roeckx <[email protected]>
1 parent 3b509e8 commit f7bf8e0

1 file changed

Lines changed: 98 additions & 67 deletions

File tree

crypto/x509/x509_vfy.c

Lines changed: 98 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,11 @@ static int x509_subject_cmp(X509 **a, X509 **b)
151151

152152
int X509_verify_cert(X509_STORE_CTX *ctx)
153153
{
154-
X509 *x, *xtmp, *chain_ss = NULL;
154+
X509 *x, *xtmp, *xtmp2, *chain_ss = NULL;
155155
int bad_chain = 0;
156156
X509_VERIFY_PARAM *param = ctx->param;
157157
int depth, i, ok = 0;
158-
int num;
158+
int num, j, retry;
159159
int (*cb) (int xok, X509_STORE_CTX *xctx);
160160
STACK_OF(X509) *sktmp = NULL;
161161
if (ctx->cert == NULL) {
@@ -224,85 +224,116 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
224224
break;
225225
}
226226

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

233-
/*
234-
* Examine last certificate in chain and see if it is self signed.
235-
*/
236-
237-
i = sk_X509_num(ctx->chain);
238-
x = sk_X509_value(ctx->chain, i - 1);
239-
if (ctx->check_issued(ctx, x, x)) {
240-
/* we have a self signed certificate */
241-
if (sk_X509_num(ctx->chain) == 1) {
242-
/*
243-
* We have a single self signed certificate: see if we can find
244-
* it in the store. We must have an exact match to avoid possible
245-
* impersonation.
246-
*/
247-
ok = ctx->get_issuer(&xtmp, ctx, x);
248-
if ((ok <= 0) || X509_cmp(x, xtmp)) {
249-
ctx->error = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT;
250-
ctx->current_cert = x;
251-
ctx->error_depth = i - 1;
252-
if (ok == 1)
253-
X509_free(xtmp);
254-
bad_chain = 1;
255-
ok = cb(0, ctx);
256-
if (!ok)
257-
goto end;
235+
do {
236+
/*
237+
* Examine last certificate in chain and see if it is self signed.
238+
*/
239+
i = sk_X509_num(ctx->chain);
240+
x = sk_X509_value(ctx->chain, i - 1);
241+
if (ctx->check_issued(ctx, x, x)) {
242+
/* we have a self signed certificate */
243+
if (sk_X509_num(ctx->chain) == 1) {
244+
/*
245+
* We have a single self signed certificate: see if we can
246+
* find it in the store. We must have an exact match to avoid
247+
* possible impersonation.
248+
*/
249+
ok = ctx->get_issuer(&xtmp, ctx, x);
250+
if ((ok <= 0) || X509_cmp(x, xtmp)) {
251+
ctx->error = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT;
252+
ctx->current_cert = x;
253+
ctx->error_depth = i - 1;
254+
if (ok == 1)
255+
X509_free(xtmp);
256+
bad_chain = 1;
257+
ok = cb(0, ctx);
258+
if (!ok)
259+
goto end;
260+
} else {
261+
/*
262+
* We have a match: replace certificate with store
263+
* version so we get any trust settings.
264+
*/
265+
X509_free(x);
266+
x = xtmp;
267+
(void)sk_X509_set(ctx->chain, i - 1, x);
268+
ctx->last_untrusted = 0;
269+
}
258270
} else {
259271
/*
260-
* We have a match: replace certificate with store version so
261-
* we get any trust settings.
272+
* extract and save self signed certificate for later use
262273
*/
263-
X509_free(x);
264-
x = xtmp;
265-
(void)sk_X509_set(ctx->chain, i - 1, x);
266-
ctx->last_untrusted = 0;
274+
chain_ss = sk_X509_pop(ctx->chain);
275+
ctx->last_untrusted--;
276+
num--;
277+
j--;
278+
x = sk_X509_value(ctx->chain, num - 1);
267279
}
268-
} else {
269-
/*
270-
* extract and save self signed certificate for later use
271-
*/
272-
chain_ss = sk_X509_pop(ctx->chain);
273-
ctx->last_untrusted--;
274-
num--;
275-
x = sk_X509_value(ctx->chain, num - 1);
276280
}
277-
}
278-
279-
/* We now lookup certs from the certificate store */
280-
for (;;) {
281-
/* If we have enough, we break */
282-
if (depth < num)
283-
break;
284-
285-
/* If we are self signed, we break */
286-
if (ctx->check_issued(ctx, x, x))
287-
break;
288-
289-
ok = ctx->get_issuer(&xtmp, ctx, x);
281+
/* We now lookup certs from the certificate store */
282+
for (;;) {
283+
/* If we have enough, we break */
284+
if (depth < num)
285+
break;
286+
/* If we are self signed, we break */
287+
if (ctx->check_issued(ctx, x, x))
288+
break;
289+
ok = ctx->get_issuer(&xtmp, ctx, x);
290+
if (ok < 0)
291+
return ok;
292+
if (ok == 0)
293+
break;
294+
x = xtmp;
295+
if (!sk_X509_push(ctx->chain, x)) {
296+
X509_free(xtmp);
297+
X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
298+
return 0;
299+
}
300+
num++;
301+
}
290302

291-
if (ok < 0)
292-
return ok;
293-
if (ok == 0)
294-
break;
303+
/*
304+
* If we haven't got a least one certificate from our store then check
305+
* if there is an alternative chain that could be used.
306+
*/
307+
retry = 0;
308+
if (j == ctx->last_untrusted) {
309+
while (j-- > 1) {
310+
xtmp2 = sk_X509_value(ctx->chain, j - 1);
311+
ok = ctx->get_issuer(&xtmp, ctx, xtmp2);
312+
if (ok < 0)
313+
goto end;
314+
/* Check if we found an alternate chain */
315+
if (ok > 0) {
316+
/*
317+
* Free up the found cert we'll add it again later
318+
*/
319+
X509_free(xtmp);
295320

296-
x = xtmp;
297-
if (!sk_X509_push(ctx->chain, x)) {
298-
X509_free(xtmp);
299-
X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
300-
return 0;
321+
/*
322+
* Dump all the certs above this point - we've found an
323+
* alternate chain
324+
*/
325+
while (num > j) {
326+
xtmp = sk_X509_pop(ctx->chain);
327+
X509_free(xtmp);
328+
num--;
329+
ctx->last_untrusted--;
330+
}
331+
retry = 1;
332+
break;
333+
}
334+
}
301335
}
302-
num++;
303-
}
304-
305-
/* we now have our chain, lets check it... */
336+
} while (retry);
306337

307338
/* Is last certificate looked up self signed? */
308339
if (!ctx->check_issued(ctx, x, x)) {

0 commit comments

Comments
 (0)