diff -up openssl-1.0.1k/apps/apps.c.alt-chains openssl-1.0.1k/apps/apps.c --- openssl-1.0.1k/apps/apps.c.alt-chains 2015-07-09 14:58:55.949753674 +0200 +++ openssl-1.0.1k/apps/apps.c 2015-07-09 14:58:55.970754174 +0200 @@ -2365,6 +2365,8 @@ int args_verify(char ***pargs, int *parg flags |= X509_V_FLAG_NOTIFY_POLICY; else if (!strcmp(arg, "-check_ss_sig")) flags |= X509_V_FLAG_CHECK_SS_SIGNATURE; + else if (!strcmp(arg, "-no_alt_chains")) + flags |= X509_V_FLAG_NO_ALT_CHAINS; else if (!strcmp(arg, "-trusted_first")) flags |= X509_V_FLAG_TRUSTED_FIRST; else diff -up openssl-1.0.1k/apps/cms.c.alt-chains openssl-1.0.1k/apps/cms.c --- openssl-1.0.1k/apps/cms.c.alt-chains 2015-07-09 14:58:55.949753674 +0200 +++ openssl-1.0.1k/apps/cms.c 2015-07-09 14:58:55.970754174 +0200 @@ -642,6 +642,7 @@ int MAIN(int argc, char **argv) BIO_printf (bio_err, "-text include or delete text MIME headers\n"); BIO_printf (bio_err, "-CApath dir trusted certificates directory\n"); BIO_printf (bio_err, "-CAfile file trusted certificates file\n"); + BIO_printf (bio_err, "-no_alt_chains only ever use the first certificate chain found\n"); BIO_printf (bio_err, "-trusted_first use trusted certificates first when building the trust chain\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.1k/apps/ocsp.c.alt-chains openssl-1.0.1k/apps/ocsp.c --- openssl-1.0.1k/apps/ocsp.c.alt-chains 2015-07-09 14:58:55.949753674 +0200 +++ openssl-1.0.1k/apps/ocsp.c 2015-07-09 14:58:55.971754198 +0200 @@ -605,6 +605,7 @@ int MAIN(int argc, char **argv) BIO_printf (bio_err, "-path path to use in OCSP request\n"); BIO_printf (bio_err, "-CApath dir trusted certificates directory\n"); BIO_printf (bio_err, "-CAfile file trusted certificates file\n"); + BIO_printf (bio_err, "-no_alt_chains only ever use the first certificate chain found\n"); BIO_printf (bio_err, "-trusted_first use trusted certificates first when building the trust chain\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.1k/apps/s_client.c.alt-chains openssl-1.0.1k/apps/s_client.c --- openssl-1.0.1k/apps/s_client.c.alt-chains 2015-07-09 14:58:55.956753841 +0200 +++ openssl-1.0.1k/apps/s_client.c 2015-07-09 14:58:55.971754198 +0200 @@ -299,6 +299,7 @@ static void sc_usage(void) BIO_printf(bio_err," -pass arg - private key file pass phrase source\n"); BIO_printf(bio_err," -CApath arg - PEM format directory of CA's\n"); BIO_printf(bio_err," -CAfile arg - PEM format file of CA's\n"); + BIO_printf(bio_err," -no_alt_chains - only ever use the first certificate chain found\n"); BIO_printf(bio_err," -trusted_first - Use trusted CA's first when building the trust chain\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.1k/apps/smime.c.alt-chains openssl-1.0.1k/apps/smime.c --- openssl-1.0.1k/apps/smime.c.alt-chains 2015-07-09 14:58:55.950753698 +0200 +++ openssl-1.0.1k/apps/smime.c 2015-07-09 14:58:55.971754198 +0200 @@ -479,6 +479,7 @@ int MAIN(int argc, char **argv) BIO_printf (bio_err, "-text include or delete text MIME headers\n"); BIO_printf (bio_err, "-CApath dir trusted certificates directory\n"); BIO_printf (bio_err, "-CAfile file trusted certificates file\n"); + BIO_printf (bio_err, "-no_alt_chains only ever use the first certificate chain found\n"); BIO_printf (bio_err, "-trusted_first use trusted certificates first when building the trust chain\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.1k/apps/s_server.c.alt-chains openssl-1.0.1k/apps/s_server.c --- openssl-1.0.1k/apps/s_server.c.alt-chains 2015-07-09 14:58:55.950753698 +0200 +++ openssl-1.0.1k/apps/s_server.c 2015-07-09 14:58:55.971754198 +0200 @@ -502,6 +502,7 @@ static void sv_usage(void) BIO_printf(bio_err," -state - Print the SSL states\n"); BIO_printf(bio_err," -CApath arg - PEM format directory of CA's\n"); BIO_printf(bio_err," -CAfile arg - PEM format file of CA's\n"); + BIO_printf(bio_err," -no_alt_chains - only ever use the first certificate chain found\n"); BIO_printf(bio_err," -trusted_first - Use trusted CA's first when building the trust chain\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.1k/apps/verify.c.alt-chains openssl-1.0.1k/apps/verify.c --- openssl-1.0.1k/apps/verify.c.alt-chains 2015-07-09 14:58:55.951753722 +0200 +++ openssl-1.0.1k/apps/verify.c 2015-07-09 14:58:55.972754221 +0200 @@ -238,7 +238,7 @@ int MAIN(int argc, char **argv) end: 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.1k/crypto/x509/x509_vfy.c.alt-chains openssl-1.0.1k/crypto/x509/x509_vfy.c --- openssl-1.0.1k/crypto/x509/x509_vfy.c.alt-chains 2015-07-09 14:58:55.951753722 +0200 +++ openssl-1.0.1k/crypto/x509/x509_vfy.c 2015-07-09 15:28:03.630442145 +0200 @@ -154,11 +154,11 @@ static int x509_subject_cmp(X509 **a, X5 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) @@ -167,21 +167,27 @@ int X509_verify_cert(X509_STORE_CTX *ctx return -1; } + if (ctx->chain != NULL) { + /* + * This X509_STORE_CTX has already been used to verify a cert. We + * cannot do another one. + */ + X509err(X509_F_X509_VERIFY_CERT, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return -1; + } + cb=ctx->verify_cb; /* first we make sure the chain we are going to build is * present and that the first entry is in place */ - if (ctx->chain == NULL) + if ( ((ctx->chain=sk_X509_new_null()) == NULL) || + (!sk_X509_push(ctx->chain,ctx->cert))) { - if ( ((ctx->chain=sk_X509_new_null()) == NULL) || - (!sk_X509_push(ctx->chain,ctx->cert))) - { - X509err(X509_F_X509_VERIFY_CERT,ERR_R_MALLOC_FAILURE); - goto end; - } - CRYPTO_add(&ctx->cert->references,1,CRYPTO_LOCK_X509); - ctx->last_untrusted=1; + X509err(X509_F_X509_VERIFY_CERT,ERR_R_MALLOC_FAILURE); + goto end; } + CRYPTO_add(&ctx->cert->references,1,CRYPTO_LOCK_X509); + ctx->last_untrusted=1; /* We use a temporary STACK so we can chop and hack at it */ if (ctx->untrusted != NULL @@ -247,10 +253,14 @@ 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. */ + do { /* Examine last certificate in chain and see if it * is self signed. */ @@ -294,6 +304,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx chain_ss=sk_X509_pop(ctx->chain); ctx->last_untrusted--; num--; + j--; x=sk_X509_value(ctx->chain,num-1); } } @@ -322,7 +333,42 @@ int X509_verify_cert(X509_STORE_CTX *ctx num++; } - /* we now have our chain, lets check it... */ + /* + * If we haven't got a least one certificate from our store then check + * if there is an alternative chain that could be used. We only do this + * if the user hasn't switched off alternate chain checking + */ + retry = 0; + if (num == ctx->last_untrusted && + !(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); + + /* + * 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 = j; + retry = 1; + break; + } + } + } + } while (retry); /* Is last certificate looked up self signed? */ if (!ctx->check_issued(ctx,x,x)) diff -up openssl-1.0.1k/crypto/x509/x509_vfy.h.alt-chains openssl-1.0.1k/crypto/x509/x509_vfy.h --- openssl-1.0.1k/crypto/x509/x509_vfy.h.alt-chains 2015-07-09 14:58:55.951753722 +0200 +++ openssl-1.0.1k/crypto/x509/x509_vfy.h 2015-07-09 14:58:55.972754221 +0200 @@ -391,7 +391,12 @@ void X509_STORE_CTX_set_depth(X509_STORE #define X509_V_FLAG_CHECK_SS_SIGNATURE 0x4000 /* Use trusted store first */ #define X509_V_FLAG_TRUSTED_FIRST 0x8000 - +/* + * If the initial chain is not trusted, do not attempt to build an alternative + * chain. Alternate chain checking was introduced in 1.0.1n/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.1k/doc/apps/cms.pod.alt-chains openssl-1.0.1k/doc/apps/cms.pod --- openssl-1.0.1k/doc/apps/cms.pod.alt-chains 2015-07-09 14:58:55.951753722 +0200 +++ openssl-1.0.1k/doc/apps/cms.pod 2015-07-09 14:58:55.972754221 +0200 @@ -35,6 +35,7 @@ B B [B<-print>] [B<-CAfile file>] [B<-CApath dir>] +[B<-no_alt_chains>] [B<-trusted_first>] [B<-md digest>] [B<-[cipher]>] @@ -413,7 +414,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. diff -up openssl-1.0.1k/doc/apps/ocsp.pod.alt-chains openssl-1.0.1k/doc/apps/ocsp.pod --- openssl-1.0.1k/doc/apps/ocsp.pod.alt-chains 2015-07-09 14:58:55.951753722 +0200 +++ openssl-1.0.1k/doc/apps/ocsp.pod 2015-07-09 14:58:55.973754245 +0200 @@ -29,6 +29,7 @@ B B [B<-path>] [B<-CApath dir>] [B<-CAfile file>] +[B<-no_alt_chains>]] [B<-trusted_first>] [B<-VAfile file>] [B<-validity_period n>] @@ -143,6 +144,10 @@ connection timeout to the OCSP responder file or pathname containing trusted CA certificates. These are used to verify the signature on the OCSP response. +=item B<-no_alt_chains> + +See L|verify(1)> manual page for details. + =item B<-trusted_first> Use certificates in CA file or CA directory over certificates provided diff -up openssl-1.0.1k/doc/apps/s_client.pod.alt-chains openssl-1.0.1k/doc/apps/s_client.pod --- openssl-1.0.1k/doc/apps/s_client.pod.alt-chains 2015-07-09 14:58:55.952753746 +0200 +++ openssl-1.0.1k/doc/apps/s_client.pod 2015-07-09 14:58:55.973754245 +0200 @@ -19,6 +19,7 @@ B B [B<-pass arg>] [B<-CApath directory>] [B<-CAfile filename>] +[B<-no_alt_chains>] [B<-trusted_first>] [B<-reconnect>] [B<-pause>] @@ -122,7 +123,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 -no_alt_chains> Set various certificate chain valiadition option. See the L|verify(1)> manual page for details. diff -up openssl-1.0.1k/doc/apps/smime.pod.alt-chains openssl-1.0.1k/doc/apps/smime.pod --- openssl-1.0.1k/doc/apps/smime.pod.alt-chains 2015-07-09 14:58:55.952753746 +0200 +++ openssl-1.0.1k/doc/apps/smime.pod 2015-07-09 14:58:55.973754245 +0200 @@ -17,6 +17,7 @@ B B [B<-in file>] [B<-CAfile file>] [B<-CApath dir>] +[B<-no_alt_chains>] [B<-trusted_first>] [B<-certfile file>] [B<-signer 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. diff -up openssl-1.0.1k/doc/apps/s_server.pod.alt-chains openssl-1.0.1k/doc/apps/s_server.pod --- openssl-1.0.1k/doc/apps/s_server.pod.alt-chains 2015-07-09 14:58:55.952753746 +0200 +++ openssl-1.0.1k/doc/apps/s_server.pod 2015-07-09 14:58:55.973754245 +0200 @@ -33,6 +33,7 @@ B B [B<-state>] [B<-CApath directory>] [B<-CAfile filename>] +[B<-no_alt_chains>] [B<-trusted_first>] [B<-nocert>] [B<-cipher cipherlist>] @@ -179,6 +180,10 @@ and to use when attempting to build the is also used in the list of acceptable client CAs passed to the client when a certificate is requested. +=item B<-no_alt_chains> + +See the L|verify(1)> manual page for details. + =item B<-trusted_first> Use certificates in CA file or CA directory before other certificates diff -up openssl-1.0.1k/doc/apps/verify.pod.alt-chains openssl-1.0.1k/doc/apps/verify.pod --- openssl-1.0.1k/doc/apps/verify.pod.alt-chains 2015-07-09 14:58:55.952753746 +0200 +++ openssl-1.0.1k/doc/apps/verify.pod 2015-07-09 14:58:55.973754245 +0200 @@ -23,6 +23,7 @@ B B [B<-extended_crl>] [B<-use_deltas>] [B<-policy_print>] +[B<-no_alt_chains>] [B<-untrusted file>] [B<-help>] [B<-issuer_checks>] @@ -115,6 +116,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. diff -up openssl-1.0.1k/doc/crypto/X509_STORE_CTX_new.pod.alt-chains openssl-1.0.1k/doc/crypto/X509_STORE_CTX_new.pod --- openssl-1.0.1k/doc/crypto/X509_STORE_CTX_new.pod.alt-chains 2014-10-15 15:49:15.000000000 +0200 +++ openssl-1.0.1k/doc/crypto/X509_STORE_CTX_new.pod 2015-07-09 15:29:16.461174414 +0200 @@ -39,10 +39,15 @@ X509_STORE_CTX_free() completely frees u is no longer valid. X509_STORE_CTX_init() sets up B for a subsequent verification operation. -The trusted certificate store is set to B, the end entity certificate -to be verified is set to B and a set of additional certificates (which -will be untrusted but may be used to build the chain) in B. Any or -all of the B, B and B parameters can be B. +It must be called before each call to X509_verify_cert(), i.e. a B is only +good for one call to X509_verify_cert(); if you want to verify a second +certificate with the same B then you must call X509_XTORE_CTX_cleanup() +and then X509_STORE_CTX_init() again before the second call to +X509_verify_cert(). The trusted certificate store is set to B, the end +entity certificate to be verified is set to B and a set of additional +certificates (which will be untrusted but may be used to build the chain) in +B. Any or all of the B, B and B parameters can be +B. X509_STORE_CTX_trusted_stack() sets the set of trusted certificates of B to B. This is an alternative way of specifying trusted certificates diff -up openssl-1.0.1k/doc/crypto/X509_verify_cert.pod.alt-chains openssl-1.0.1k/doc/crypto/X509_verify_cert.pod --- openssl-1.0.1k/doc/crypto/X509_verify_cert.pod.alt-chains 2014-10-15 15:49:15.000000000 +0200 +++ openssl-1.0.1k/doc/crypto/X509_verify_cert.pod 2015-07-09 15:29:16.461174414 +0200 @@ -32,7 +32,8 @@ OpenSSL internally for certificate valid SSL/TLS code. The negative return value from X509_verify_cert() can only occur if no -certificate is set in B (due to a programming error) or if a retry +certificate is set in B (due to a programming error); if X509_verify_cert() +twice without reinitialising B in between; or if a retry operation is requested during internal lookups (which never happens with standard lookup methods). It is however recommended that application check for <= 0 return value on error. diff -up openssl-1.0.1k/doc/crypto/X509_VERIFY_PARAM_set_flags.pod.alt-chains openssl-1.0.1k/doc/crypto/X509_VERIFY_PARAM_set_flags.pod --- openssl-1.0.1k/doc/crypto/X509_VERIFY_PARAM_set_flags.pod.alt-chains 2015-01-08 15:00:36.000000000 +0100 +++ openssl-1.0.1k/doc/crypto/X509_VERIFY_PARAM_set_flags.pod 2015-07-09 14:58:55.973754245 +0200 @@ -133,6 +133,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.1n and 1.0.2b. + =head1 NOTES The above functions should be used to manipulate verification parameters @@ -166,6 +172,6 @@ L flag was added in upstream OpenSSL 1.0.1n and 1.0.2b =cut