@@ -187,11 +187,11 @@ static X509 *lookup_cert_match(X509_STORE_CTX *ctx, X509 *x)
187187
188188int 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
0 commit comments