From: Andy Polyakov Date: Wed, 25 Apr 2012 22:07:23 +0000 (+0000) Subject: s23_clnt.c: ensure interoperability by maitaining client "version capability" X-Git-Tag: OpenSSL_1_0_1b~6 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=5bbed29518243edc4b62b452151b9756f057f168;p=oweals%2Fopenssl.git s23_clnt.c: ensure interoperability by maitaining client "version capability" vector contiguous [from HEAD]. PR: 2802 --- diff --git a/CHANGES b/CHANGES index 99b0a5de9f..7b4a78a160 100644 --- a/CHANGES +++ b/CHANGES @@ -4,7 +4,13 @@ Changes between 1.0.1a and 1.0.1b [xx XXX xxxx] - *) + *) In order to ensure interoperabilty SSL_OP_NO_protocolX does not + disable just protocol X, but all protocols above X *if* there are + protocols *below* X still enabled. In more practical terms it means + that if application wants to disable TLS1.0 in favor of TLS1.1 and + above, it's not sufficient to pass SSL_OP_NO_TLSv1, one has to pass + SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3|SSL_OP_NO_SSLv2. + [Andy Polyakov] Changes between 1.0.1 and 1.0.1a [19 Apr 2012] diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c index 0f2e19e135..47673e740a 100644 --- a/ssl/s23_clnt.c +++ b/ssl/s23_clnt.c @@ -282,34 +282,51 @@ static int ssl23_client_hello(SSL *s) SSL_COMP *comp; #endif int ret; + unsigned long mask, options = s->options; - ssl2_compat = (s->options & SSL_OP_NO_SSLv2) ? 0 : 1; + ssl2_compat = (options & SSL_OP_NO_SSLv2) ? 0 : 1; if (ssl2_compat && ssl23_no_ssl2_ciphers(s)) ssl2_compat = 0; -#ifndef OPENSSL_NO_TLS1_2_CLIENT - if (!(s->options & SSL_OP_NO_TLSv1_2)) - { - version = TLS1_2_VERSION; - } - else + + /* + * SSL_OP_NO_X disables all protocols above X *if* there are + * some protocols below X enabled. This is required in order + * to maintain "version capability" vector contiguous. So + * that if application wants to disable TLS1.0 in favour of + * TLS1>=1, it would be insufficient to pass SSL_NO_TLSv1, the + * answer is SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3|SSL_OP_NO_SSLv2. + */ + mask = SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1 +#if !defined(OPENSSL_NO_SSL3) + |SSL_OP_NO_SSLv3 #endif - if (!(s->options & SSL_OP_NO_TLSv1_1)) - { +#if !defined(OPENSSL_NO_SSL2) + |(ssl2_compat?SSL_OP_NO_SSLv2:0) +#endif + ; +#if !defined(OPENSSL_NO_TLS1_2_CLIENT) + version = TLS1_2_VERSION; + + if ((options & SSL_OP_NO_TLSv1_2) && (options & mask) != mask) version = TLS1_1_VERSION; - } - else if (!(s->options & SSL_OP_NO_TLSv1)) - { +#else + version = TLS1_1_VERSION; +#endif + mask &= ~SSL_OP_NO_TLSv1_1; + if ((options & SSL_OP_NO_TLSv1_1) && (options & mask) != mask) version = TLS1_VERSION; - } - else if (!(s->options & SSL_OP_NO_SSLv3)) - { + mask &= ~SSL_OP_NO_TLSv1; +#if !defined(OPENSSL_NO_SSL3) + if ((options & SSL_OP_NO_TLSv1) && (options & mask) != mask) version = SSL3_VERSION; - } - else if (!(s->options & SSL_OP_NO_SSLv2)) - { + mask &= ~SSL_OP_NO_SSLv3; +#endif +#if !defined(OPENSSL_NO_SSL2) + if ((options & SSL_OP_NO_SSLv3) && (options & mask) != mask) version = SSL2_VERSION; - } +#endif + #ifndef OPENSSL_NO_TLSEXT if (version != SSL2_VERSION) {