diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c index b0d6b6902..ca46d8dfc 100644 --- a/ssl/s23_clnt.c +++ b/ssl/s23_clnt.c @@ -447,37 +447,15 @@ static int ssl23_get_server_hello(SSL *s) ((p[0] == SSL3_RT_HANDSHAKE && p[5] == SSL3_MT_SERVER_HELLO) || (p[0] == SSL3_RT_ALERT && p[3] == 0 && p[4] == 2))) { - /* we have sslv3 or tls1 (server hello or alert) */ - - if ((p[2] == SSL3_VERSION_MINOR) && - !(s->options & SSL_OP_NO_SSLv3)) - { - s->version=SSL3_VERSION; - s->method=SSLv3_client_method(); - } - else if ((p[2] == TLS1_VERSION_MINOR) && - !(s->options & SSL_OP_NO_TLSv1)) - { - s->version=TLS1_VERSION; - s->method=TLSv1_client_method(); - } - else if ((p[2] == TLS1_1_VERSION_MINOR) && - !(s->options & SSL_OP_NO_TLSv1_1)) - { - s->version=TLS1_1_VERSION; - s->method=TLSv1_1_client_method(); - } - else if ((p[2] == TLS1_2_VERSION_MINOR) && - !(s->options & SSL_OP_NO_TLSv1_2)) - { - s->version=TLS1_2_VERSION; - s->method=TLSv1_2_client_method(); - } - else + uint16_t version = (p[1] << 8) | p[2]; + if (!ssl3_is_version_enabled(s, version)) { OPENSSL_PUT_ERROR(SSL, ssl23_get_server_hello, SSL_R_UNSUPPORTED_PROTOCOL); goto err; } + s->version = version; + s->method = ssl3_get_method(version); + assert(s->method != NULL); if (p[0] == SSL3_RT_ALERT && p[5] != SSL3_AL_WARNING) { diff --git a/ssl/s23_srvr.c b/ssl/s23_srvr.c index 06916ed30..08d063a1d 100644 --- a/ssl/s23_srvr.c +++ b/ssl/s23_srvr.c @@ -121,20 +121,6 @@ static int ssl23_get_client_hello(SSL *s); static int ssl23_get_v2_client_hello(SSL *s); -static const SSL_METHOD *ssl23_get_server_method(int ver) - { - if (ver == SSL3_VERSION) - return(SSLv3_server_method()); - else if (ver == TLS1_VERSION) - return(TLSv1_server_method()); - else if (ver == TLS1_1_VERSION) - return(TLSv1_1_server_method()); - else if (ver == TLS1_2_VERSION) - return(TLSv1_2_server_method()); - else - return(NULL); - } - int ssl23_accept(SSL *s) { BUF_MEM *buf; @@ -213,7 +199,7 @@ int ssl23_accept(SSL *s) } s->state = SSL3_ST_SR_CLNT_HELLO_A; - s->method = ssl23_get_server_method(s->version); + s->method = ssl3_get_method(s->version); assert(s->method != NULL); s->handshake_func = s->method->ssl_accept; s->init_num = 0; @@ -246,35 +232,6 @@ end: return(ret); } -/* ssl23_get_mutual_version determines the highest supported version for a - * client which reports a highest version of |client_version|. On success, it - * returns 1 and sets |*out_version| to the negotiated version. Otherwise, it - * returns 0. */ -static int ssl23_get_mutual_version(SSL *s, int *out_version, uint16_t client_version) - { - if (client_version >= TLS1_2_VERSION && !(s->options & SSL_OP_NO_TLSv1_2)) - { - *out_version = TLS1_2_VERSION; - return 1; - } - if (client_version >= TLS1_1_VERSION && !(s->options & SSL_OP_NO_TLSv1_1)) - { - *out_version = TLS1_1_VERSION; - return 1; - } - if (client_version >= TLS1_VERSION && !(s->options & SSL_OP_NO_TLSv1)) - { - *out_version = TLS1_VERSION; - return 1; - } - if (client_version >= SSL3_VERSION && !(s->options & SSL_OP_NO_SSLv3)) - { - *out_version = SSL3_VERSION; - return 1; - } - return 0; - } - static int ssl23_get_client_hello(SSL *s) { uint8_t *p; @@ -336,11 +293,13 @@ static int ssl23_get_client_hello(SSL *s) /* This is a V2ClientHello. Determine the version to * use. */ uint16_t client_version = (p[3] << 8) | p[4]; - if (!ssl23_get_mutual_version(s, &s->version, client_version)) + uint16_t version = ssl3_get_mutual_version(s, client_version); + if (version == 0) { OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_UNSUPPORTED_PROTOCOL); goto err; } + s->version = version; /* Parse the entire V2ClientHello. */ s->state = SSL23_ST_SR_V2_CLNT_HELLO; } @@ -355,7 +314,7 @@ static int ssl23_get_client_hello(SSL *s) * this, so we simply reject such connections to avoid * protocol version downgrade attacks. */ uint16_t record_length = (p[3] << 8) | p[4]; - uint16_t client_version; + uint16_t client_version, version; if (record_length < 6) { OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_RECORD_TOO_SMALL); @@ -363,11 +322,13 @@ static int ssl23_get_client_hello(SSL *s) } client_version = (p[9] << 8) | p[10]; - if (!ssl23_get_mutual_version(s, &s->version, client_version)) + version = ssl3_get_mutual_version(s, client_version); + if (version == 0) { OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_UNSUPPORTED_PROTOCOL); goto err; } + s->version = version; /* Reset the record-layer state for SSL3. */ assert(s->rstate == SSL_ST_READ_HEADER); diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index 19af3cc5f..c7ae0eec0 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -580,49 +580,6 @@ end: return(ret); } -uint16_t ssl3_get_max_client_version(SSL *s) - { - unsigned long options = s->options; - uint16_t version = 0; - - /* OpenSSL's API for controlling versions entails blacklisting - * individual protocols. This has two problems. First, on the client, - * the protocol can only express a contiguous range of versions. Second, - * a library consumer trying to set a maximum version cannot disable - * protocol versions that get added in a future version of the library. - * - * To account for both of these, OpenSSL interprets the client-side - * bitmask as a min/max range by picking the lowest contiguous non-empty - * range of enabled protocols. Note that this means it is impossible to - * set a maximum version of TLS 1.2 in a future-proof way. - * - * By this scheme, the maximum version is the lowest version V such that - * V is enabled and V+1 is disabled or unimplemented. - * - * TODO(davidben): Deprecate this API in favor of more sensible - * min_version/max_version settings. */ - if (SSL_IS_DTLS(s)) - { - if (!(options & SSL_OP_NO_DTLSv1_2)) - version = DTLS1_2_VERSION; - if (!(options & SSL_OP_NO_DTLSv1) && (options & SSL_OP_NO_DTLSv1_2)) - version = DTLS1_VERSION; - } - else - { - if (!(options & SSL_OP_NO_TLSv1_2)) - version = TLS1_2_VERSION; - if (!(options & SSL_OP_NO_TLSv1_1) && (options & SSL_OP_NO_TLSv1_2)) - version = TLS1_1_VERSION; - if (!(options & SSL_OP_NO_TLSv1) && (options & SSL_OP_NO_TLSv1_1)) - version = TLS1_VERSION; - if (!(options & SSL_OP_NO_SSLv3) && (options & SSL_OP_NO_TLSv1)) - version = SSL3_VERSION; - } - - return version; - } - int ssl3_send_client_hello(SSL *s) { unsigned char *buf; @@ -816,22 +773,16 @@ int ssl3_get_server_hello(SSL *s) if (s->method->version == DTLS_ANY_VERSION) { - /* Work out correct protocol version to use */ - int options = s->options; - if (server_version == DTLS1_2_VERSION - && !(options & SSL_OP_NO_DTLSv1_2)) - s->method = DTLSv1_2_client_method(); - else if (server_version == DTLS1_VERSION - && !(options & SSL_OP_NO_DTLSv1)) - s->method = DTLSv1_client_method(); - else + if (!ssl3_is_version_enabled(s, server_version)) { OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_WRONG_SSL_VERSION); s->version = server_version; al = SSL_AD_PROTOCOL_VERSION; goto f_err; } - s->version = s->method->version; + s->version = server_version; + s->method = ssl3_get_method(server_version); + assert(s->method != NULL); } if (server_version != s->version) diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 86e87440c..8a204cecd 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -854,25 +854,17 @@ int ssl3_get_client_hello(SSL *s) if (s->method->version == DTLS_ANY_VERSION) { /* Select version to use */ - if (s->client_version <= DTLS1_2_VERSION && - !(s->options & SSL_OP_NO_DTLSv1_2)) - { - s->version = DTLS1_2_VERSION; - s->method = DTLSv1_2_server_method(); - } - else if (s->client_version <= DTLS1_VERSION && - !(s->options & SSL_OP_NO_DTLSv1)) - { - s->version = DTLS1_VERSION; - s->method = DTLSv1_server_method(); - } - else + uint16_t version = ssl3_get_mutual_version(s, client_version); + if (version == 0) { OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_WRONG_VERSION_NUMBER); s->version = s->client_version; al = SSL_AD_PROTOCOL_VERSION; goto f_err; } + s->version = version; + s->method = ssl3_get_method(version); + assert(s->method != NULL); } } diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 61c8dc999..0456cf6ad 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -1498,7 +1498,9 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs) /* Check for FALLBACK_SCSV. */ if (s->s3 && cipher_suite == (SSL3_CK_FALLBACK_SCSV & 0xffff)) { - if (s->version < ssl_get_max_version(s)) + uint16_t max_version = ssl3_get_max_server_version(s); + if (SSL_IS_DTLS(s) ? (uint16_t)s->version > max_version + : (uint16_t)s->version < max_version) { OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, SSL_R_INAPPROPRIATE_FALLBACK); ssl3_send_alert(s, SSL3_AL_FATAL, SSL3_AD_INAPPROPRIATE_FALLBACK); @@ -3046,13 +3048,37 @@ int ssl3_can_cutthrough(const SSL *s) return 1; } -/* ssl_get_max_version returns the maximum SSL/TLS version number supported by - * |s|, or zero if all versions are disabled. */ -int ssl_get_max_version(const SSL *s) +const SSL_METHOD *ssl3_get_method(uint16_t version) { - /* Only one version supported for DTLS. */ - if (s->version == DTLS1_VERSION) - return DTLS1_VERSION; + switch (version) + { + case SSL3_VERSION: + return SSLv3_method(); + case TLS1_VERSION: + return TLSv1_method(); + case TLS1_1_VERSION: + return TLSv1_1_method(); + case TLS1_2_VERSION: + return TLSv1_2_method(); + case DTLS1_VERSION: + return DTLSv1_method(); + case DTLS1_2_VERSION: + return DTLSv1_2_method(); + default: + return NULL; + } + } + +uint16_t ssl3_get_max_server_version(const SSL *s) + { + if (SSL_IS_DTLS(s)) + { + if (!(s->options & SSL_OP_NO_DTLSv1_2)) + return DTLS1_2_VERSION; + if (!(s->options & SSL_OP_NO_DTLSv1)) + return DTLS1_VERSION; + return 0; + } if (!(s->options & SSL_OP_NO_TLSv1_2)) return TLS1_2_VERSION; @@ -3065,6 +3091,105 @@ int ssl_get_max_version(const SSL *s) return 0; } +uint16_t ssl3_get_mutual_version(SSL *s, uint16_t client_version) + { + if (SSL_IS_DTLS(s)) + { + if (client_version <= DTLS1_2_VERSION && !(s->options & SSL_OP_NO_DTLSv1_2)) + return DTLS1_2_VERSION; + if (client_version <= DTLS1_VERSION && !(s->options & SSL_OP_NO_DTLSv1)) + return DTLS1_VERSION; + return 0; + } + else + { + if (client_version >= TLS1_2_VERSION && !(s->options & SSL_OP_NO_TLSv1_2)) + return TLS1_2_VERSION; + if (client_version >= TLS1_1_VERSION && !(s->options & SSL_OP_NO_TLSv1_1)) + return TLS1_1_VERSION; + if (client_version >= TLS1_VERSION && !(s->options & SSL_OP_NO_TLSv1)) + return TLS1_VERSION; + if (client_version >= SSL3_VERSION && !(s->options & SSL_OP_NO_SSLv3)) + return SSL3_VERSION; + return 0; + } + } + +uint16_t ssl3_get_max_client_version(SSL *s) + { + unsigned long options = s->options; + uint16_t version = 0; + + /* OpenSSL's API for controlling versions entails blacklisting + * individual protocols. This has two problems. First, on the client, + * the protocol can only express a contiguous range of versions. Second, + * a library consumer trying to set a maximum version cannot disable + * protocol versions that get added in a future version of the library. + * + * To account for both of these, OpenSSL interprets the client-side + * bitmask as a min/max range by picking the lowest contiguous non-empty + * range of enabled protocols. Note that this means it is impossible to + * set a maximum version of TLS 1.2 in a future-proof way. + * + * By this scheme, the maximum version is the lowest version V such that + * V is enabled and V+1 is disabled or unimplemented. + * + * TODO(davidben): Deprecate this API in favor of more sensible + * min_version/max_version settings. */ + if (SSL_IS_DTLS(s)) + { + if (!(options & SSL_OP_NO_DTLSv1_2)) + version = DTLS1_2_VERSION; + if (!(options & SSL_OP_NO_DTLSv1) && (options & SSL_OP_NO_DTLSv1_2)) + version = DTLS1_VERSION; + } + else + { + if (!(options & SSL_OP_NO_TLSv1_2)) + version = TLS1_2_VERSION; + if (!(options & SSL_OP_NO_TLSv1_1) && (options & SSL_OP_NO_TLSv1_2)) + version = TLS1_1_VERSION; + if (!(options & SSL_OP_NO_TLSv1) && (options & SSL_OP_NO_TLSv1_1)) + version = TLS1_VERSION; + if (!(options & SSL_OP_NO_SSLv3) && (options & SSL_OP_NO_TLSv1)) + version = SSL3_VERSION; + } + + return version; + } + +int ssl3_is_version_enabled(SSL *s, uint16_t version) + { + if (SSL_IS_DTLS(s)) + { + switch (version) + { + case DTLS1_VERSION: + return !(s->options & SSL_OP_NO_DTLSv1); + case DTLS1_2_VERSION: + return !(s->options & SSL_OP_NO_DTLSv1_2); + default: + return 0; + } + } + else + { + switch (version) + { + case SSL3_VERSION: + return !(s->options & SSL_OP_NO_SSLv3); + case TLS1_VERSION: + return !(s->options & SSL_OP_NO_TLSv1); + case TLS1_1_VERSION: + return !(s->options & SSL_OP_NO_TLSv1_1); + case TLS1_2_VERSION: + return !(s->options & SSL_OP_NO_TLSv1_2); + default: + return 0; + } + } + } + /* Allocates new EVP_MD_CTX and sets pointer to it into given pointer * vairable, freeing EVP_MD_CTX previously stored in that variable, if * any. If EVP_MD pointer is passed, initializes ctx with this md diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 1c8137068..9940eb076 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -929,13 +929,6 @@ unsigned int dtls1_min_mtu(void); void dtls1_hm_fragment_free(hm_fragment *frag); /* some client-only functions */ - -/* ssl3_get_max_client_version returns the maximum protocol version configured - * for the client. It is guaranteed that the set of allowed versions at or below - * this maximum version is contiguous. If all versions are disabled, it returns - * zero. */ -uint16_t ssl3_get_max_client_version(SSL *s); - int ssl3_send_client_hello(SSL *s); int ssl3_get_server_hello(SSL *s); int ssl3_get_certificate_request(SSL *s); @@ -1078,7 +1071,30 @@ int ssl_ctx_log_master_secret(SSL_CTX *ctx, const uint8_t *master, size_t master_len); int ssl3_can_cutthrough(const SSL *s); -int ssl_get_max_version(const SSL *s); + +/* ssl3_get_method returns the version-locked SSL_METHOD corresponding + * to |version|. */ +const SSL_METHOD *ssl3_get_method(uint16_t version); + +/* ssl3_get_max_server_version returns the maximum SSL/TLS version number + * supported by |s| as a server, or zero if all versions are disabled. */ +uint16_t ssl3_get_max_server_version(const SSL *s); + +/* ssl3_get_mutual_version selects the protocol version on |s| for a client + * which advertises |client_version|. If no suitable version exists, it returns + * zero. */ +uint16_t ssl3_get_mutual_version(SSL *s, uint16_t client_version); + +/* ssl3_get_max_client_version returns the maximum protocol version configured + * for the client. It is guaranteed that the set of allowed versions at or below + * this maximum version is contiguous. If all versions are disabled, it returns + * zero. */ +uint16_t ssl3_get_max_client_version(SSL *s); + +/* ssl3_is_version_enabled returns one if |version| is an enabled protocol + * version for |s| and zero otherwise. */ +int ssl3_is_version_enabled(SSL *s, uint16_t version); + EVP_MD_CTX* ssl_replace_hash(EVP_MD_CTX **hash,const EVP_MD *md) ; void ssl_clear_hash_ctx(EVP_MD_CTX **hash); int ssl_add_serverhello_renegotiate_ext(SSL *s, unsigned char *p, int *len,