diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2018-02-28 12:41:40 +0100 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2018-03-08 12:56:32 +0100 |
commit | 02354f173e66df3dad4ac9447e4965aecfad65e8 (patch) | |
tree | f608358522d46cd12484f0a0fa71e19ad4f6acef /lib | |
parent | 90c4f5c1c4a4ec7bce1db01447df2727407cba3f (diff) | |
download | gnutls-02354f173e66df3dad4ac9447e4965aecfad65e8.tar.gz |
Server hello format follows TLS1.2 format
Also version negotiation was moved to supported_versions extension,
and session ID is set by client following appendix D.4.
This is a draft-ietf-tls-tls13-22 change.
Resolves #393, #389, #397
Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/ext/supported_versions.c | 63 | ||||
-rw-r--r-- | lib/handshake.c | 378 | ||||
-rw-r--r-- | lib/handshake.h | 2 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 21 | ||||
-rw-r--r-- | lib/sslv2_compat.c | 2 |
5 files changed, 293 insertions, 173 deletions
diff --git a/lib/ext/supported_versions.c b/lib/ext/supported_versions.c index deca74039d..c7fc82d8d9 100644 --- a/lib/ext/supported_versions.c +++ b/lib/ext/supported_versions.c @@ -29,6 +29,7 @@ #include "num.h" #include <hello_ext.h> #include <ext/supported_versions.h> +#include "handshake.h" static int supported_versions_recv_params(gnutls_session_t session, const uint8_t * data, @@ -40,8 +41,8 @@ const hello_ext_entry_st ext_mod_supported_versions = { .name = "Supported Versions", .tls_id = 43, .gid = GNUTLS_EXTENSION_SUPPORTED_VERSIONS, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO, - .parse_type = GNUTLS_EXT_MANDATORY, /* force parsing prior to EXT_TLS extensions */ + .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO|GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO, + .parse_type = GNUTLS_EXT_VERSION_NEG, /* force parsing prior to EXT_TLS extensions */ .recv_func = supported_versions_recv_params, .send_func = supported_versions_send_params, @@ -99,10 +100,32 @@ supported_versions_recv_params(gnutls_session_t session, /* if we are here, none of the versions were acceptable */ return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); - } else { - /* a server should never send this message */ - gnutls_assert(); - return GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION; + } else { /* client */ + const version_entry_st *vers; + + DECR_LEN(data_size, 2); + + if (data_size != 0) + return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); + + major = data[0]; + minor = data[1]; + + vers = nversion_to_entry(major, minor); + if (!vers) + return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); + + set_adv_version(session, major, minor); + proto = _gnutls_version_get(major, minor); + + _gnutls_handshake_log("EXT[%p]: Negotiated version: %d.%d\n", + session, (int)major, (int)minor); + + ret = _gnutls_negotiate_version(session, proto, major, minor); + if (ret < 0) { + gnutls_assert(); + return ret; + } } return 0; @@ -116,10 +139,18 @@ supported_versions_send_params(gnutls_session_t session, { uint8_t versions[32]; size_t versions_size; + const version_entry_st *vers; int ret; /* this function sends the client extension data (dnsname) */ if (session->security_parameters.entity == GNUTLS_CLIENT) { + vers = _gnutls_version_max(session); + + /* do not advertise this extension when we haven't TLS1.3 + * enabled. */ + if (vers && !vers->tls13_sem) + return 0; + ret = _gnutls_write_supported_versions(session, versions, sizeof(versions)); if (ret <= 0) /* if this function doesn't succeed do not send anything */ return 0; @@ -131,6 +162,26 @@ supported_versions_send_params(gnutls_session_t session, return gnutls_assert_val(ret); return versions_size+2; + } else { + vers = get_version(session); + if (unlikely(vers == NULL)) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + + /* don't use this extension to negotiate versions <= 1.2, + * pretend we don't support it, so that we use a single + * code path to negotiate these protocols. */ + if (!vers->tls13_sem) + return 0; + + ret = _gnutls_buffer_append_data(extdata, &vers->major, 1); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = _gnutls_buffer_append_data(extdata, &vers->minor, 1); + if (ret < 0) + return gnutls_assert_val(ret); + + return 2; } return 0; diff --git a/lib/handshake.c b/lib/handshake.c index 9b3fe6f648..d96d21cce6 100644 --- a/lib/handshake.c +++ b/lib/handshake.c @@ -422,14 +422,15 @@ _gnutls_finished(gnutls_session_t session, int type, void *ret, /* returns the 0 on success or a negative error code. */ int -_gnutls_negotiate_legacy_version(gnutls_session_t session, +_gnutls_negotiate_version(gnutls_session_t session, gnutls_protocol_t adv_version, uint8_t major, uint8_t minor) { const version_entry_st *vers; /* if we do not support that version, unless that version is TLS 1.2; * TLS 1.2 is handled separately because it is always advertized under TLS 1.3 or later */ - if (adv_version == GNUTLS_VERSION_UNKNOWN || _gnutls_version_is_supported(session, adv_version) == 0) { + if (adv_version == GNUTLS_VERSION_UNKNOWN || + _gnutls_version_is_supported(session, adv_version) == 0) { if (adv_version == GNUTLS_TLS1_2) { vers = _gnutls_version_max(session); @@ -477,6 +478,7 @@ _gnutls_user_hello_func(gnutls_session_t session, gnutls_protocol_t adv_version, uint8_t major, uint8_t minor) { int ret, sret = 0; + const version_entry_st *vers; if (session->internals.user_hello_func != NULL) { ret = session->internals.user_hello_func(session); @@ -489,13 +491,18 @@ _gnutls_user_hello_func(gnutls_session_t session, return ret; } - /* Here we need to renegotiate the version since the callee might - * have disabled some TLS versions. - */ - ret = _gnutls_negotiate_legacy_version(session, adv_version, major, minor); - if (ret < 0) { - gnutls_assert(); - return ret; + vers = get_version(session); + if (!vers->tls13_sem) { + /* Here we need to renegotiate the version since the callee might + * have disabled some TLS versions. We only do it for TLS1.2 or + * earlier, as TLS1.3 uses a different set of ciphersuites, and + * thus we cannot fallback. + */ + ret = _gnutls_negotiate_version(session, adv_version, major, minor); + if (ret < 0) { + gnutls_assert(); + return ret; + } } } return sret; @@ -519,6 +526,7 @@ read_client_hello(gnutls_session_t session, uint8_t * data, int len = datalen; uint8_t major, minor; uint8_t *suite_ptr, *comp_ptr, *session_id, *ext_ptr; + const version_entry_st *vers; DECR_LEN(len, 2); _gnutls_handshake_log("HSK[%p]: Client's version: %d.%d\n", @@ -530,7 +538,7 @@ read_client_hello(gnutls_session_t session, uint8_t * data, minor = data[pos+1]; set_adv_version(session, major, minor); - neg_version = _gnutls_negotiate_legacy_version(session, adv_version, major, minor); + neg_version = _gnutls_negotiate_version(session, adv_version, major, minor); if (neg_version < 0) { gnutls_assert(); return neg_version; @@ -598,46 +606,64 @@ read_client_hello(gnutls_session_t session, uint8_t * data, ext_ptr = &data[pos]; ext_size = len; - /* Parse only the mandatory to read extensions for resumption. - * We don't want to parse any other extensions since - * we don't want new extension values to override the - * resumed ones. - */ + /* Parse only the mandatory to read extensions for resumption + * and version negotiation. We don't want to parse any other + * extensions since we don't want new extension values to override + * the resumed ones. */ ret = _gnutls_parse_hello_extensions(session, GNUTLS_EXT_FLAG_CLIENT_HELLO, - GNUTLS_EXT_MANDATORY, - ext_ptr, ext_size); - if (ret < 0) { - gnutls_assert(); - return ret; - } + GNUTLS_EXT_VERSION_NEG, + ext_ptr, ext_size); + if (ret < 0) + return gnutls_assert_val(ret); ret = - _gnutls_server_restore_session(session, session_id, - session_id_len); + _gnutls_parse_hello_extensions(session, GNUTLS_EXT_FLAG_CLIENT_HELLO, + GNUTLS_EXT_MANDATORY, + ext_ptr, ext_size); + if (ret < 0) + return gnutls_assert_val(ret); - if (session_id_len > 0) - session->internals.resumption_requested = 1; + vers = get_version(session); + if (unlikely(vers == NULL)) + return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); - if (ret == 0) { /* resumed using default TLS resumption! */ - ret = _gnutls_server_select_suite(session, suite_ptr, suite_size, 1); - if (ret < 0) - return gnutls_assert_val(ret); + if (!vers->tls13_sem) { + ret = + _gnutls_server_restore_session(session, session_id, + session_id_len); - ret = resume_copy_required_values(session); - if (ret < 0) - return gnutls_assert_val(ret); + if (session_id_len > 0) + session->internals.resumption_requested = 1; + + if (ret == 0) { /* resumed using default TLS resumption! */ + ret = _gnutls_server_select_suite(session, suite_ptr, suite_size, 1); + if (ret < 0) + return gnutls_assert_val(ret); - session->internals.resumed = RESUME_TRUE; + ret = resume_copy_required_values(session); + if (ret < 0) + return gnutls_assert_val(ret); - return _gnutls_user_hello_func(session, adv_version, major, minor); - } else { - _gnutls_generate_session_id(session->security_parameters. - session_id, - &session->security_parameters. - session_id_size); + session->internals.resumed = RESUME_TRUE; - session->internals.resumed = RESUME_FALSE; + return _gnutls_user_hello_func(session, adv_version, major, minor); + } else { + ret = _gnutls_generate_session_id(session->security_parameters. + session_id, + &session->security_parameters. + session_id_size); + if (ret < 0) + return gnutls_assert_val(ret); + + session->internals.resumed = RESUME_FALSE; + } + } else { /* TLS1.3 */ + /* we echo client's session ID - length was checked previously */ + assert(session_id_len <= GNUTLS_MAX_SESSION_ID_SIZE); + if (session_id_len > 0) + memcpy(session->security_parameters.session_id, session_id, session_id_len); + session->security_parameters.session_id_size = session_id_len; } /* Parse the extensions (if any) @@ -646,8 +672,8 @@ read_client_hello(gnutls_session_t session, uint8_t * data, * sslv3 and higher, even though sslv3 doesn't officially support them. */ ret = _gnutls_parse_hello_extensions(session, GNUTLS_EXT_FLAG_CLIENT_HELLO, - GNUTLS_EXT_APPLICATION, - ext_ptr, ext_size); + GNUTLS_EXT_APPLICATION, + ext_ptr, ext_size); /* len is the rest of the parsed length */ if (ret < 0) { gnutls_assert(); @@ -664,7 +690,7 @@ read_client_hello(gnutls_session_t session, uint8_t * data, /* Session tickets are parsed in this point */ ret = _gnutls_parse_hello_extensions(session, GNUTLS_EXT_FLAG_CLIENT_HELLO, - GNUTLS_EXT_TLS, ext_ptr, ext_size); + GNUTLS_EXT_TLS, ext_ptr, ext_size); if (ret < 0) { gnutls_assert(); return ret; @@ -1562,7 +1588,7 @@ set_client_ciphersuite(gnutls_session_t session, uint8_t suite[2]) /* This function returns 0 if we are resuming a session or -1 otherwise. * This also sets the variables in the session. Used only while reading a server - * hello. + * hello. Only applicable to TLS1.2 or earlier. */ static int client_check_if_resuming(gnutls_session_t session, @@ -1611,13 +1637,6 @@ client_check_if_resuming(gnutls_session_t session, no_resume: /* keep the new session id */ session->internals.resumed = RESUME_FALSE; /* we are not resuming */ - session->security_parameters.session_id_size = - session_id_len; - if (session_id_len > 0) { - memcpy(session->security_parameters.session_id, session_id, - session_id_len); - } - return -1; } } @@ -1632,11 +1651,14 @@ read_server_hello(gnutls_session_t session, uint8_t * data, int datalen) { uint8_t session_id_len = 0; + uint8_t *session_id; + uint8_t *cs_pos, *comp_pos, *srandom_pos; + uint8_t major, minor; int pos = 0; int ret = 0; int len = datalen; + unsigned ext_parse_flag = 0; const version_entry_st *vers; - gnutls_ext_flags_t ext_parse_flag; if (datalen < GNUTLS_RANDOM_SIZE+2) { gnutls_assert(); @@ -1647,14 +1669,15 @@ read_server_hello(gnutls_session_t session, session, data[pos], data[pos + 1]); DECR_LEN(len, 2); - vers = nversion_to_entry(data[pos], data[pos + 1]); + major = data[pos]; + minor = data[pos+1]; + + vers = nversion_to_entry(major, minor); if (unlikely(vers == NULL)) return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); - if (_gnutls_version_is_supported(session, vers->id) == 0) { - gnutls_assert(); - return GNUTLS_E_UNSUPPORTED_VERSION_PACKET; - } + if (vers->tls13_sem) /* that shouldn't have been negotiated here */ + return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); if (_gnutls_set_current_version(session, vers->id) < 0) return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); @@ -1662,64 +1685,96 @@ read_server_hello(gnutls_session_t session, pos += 2; DECR_LEN(len, GNUTLS_RANDOM_SIZE); - ret = _gnutls_set_server_random(session, vers, &data[pos]); + srandom_pos = &data[pos]; + pos += GNUTLS_RANDOM_SIZE; + + /* Read session ID + */ + DECR_LEN(len, 1); + session_id_len = data[pos++]; + + if (len < session_id_len || session_id_len > GNUTLS_MAX_SESSION_ID_SIZE) { + gnutls_assert(); + return GNUTLS_E_ILLEGAL_PARAMETER; + } + DECR_LEN(len, session_id_len); + session_id = &data[pos]; + pos += session_id_len; + + DECR_LEN(len, 2); + cs_pos = &data[pos]; + pos += 2; + + /* move to compression + */ + DECR_LEN(len, 1); + comp_pos = &data[pos]; + pos++; + + /* parse extensions to figure version */ + ret = + _gnutls_parse_hello_extensions(session, GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO| + GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO, + GNUTLS_EXT_VERSION_NEG, + &data[pos], len); if (ret < 0) return gnutls_assert_val(ret); - pos += GNUTLS_RANDOM_SIZE; + vers = get_version(session); + if (unlikely(vers == NULL)) + return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); + if (vers->tls13_sem) { + if (major != 0x03 || minor != 0x03) + return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); + } - if (!vers->tls13_sem) { - /* Read session ID - */ - DECR_LEN(len, 1); - session_id_len = data[pos++]; + if (_gnutls_version_is_supported(session, vers->id) == 0) + return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); - if (len < session_id_len || session_id_len > GNUTLS_MAX_SESSION_ID_SIZE) { - gnutls_assert(); - return GNUTLS_E_ILLEGAL_PARAMETER; - } - DECR_LEN(len, session_id_len); + /* set server random - done after final version is selected */ + ret = _gnutls_set_server_random(session, vers, srandom_pos); + if (ret < 0) + return gnutls_assert_val(ret); - /* check if we are resuming and set the appropriate - * values; - */ - if (client_check_if_resuming - (session, &data[pos], session_id_len) == 0) { - pos += session_id_len + 2 + 1; - DECR_LEN(len, 2 + 1); + /* check if we are resuming and set the appropriate + * values; + */ + if (!vers->tls13_sem && + client_check_if_resuming(session, session_id, session_id_len) == 0) { - ret = - _gnutls_parse_hello_extensions(session, GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, - GNUTLS_EXT_MANDATORY, - &data[pos], len); - if (ret < 0) { - gnutls_assert(); - return ret; - } - return 0; - } + ret = + _gnutls_parse_hello_extensions(session, GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, + GNUTLS_EXT_MANDATORY, + &data[pos], len); + if (ret < 0) + return gnutls_assert_val(ret); - pos += session_id_len; + return 0; + } else { + session->security_parameters.session_id_size = session_id_len; + if (session_id_len > 0) + memcpy(session->security_parameters.session_id, session_id, + session_id_len); } /* Check if the given cipher suite is supported and copy * it to the session. */ - - DECR_LEN(len, 2); - ret = set_client_ciphersuite(session, &data[pos]); + ret = set_client_ciphersuite(session, cs_pos); if (ret < 0) { gnutls_assert(); return ret; } - pos += 2; if (session->internals.hsk_flags & HSK_HRR_RECEIVED) { /* check if ciphersuite matches */ - if (memcmp(session->security_parameters.cs->id, session->internals.hrr_cs, 2) != 0) + if (memcmp(cs_pos, session->internals.hrr_cs, 2) != 0) return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); } + if (*comp_pos != 0) + return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); + if (vers->tls13_sem) { /* TLS 1.3 Early Secret */ ret = _tls13_init_secret(session, NULL, 0); @@ -1732,46 +1787,42 @@ read_server_hello(gnutls_session_t session, if (ret < 0) return gnutls_assert_val(ret); - ext_parse_flag = GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO; + ext_parse_flag |= GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO; } else { - /* move to compression - */ - DECR_LEN(len, 1); - pos++; - ext_parse_flag = GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO; + ext_parse_flag |= GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO; } /* Parse extensions in order. */ ret = _gnutls_parse_hello_extensions(session, - ext_parse_flag, - GNUTLS_EXT_MANDATORY, - &data[pos], len); + ext_parse_flag, + GNUTLS_EXT_MANDATORY, + &data[pos], len); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_parse_hello_extensions(session, - ext_parse_flag, - GNUTLS_EXT_APPLICATION, - &data[pos], len); + ext_parse_flag, + GNUTLS_EXT_APPLICATION, + &data[pos], len); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_parse_hello_extensions(session, - ext_parse_flag, - GNUTLS_EXT_TLS, - &data[pos], len); + ext_parse_flag, + GNUTLS_EXT_TLS, + &data[pos], len); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_parse_hello_extensions(session, - ext_parse_flag, - _GNUTLS_EXT_TLS_POST_CS, - &data[pos], len); + ext_parse_flag, + _GNUTLS_EXT_TLS_POST_CS, + &data[pos], len); if (ret < 0) return gnutls_assert_val(ret); @@ -1806,7 +1857,7 @@ static int send_client_hello(gnutls_session_t session, int again) mbuffer_st *bufel = NULL; int type; int ret = 0; - const version_entry_st *hver, *min_ver; + const version_entry_st *hver, *min_ver, *max_ver; uint8_t tver[2]; gnutls_buffer_st extdata; int rehandshake = 0; @@ -1842,7 +1893,8 @@ static int send_client_hello(gnutls_session_t session, int again) if (hver == NULL) { gnutls_assert(); - return GNUTLS_E_NO_PRIORITIES_WERE_SET; + ret = GNUTLS_E_NO_PRIORITIES_WERE_SET; + goto cleanup; } if (unlikely(session->internals.default_hello_version[0] != 0)) { @@ -1861,7 +1913,8 @@ static int send_client_hello(gnutls_session_t session, int again) (unsigned)tver[0], (unsigned)tver[1]); min_ver = _gnutls_version_lowest(session); - if (min_ver == NULL) { + max_ver = _gnutls_version_max(session); + if (min_ver == NULL || max_ver == NULL) { gnutls_assert(); ret = GNUTLS_E_NO_PRIORITIES_WERE_SET; goto cleanup; @@ -1871,8 +1924,10 @@ static int send_client_hello(gnutls_session_t session, int again) * (RSA uses it). */ set_adv_version(session, hver->major, hver->minor); - if (_gnutls_set_current_version(session, hver->id) < 0) - return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); + if (_gnutls_set_current_version(session, hver->id) < 0) { + ret = gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); + goto cleanup; + } if (session->internals.priorities->min_record_version != 0) { /* Advertize the lowest supported (SSL 3.0) record packet @@ -1895,24 +1950,43 @@ static int send_client_hello(gnutls_session_t session, int again) if (!(session->internals.hsk_flags & HSK_HRR_RECEIVED) && !(IS_DTLS(session) && session->internals.dtls.hsk_hello_verify_requests == 0)) { ret = _gnutls_gen_client_random(session); - if (ret < 0) - return gnutls_assert_val(ret); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } } ret = _gnutls_buffer_append_data(&extdata, - session->security_parameters.client_random, - GNUTLS_RANDOM_SIZE); + session->security_parameters.client_random, + GNUTLS_RANDOM_SIZE); if (ret < 0) { gnutls_assert(); goto cleanup; } - /* Copy the Session ID +#ifdef TLS13_APPENDIX_D4 + if (max_ver->tls13_sem && + session->security_parameters.session_id_size == 0) { + + /* Under TLS1.3 we generate a random session ID to make + * the TLS1.3 session look like a resumed TLS1.2 session */ + ret = _gnutls_generate_session_id(session->security_parameters. + session_id, + &session->security_parameters. + session_id_size); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + } +#endif + + /* Copy the Session ID - if any */ ret = _gnutls_buffer_append_data_prefix(&extdata, 8, - session->internals.resumed_security_parameters.session_id, - session_id_len); + session->internals.resumed_security_parameters.session_id, + session_id_len); if (ret < 0) { gnutls_assert(); goto cleanup; @@ -1970,8 +2044,8 @@ static int send_client_hello(gnutls_session_t session, int again) ret = _gnutls_gen_hello_extensions(session, &extdata, - GNUTLS_EXT_FLAG_CLIENT_HELLO, - type); + GNUTLS_EXT_FLAG_CLIENT_HELLO, + type); if (ret < 0) { gnutls_assert(); goto cleanup; @@ -1999,7 +2073,8 @@ int _gnutls_send_server_hello(gnutls_session_t session, int again) session->security_parameters.session_id_size; char tmpbuf[2 * GNUTLS_MAX_SESSION_ID_SIZE + 1]; const version_entry_st *vers; - gnutls_ext_flags_t ext_parse_flag; + uint8_t vbytes[2]; + unsigned extflag = 0; _gnutls_buffer_init(&buf); @@ -2014,50 +2089,46 @@ int _gnutls_send_server_hello(gnutls_session_t session, int again) if (ret < 0) return gnutls_assert_val(ret); - ext_parse_flag = GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO; + vbytes[0] = 0x03; /* TLS1.2 */ + vbytes[1] = 0x03; + extflag |= GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO; } else { - ext_parse_flag = GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO; + vbytes[0] = vers->major; + vbytes[1] = vers->minor; + extflag |= GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO; } ret = _gnutls_buffer_init_handshake_mbuffer(&buf); if (ret < 0) return gnutls_assert_val(ret); - ret = _gnutls_buffer_append_data(&buf, &vers->major, 1); + ret = _gnutls_buffer_append_data(&buf, vbytes, 2); if (ret < 0) { gnutls_assert(); goto fail; } - ret = _gnutls_buffer_append_data(&buf, &vers->minor, 1); + ret = _gnutls_buffer_append_data(&buf, + session->security_parameters.server_random, + GNUTLS_RANDOM_SIZE); if (ret < 0) { gnutls_assert(); goto fail; } - ret = _gnutls_buffer_append_data(&buf, - session->security_parameters.server_random, - GNUTLS_RANDOM_SIZE); + ret = _gnutls_buffer_append_data_prefix(&buf, 8, + session->security_parameters.session_id, + session_id_len); if (ret < 0) { gnutls_assert(); goto fail; } - if (!vers->tls13_sem) { - ret = _gnutls_buffer_append_data_prefix(&buf, 8, - session->security_parameters.session_id, - session_id_len); - if (ret < 0) { - gnutls_assert(); - goto fail; - } - - _gnutls_handshake_log("HSK[%p]: SessionID: %s\n", session, - _gnutls_bin2hex(session-> - security_parameters.session_id, - session_id_len, tmpbuf, - sizeof(tmpbuf), NULL)); - } + _gnutls_handshake_log("HSK[%p]: SessionID: %s\n", session, + _gnutls_bin2hex(session-> + security_parameters.session_id, + session_id_len, tmpbuf, + sizeof(tmpbuf), NULL)); ret = _gnutls_buffer_append_data(&buf, session->security_parameters.cs->id, @@ -2067,17 +2138,16 @@ int _gnutls_send_server_hello(gnutls_session_t session, int again) goto fail; } - if (!vers->tls13_sem) { - ret = _gnutls_buffer_append_prefix(&buf, 8, 0); - if (ret < 0) { - gnutls_assert(); - goto fail; - } + /* compression */ + ret = _gnutls_buffer_append_prefix(&buf, 8, 0); + if (ret < 0) { + gnutls_assert(); + goto fail; } ret = _gnutls_gen_hello_extensions(session, &buf, - ext_parse_flag, + extflag, (session->internals.resumed == RESUME_TRUE) ? GNUTLS_EXT_MANDATORY : diff --git a/lib/handshake.h b/lib/handshake.h index 0084789bcd..1096226410 100644 --- a/lib/handshake.h +++ b/lib/handshake.h @@ -72,7 +72,7 @@ int _gnutls_find_pk_algos_in_ciphersuites(uint8_t * data, int datalen); int _gnutls_server_select_suite(gnutls_session_t session, uint8_t * data, unsigned int datalen, unsigned int scsv_only); -int _gnutls_negotiate_legacy_version(gnutls_session_t session, +int _gnutls_negotiate_version(gnutls_session_t session, gnutls_protocol_t adv_version, uint8_t major, uint8_t minor); int _gnutls_user_hello_func(gnutls_session_t session, gnutls_protocol_t adv_version, uint8_t major, uint8_t minor); diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index b9142519aa..37d90adfcf 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -2715,25 +2715,24 @@ int gnutls_ext_raw_parse(void *ctx, gnutls_ext_raw_process_func cb, /** * gnutls_ext_parse_type_t: - * @GNUTLS_EXT_NONE: Never parsed - * @GNUTLS_EXT_ANY: Any extension type (internal use only). - * @GNUTLS_EXT_APPLICATION: Application extension. - * @GNUTLS_EXT_TLS: TLS-internal extension. - * @GNUTLS_EXT_MANDATORY: Extension parsed even if resuming (or extensions are disabled). + * @GNUTLS_EXT_NONE: Never to be parsed + * @GNUTLS_EXT_ANY: Any extension type (should not be used as it is used only internally). + * @GNUTLS_EXT_VERSION_NEG: Extensions to be parsed first for TLS version negotiation. + * @GNUTLS_EXT_MANDATORY: Parsed after @GNUTLS_EXT_VERSION_NEG and even when resuming. + * @GNUTLS_EXT_APPLICATION: Parsed after @GNUTLS_EXT_MANDATORY + * @GNUTLS_EXT_TLS: TLS-internal extensions, parsed after @GNUTLS_EXT_APPLICATION. * - * Enumeration of different TLS extension parsing types. This type is - * to indicate whether an extension is useful to application - * level or TLS level only. This is used to decide the appropriate time - * each extension is parsed at during the server or client hello parsing. + * Enumeration of different TLS extension parsing phases. The @gnutls_ext_parse_type_t + * indicates the time/phase an extension is parsed during Client or Server hello parsing. * - * This applies to TLS 1.2 and earlier versions. */ typedef enum { GNUTLS_EXT_ANY = 0, GNUTLS_EXT_APPLICATION = 1, GNUTLS_EXT_TLS = 2, GNUTLS_EXT_MANDATORY = 3, - GNUTLS_EXT_NONE = 4 + GNUTLS_EXT_NONE = 4, + GNUTLS_EXT_VERSION_NEG = 5 } gnutls_ext_parse_type_t; /** diff --git a/lib/sslv2_compat.c b/lib/sslv2_compat.c index 882cbd628d..d466cc30f1 100644 --- a/lib/sslv2_compat.c +++ b/lib/sslv2_compat.c @@ -112,7 +112,7 @@ _gnutls_read_client_hello_v2(gnutls_session_t session, uint8_t * data, adv_version = _gnutls_version_get(major, minor); - ret = _gnutls_negotiate_legacy_version(session, adv_version, major, minor); + ret = _gnutls_negotiate_version(session, adv_version, major, minor); if (ret < 0) { gnutls_assert(); return ret; |