diff -up openssl-1.0.2a/apps/apps.c.alt-chains openssl-1.0.2a/apps/apps.c --- openssl-1.0.2a/apps/apps.c.alt-chains 2015-03-19 14:30:36.000000000 +0100 +++ openssl-1.0.2a/apps/apps.c 2015-04-28 16:49:50.124558770 +0200 @@ -2371,6 +2371,8 @@ int args_verify(char ***pargs, int *parg flags |= X509_V_FLAG_SUITEB_192_LOS; else if (!strcmp(arg, "-partial_chain")) flags |= X509_V_FLAG_PARTIAL_CHAIN; + else if (!strcmp(arg, "-no_alt_chains")) + flags |= X509_V_FLAG_NO_ALT_CHAINS; else return 0; diff -up openssl-1.0.2a/apps/cms.c.alt-chains openssl-1.0.2a/apps/cms.c --- openssl-1.0.2a/apps/cms.c.alt-chains 2015-04-23 10:22:56.225685251 +0200 +++ openssl-1.0.2a/apps/cms.c 2015-04-28 16:49:50.125558793 +0200 @@ -648,6 +648,8 @@ int MAIN(int argc, char **argv) BIO_printf(bio_err, "-trusted_first use trusted certificates first when building the trust chain\n"); BIO_printf(bio_err, + "-no_alt_chains only ever use the first certificate chain found\n"); + BIO_printf(bio_err, "-crl_check check revocation status of signer's certificate using CRLs\n"); BIO_printf(bio_err, "-crl_check_all check revocation status of signer's certificate chain using CRLs\n"); diff -up openssl-1.0.2a/apps/ocsp.c.alt-chains openssl-1.0.2a/apps/ocsp.c --- openssl-1.0.2a/apps/ocsp.c.alt-chains 2015-04-23 10:22:56.225685251 +0200 +++ openssl-1.0.2a/apps/ocsp.c 2015-04-28 16:49:50.125558793 +0200 @@ -538,6 +538,8 @@ int MAIN(int argc, char **argv) BIO_printf(bio_err, "-trusted_first use trusted certificates first when building the trust chain\n"); BIO_printf(bio_err, + "-no_alt_chains only ever use the first certificate chain found\n"); + BIO_printf(bio_err, "-VAfile file validator certificates file\n"); BIO_printf(bio_err, "-validity_period n maximum validity discrepancy in seconds\n"); diff -up openssl-1.0.2a/apps/s_client.c.alt-chains openssl-1.0.2a/apps/s_client.c --- openssl-1.0.2a/apps/s_client.c.alt-chains 2015-04-23 10:22:56.225685251 +0200 +++ openssl-1.0.2a/apps/s_client.c 2015-04-28 16:49:50.126558815 +0200 @@ -335,6 +335,8 @@ static void sc_usage(void) BIO_printf(bio_err, " -trusted_first - Use trusted CA's first when building the trust chain\n"); BIO_printf(bio_err, + " -no_alt_chains - only ever use the first certificate chain found\n"); + BIO_printf(bio_err, " -reconnect - Drop and re-make the connection with the same Session-ID\n"); BIO_printf(bio_err, " -pause - sleep(1) after each read(2) and write(2) system call\n"); diff -up openssl-1.0.2a/apps/smime.c.alt-chains openssl-1.0.2a/apps/smime.c --- openssl-1.0.2a/apps/smime.c.alt-chains 2015-04-23 10:22:56.226685277 +0200 +++ openssl-1.0.2a/apps/smime.c 2015-04-28 16:49:50.128558861 +0200 @@ -444,6 +444,8 @@ int MAIN(int argc, char **argv) BIO_printf(bio_err, "-trusted_first use trusted certificates first when building the trust chain\n"); BIO_printf(bio_err, + "-no_alt_chains only ever use the first certificate chain found\n"); + BIO_printf(bio_err, "-crl_check check revocation status of signer's certificate using CRLs\n"); BIO_printf(bio_err, "-crl_check_all check revocation status of signer's certificate chain using CRLs\n"); diff -up openssl-1.0.2a/apps/s_server.c.alt-chains openssl-1.0.2a/apps/s_server.c --- openssl-1.0.2a/apps/s_server.c.alt-chains 2015-04-23 10:22:56.226685277 +0200 +++ openssl-1.0.2a/apps/s_server.c 2015-04-28 16:49:50.128558861 +0200 @@ -571,6 +571,8 @@ static void sv_usage(void) BIO_printf(bio_err, " -trusted_first - Use trusted CA's first when building the trust chain\n"); BIO_printf(bio_err, + " -no_alt_chains - only ever use the first certificate chain found\n"); + BIO_printf(bio_err, " -nocert - Don't use any certificates (Anon-DH)\n"); BIO_printf(bio_err, " -cipher arg - play with 'openssl ciphers' to see what goes here\n"); diff -up openssl-1.0.2a/apps/verify.c.alt-chains openssl-1.0.2a/apps/verify.c --- openssl-1.0.2a/apps/verify.c.alt-chains 2015-04-28 16:49:50.128558861 +0200 +++ openssl-1.0.2a/apps/verify.c 2015-04-28 16:50:52.210974346 +0200 @@ -232,7 +232,7 @@ int MAIN(int argc, char **argv) if (ret == 1) { BIO_printf(bio_err, "usage: verify [-verbose] [-CApath path] [-CAfile file] [-trusted_first] [-purpose purpose] [-crl_check]"); - BIO_printf(bio_err, " [-attime timestamp]"); + BIO_printf(bio_err, " [-no_alt_chains] [-attime timestamp]"); #ifndef OPENSSL_NO_ENGINE BIO_printf(bio_err, " [-engine e]"); #endif diff -up openssl-1.0.2a/crypto/x509/x509_vfy.c.alt-chains openssl-1.0.2a/crypto/x509/x509_vfy.c --- openssl-1.0.2a/crypto/x509/x509_vfy.c.alt-chains 2015-04-23 10:22:56.188684277 +0200 +++ openssl-1.0.2a/crypto/x509/x509_vfy.c 2015-04-28 17:03:40.478786778 +0200 @@ -189,11 +189,11 @@ static X509 *lookup_cert_match(X509_STOR 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) { @@ -278,91 +278,136 @@ 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) { + STACK_OF(X509) *chtmp = ctx->chain; + xtmp2 = sk_X509_value(ctx->chain, j - 1); + /* + * Temporarily set chain to NULL so we don't discount + * duplicates: the same certificate could be an untrusted + * CA found in the trusted store. + */ + ctx->chain = NULL; + ok = ctx->get_issuer(&xtmp, ctx, xtmp2); + ctx->chain = chtmp; + 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 diff -up openssl-1.0.2a/crypto/x509/x509_vfy.h.alt-chains openssl-1.0.2a/crypto/x509/x509_vfy.h --- openssl-1.0.2a/crypto/x509/x509_vfy.h.alt-chains 2015-04-23 10:22:56.016679751 +0200 +++ openssl-1.0.2a/crypto/x509/x509_vfy.h 2015-04-28 16:49:18.551838908 +0200 @@ -432,6 +432,12 @@ void X509_STORE_CTX_set_depth(X509_STORE /* 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.0.2b. 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 diff -up openssl-1.0.2a/doc/apps/cms.pod.alt-chains openssl-1.0.2a/doc/apps/cms.pod --- openssl-1.0.2a/doc/apps/cms.pod.alt-chains 2015-04-23 10:22:56.227685303 +0200 +++ openssl-1.0.2a/doc/apps/cms.pod 2015-04-28 16:54:17.537682406 +0200 @@ -36,6 +36,7 @@ B B [B<-CAfile file>] [B<-CApath dir>] [B<-trusted_first>] +[B<-no_alt_chains>] [B<-md digest>] [B<-[cipher]>] [B<-nointern>] @@ -426,7 +427,7 @@ portion of a message so they may be incl then many S/MIME mail clients check the signers certificate's email address matches that specified in the From: address. -=item B<-purpose, -ignore_critical, -issuer_checks, -crl_check, -crl_check_all, -policy_check, -extended_crl, -x509_strict, -policy -check_ss_sig> +=item B<-purpose, -ignore_critical, -issuer_checks, -crl_check, -crl_check_all, -policy_check, -extended_crl, -x509_strict, -policy -check_ss_sig -no_alt_chains> Set various certificate chain valiadition option. See the L|verify(1)> manual page for details. @@ -662,4 +663,6 @@ Support for RSA-OAEP and RSA-PSS was fir The use of non-RSA keys with B<-encrypt> and B<-decrypt> was first added to OpenSSL 1.1.0. +The -no_alt_chains options was first added to OpenSSL 1.0.2b. + =cut diff -up openssl-1.0.2a/doc/apps/ocsp.pod.alt-chains openssl-1.0.2a/doc/apps/ocsp.pod --- openssl-1.0.2a/doc/apps/ocsp.pod.alt-chains 2015-04-23 10:22:56.227685303 +0200 +++ openssl-1.0.2a/doc/apps/ocsp.pod 2015-04-28 16:53:44.564914852 +0200 @@ -30,6 +30,7 @@ B B [B<-CApath dir>] [B<-CAfile file>] [B<-trusted_first>] +[B<-no_alt_chains>] [B<-VAfile file>] [B<-validity_period n>] [B<-status_age n>] @@ -151,6 +152,10 @@ in the response or residing in other cer chain to verify responder certificate. This is mainly useful in environments with Bridge CA or Cross-Certified CAs. +=item B<-no_alt_chains> + +See L|verify(1)> manual page for details. + =item B<-verify_other file> file containing additional certificates to search when attempting to locate @@ -388,3 +393,9 @@ second file. openssl ocsp -index demoCA/index.txt -rsigner rcert.pem -CA demoCA/cacert.pem -reqin req.der -respout resp.der + +=head1 HISTORY + +The -no_alt_chains options was first added to OpenSSL 1.0.2b. + +=cut diff -up openssl-1.0.2a/doc/apps/s_client.pod.alt-chains openssl-1.0.2a/doc/apps/s_client.pod --- openssl-1.0.2a/doc/apps/s_client.pod.alt-chains 2015-04-23 10:22:56.227685303 +0200 +++ openssl-1.0.2a/doc/apps/s_client.pod 2015-04-28 16:55:24.812248450 +0200 @@ -20,6 +20,7 @@ B B [B<-CApath directory>] [B<-CAfile filename>] [B<-trusted_first>] +[B<-no_alt_chains>] [B<-reconnect>] [B<-pause>] [B<-showcerts>] @@ -124,7 +125,7 @@ also used when building the client certi A file containing trusted certificates to use during server authentication and to use when attempting to build the client certificate chain. -=item B<-purpose, -ignore_critical, -issuer_checks, -crl_check, -crl_check_all, -policy_check, -extended_crl, -x509_strict, -policy -check_ss_sig, -trusted_first> +=item B<-purpose, -ignore_critical, -issuer_checks, -crl_check, -crl_check_all, -policy_check, -extended_crl, -x509_strict, -policy -check_ss_sig, -trusted_first -no_alt_chains> Set various certificate chain valiadition option. See the L|verify(1)> manual page for details. @@ -365,4 +366,8 @@ information whenever a session is renego L, L, L +=head1 HISTORY + +The -no_alt_chains options was first added to OpenSSL 1.0.2b. + =cut diff -up openssl-1.0.2a/doc/apps/smime.pod.alt-chains openssl-1.0.2a/doc/apps/smime.pod --- openssl-1.0.2a/doc/apps/smime.pod.alt-chains 2015-04-23 10:22:56.227685303 +0200 +++ openssl-1.0.2a/doc/apps/smime.pod 2015-04-28 16:57:33.598246384 +0200 @@ -18,6 +18,7 @@ B B [B<-CAfile file>] [B<-CApath dir>] [B<-trusted_first>] +[B<-no_alt_chains>] [B<-certfile file>] [B<-signer file>] [B<-recip file>] @@ -268,7 +269,7 @@ portion of a message so they may be incl then many S/MIME mail clients check the signers certificate's email address matches that specified in the From: address. -=item B<-purpose, -ignore_critical, -issuer_checks, -crl_check, -crl_check_all, -policy_check, -extended_crl, -x509_strict, -policy -check_ss_sig> +=item B<-purpose, -ignore_critical, -issuer_checks, -crl_check, -crl_check_all, -policy_check, -extended_crl, -x509_strict, -policy -check_ss_sig -no_alt_chains> Set various options of certificate chain verification. See L|verify(1)> manual page for details. @@ -450,5 +451,6 @@ structures may cause parsing errors. The use of multiple B<-signer> options and the B<-resign> command were first added in OpenSSL 1.0.0 +The -no_alt_chains options was first added to OpenSSL 1.0.2b. =cut diff -up openssl-1.0.2a/doc/apps/s_server.pod.alt-chains openssl-1.0.2a/doc/apps/s_server.pod --- openssl-1.0.2a/doc/apps/s_server.pod.alt-chains 2015-04-23 10:22:56.227685303 +0200 +++ openssl-1.0.2a/doc/apps/s_server.pod 2015-04-28 16:56:27.494707598 +0200 @@ -34,6 +34,7 @@ B B [B<-CApath directory>] [B<-CAfile filename>] [B<-trusted_first>] +[B<-no_alt_chains>] [B<-nocert>] [B<-cipher cipherlist>] [B<-serverpref>] @@ -181,6 +182,10 @@ Use certificates in CA file or CA direct when building the trust chain to verify client certificates. This is mainly useful in environments with Bridge CA or Cross-Certified CAs. +=item B<-no_alt_chains> + +See the L|verify(1)> manual page for details. + =item B<-state> prints out the SSL session states. @@ -413,4 +418,8 @@ unknown cipher suites a client says it s L, L, L +=head1 HISTORY + +The -no_alt_chains options was first added to OpenSSL 1.0.2b. + =cut diff -up openssl-1.0.2a/doc/apps/verify.pod.alt-chains openssl-1.0.2a/doc/apps/verify.pod --- openssl-1.0.2a/doc/apps/verify.pod.alt-chains 2015-04-23 10:22:56.228685330 +0200 +++ openssl-1.0.2a/doc/apps/verify.pod 2015-04-28 16:52:22.544033948 +0200 @@ -26,6 +26,7 @@ B B [B<-extended_crl>] [B<-use_deltas>] [B<-policy_print>] +[B<-no_alt_chains>] [B<-untrusted file>] [B<-help>] [B<-issuer_checks>] @@ -131,6 +132,14 @@ Set policy variable inhibit-any-policy ( Set policy variable inhibit-policy-mapping (see RFC5280). +=item B<-no_alt_chains> + +When building a certificate chain, if the first certificate chain found is not +trusted, then OpenSSL will continue to check to see if an alternative chain can +be found that is trusted. With this option that behaviour is suppressed so that +only the first chain found is ever used. Using this option will force the +behaviour to match that of previous OpenSSL versions. + =item B<-policy_print> Print out diagnostics related to policy processing. @@ -432,4 +441,8 @@ B<20 X509_V_ERR_UNABLE_TO_GET_ISSUER_CER L +=head1 HISTORY + +The -no_alt_chains options was first added to OpenSSL 1.0.2b. + =cut diff -up openssl-1.0.2a/doc/crypto/X509_VERIFY_PARAM_set_flags.pod.alt-chains openssl-1.0.2a/doc/crypto/X509_VERIFY_PARAM_set_flags.pod --- openssl-1.0.2a/doc/crypto/X509_VERIFY_PARAM_set_flags.pod.alt-chains 2015-03-19 14:30:36.000000000 +0100 +++ openssl-1.0.2a/doc/crypto/X509_VERIFY_PARAM_set_flags.pod 2015-04-28 16:52:22.544033948 +0200 @@ -197,6 +197,12 @@ verification. If this flag is set then a to the verification callback and it B be prepared to handle such cases without assuming they are hard errors. +The B flag suppresses checking for alternative +chains. By default, when building a certificate chain, if the first certificate +chain found is not trusted, then OpenSSL will continue to check to see if an +alternative chain can be found that is trusted. With this flag set the behaviour +will match that of OpenSSL versions prior to 1.0.2b. + =head1 NOTES The above functions should be used to manipulate verification parameters @@ -233,6 +239,6 @@ L =head1 HISTORY -TBA +The B flag was added in OpenSSL 1.0.2b =cut