diff --git a/lib/libssl/s23_clnt.c b/lib/libssl/s23_clnt.c index 8674cdf6270..2511a94b28f 100644 --- a/lib/libssl/s23_clnt.c +++ b/lib/libssl/s23_clnt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: s23_clnt.c,v 1.47 2016/12/04 14:32:30 jsing Exp $ */ +/* $OpenBSD: s23_clnt.c,v 1.48 2016/12/30 16:57:01 jsing Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -231,43 +231,15 @@ ssl23_client_hello(SSL *s) unsigned char *buf; unsigned char *p, *d; unsigned long l; - int version = 0, version_major, version_minor; - int ret; - unsigned long mask, options = s->options; + uint16_t version; size_t outlen; - - /* - * 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; - version = TLS1_2_VERSION; - - if ((options & SSL_OP_NO_TLSv1_2) && (options & mask) != mask) - version = TLS1_1_VERSION; - mask &= ~SSL_OP_NO_TLSv1_1; - if ((options & SSL_OP_NO_TLSv1_1) && (options & mask) != mask) - version = TLS1_VERSION; - mask &= ~SSL_OP_NO_TLSv1; + int ret; buf = (unsigned char *)s->init_buf->data; if (s->state == SSL23_ST_CW_CLNT_HELLO_A) { arc4random_buf(s->s3->client_random, SSL3_RANDOM_SIZE); - if (version == TLS1_2_VERSION) { - version_major = TLS1_2_VERSION_MAJOR; - version_minor = TLS1_2_VERSION_MINOR; - } else if (version == TLS1_1_VERSION) { - version_major = TLS1_1_VERSION_MAJOR; - version_minor = TLS1_1_VERSION_MINOR; - } else if (version == TLS1_VERSION) { - version_major = TLS1_VERSION_MAJOR; - version_minor = TLS1_VERSION_MINOR; - } else { + if (ssl_enabled_version_range(s, NULL, &version) == -1) { SSLerr(SSL_F_SSL23_CLIENT_HELLO, SSL_R_NO_PROTOCOLS_AVAILABLE); return (-1); @@ -283,8 +255,8 @@ ssl23_client_hello(SSL *s) */ d = p = &(buf[SSL3_RT_HEADER_LENGTH + SSL3_HM_HEADER_LENGTH]); - *(p++) = version_major; - *(p++) = version_minor; + *(p++) = version >> 8; + *(p++) = version & 0xff; /* Random stuff */ memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE); @@ -334,7 +306,7 @@ ssl23_client_hello(SSL *s) /* fill in 5-byte record header */ d = buf; *(d++) = SSL3_RT_HANDSHAKE; - *(d++) = version_major; + *(d++) = version >> 8; /* * Some servers hang if we use long client hellos @@ -343,7 +315,7 @@ ssl23_client_hello(SSL *s) if (TLS1_get_client_version(s) > TLS1_VERSION) *(d++) = 1; else - *(d++) = version_minor; + *(d++) = version & 0xff; s2n((int)l, d); /* number of bytes to write */ @@ -362,8 +334,7 @@ ssl23_client_hello(SSL *s) if ((ret >= 2) && s->msg_callback) { /* Client Hello has been sent; tell msg_callback */ - - s->msg_callback(1, version, SSL3_RT_HANDSHAKE, + s->msg_callback(1, s->client_version, SSL3_RT_HANDSHAKE, s->init_buf->data + 5, ret - 5, s, s->msg_callback_arg); } diff --git a/lib/libssl/ssl_lib.c b/lib/libssl/ssl_lib.c index 5d93a3bc13a..11f46161a9b 100644 --- a/lib/libssl/ssl_lib.c +++ b/lib/libssl/ssl_lib.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_lib.c,v 1.122 2016/12/04 14:32:30 jsing Exp $ */ +/* $OpenBSD: ssl_lib.c,v 1.123 2016/12/30 16:57:01 jsing Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -2484,6 +2484,48 @@ SSL_get_version(const SSL *s) return ssl_version_string(s->version); } +int +ssl_enabled_version_range(SSL *s, uint16_t *min_ver, uint16_t *max_ver) +{ + uint16_t min_version, max_version; + + /* + * The enabled versions have to be a contiguous range, which means we + * cannot enable and disable single versions at our whim, even though + * this is what the OpenSSL flags allow. The historical way this has + * been handled is by making a flag mean that all higher versions + * are disabled, if any version lower than the flag is enabled. + */ + + min_version = 0; + max_version = TLS1_2_VERSION; + + if ((s->options & SSL_OP_NO_TLSv1) == 0) + min_version = TLS1_VERSION; + else if ((s->options & SSL_OP_NO_TLSv1_1) == 0) + min_version = TLS1_1_VERSION; + else if ((s->options & SSL_OP_NO_TLSv1_2) == 0) + min_version = TLS1_2_VERSION; + + if ((s->options & SSL_OP_NO_TLSv1_2) && min_version < TLS1_2_VERSION) + max_version = TLS1_1_VERSION; + if ((s->options & SSL_OP_NO_TLSv1_1) && min_version < TLS1_1_VERSION) + max_version = TLS1_VERSION; + if ((s->options & SSL_OP_NO_TLSv1) && min_version < TLS1_VERSION) + max_version = 0; + + /* Everything has been disabled... */ + if (min_version == 0 || max_version == 0) + return -1; + + if (min_ver != NULL) + *min_ver = min_version; + if (max_ver != NULL) + *max_ver = max_version; + + return 0; +} + uint16_t ssl_max_server_version(SSL *s) { diff --git a/lib/libssl/ssl_locl.h b/lib/libssl/ssl_locl.h index de977846a41..e8fbd235725 100644 --- a/lib/libssl/ssl_locl.h +++ b/lib/libssl/ssl_locl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_locl.h,v 1.142 2016/12/30 15:12:45 jsing Exp $ */ +/* $OpenBSD: ssl_locl.h,v 1.143 2016/12/30 16:57:01 jsing Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -497,6 +497,7 @@ extern SSL3_ENC_METHOD ssl3_undef_enc_method; extern SSL_CIPHER ssl3_ciphers[]; const char *ssl_version_string(int ver); +int ssl_enabled_version_range(SSL *s, uint16_t *min_ver, uint16_t *max_ver); uint16_t ssl_max_server_version(SSL *s); extern SSL3_ENC_METHOD DTLSv1_enc_data;