summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2018-02-28 12:41:40 +0100
committerNikos Mavrogiannopoulos <nmav@redhat.com>2018-03-08 12:56:32 +0100
commit02354f173e66df3dad4ac9447e4965aecfad65e8 (patch)
treef608358522d46cd12484f0a0fa71e19ad4f6acef
parent90c4f5c1c4a4ec7bce1db01447df2727407cba3f (diff)
downloadgnutls-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>
-rw-r--r--lib/ext/supported_versions.c63
-rw-r--r--lib/handshake.c378
-rw-r--r--lib/handshake.h2
-rw-r--r--lib/includes/gnutls/gnutls.h.in21
-rw-r--r--lib/sslv2_compat.c2
-rw-r--r--tests/tls13/ext-parse.h20
-rw-r--r--tests/tls13/prf.c12
-rw-r--r--tests/tls13/supported_versions.c10
8 files changed, 307 insertions, 201 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;
diff --git a/tests/tls13/ext-parse.h b/tests/tls13/ext-parse.h
index 5b9f5b868f..ff8a200768 100644
--- a/tests/tls13/ext-parse.h
+++ b/tests/tls13/ext-parse.h
@@ -107,39 +107,29 @@ static unsigned find_client_extension(const gnutls_datum_t *msg, unsigned extnr,
static unsigned find_server_extension(const gnutls_datum_t *msg, unsigned extnr, void *priv, ext_parse_func cb)
{
- unsigned tls13 = 0;
unsigned pos = 0;
success("server hello of %d bytes\n", msg->size);
/* we expect the legacy version to be present */
/* ProtocolVersion legacy_version = 0x0303 */
-#ifdef TLS13_FINAL_VERSION
- if (msg->data[0] != 0x03) {
-#else
- if (msg->data[0] != 0x7f) {
-#endif
+ if (msg->data[0] != 0x03 || msg->data[1] != 0x03) {
fail("ProtocolVersion contains %d.%d\n", (int)msg->data[0], (int)msg->data[1]);
}
if (msg->data[1] >= 0x04) {
success("assuming TLS 1.3 or better hello format (seen %d.%d)\n", (int)msg->data[0], (int)msg->data[1]);
- tls13 = 1;
}
pos += 2+TLS_RANDOM_SIZE;
- if (!tls13) {
- /* legacy_session_id */
- SKIP8(pos, msg->size);
- }
+ /* legacy_session_id */
+ SKIP8(pos, msg->size);
/* CipherSuite */
pos += 2;
- if (!tls13) {
- /* legacy_compression_methods */
- SKIP8(pos, msg->size);
- }
+ /* legacy_compression_methods */
+ SKIP8(pos, msg->size);
pos += 2;
diff --git a/tests/tls13/prf.c b/tests/tls13/prf.c
index 52b88851b8..762dddc15c 100644
--- a/tests/tls13/prf.c
+++ b/tests/tls13/prf.c
@@ -131,13 +131,13 @@ static void check_prfs(gnutls_session_t session)
unsigned char key_material[512];
int ret;
- TRY_OLD(13, "key expansion", 34, (uint8_t*)"\xd9\x09\xfa\x31\x2e\x2b\x79\x58\x3f\xde\x89\xd4\x41\xec\x2e\x62\xfd\x31\xaf\x7f\x62\xc4\x1c\xcc\x17\x6d\x0b\x30\x80\x62\x20\xb1\x52\x07");
- TRY_OLD(6, "hello", 31, (uint8_t*)"\x37\xa3\xba\xd9\x7d\x2a\x2b\xd0\x7a\x7a\x01\xde\x0a\x95\xe8\x88\x1a\xbb\x21\xa2\x7d\xa8\x12\xeb\xfd\x22\xed\x32\xc5\xa0\x19");
+ TRY_OLD(13, "key expansion", 34, (uint8_t*)"\xac\x43\xa8\x49\x8f\x36\x3b\xbd\xcb\x3f\x45\x20\xac\xd5\x99\xf5\x4c\x92\x2a\x4d\xd6\x0b\xc2\x3f\xc2\xfe\xf3\xc7\x9e\x04\x70\xd3\xe1\x92");
+ TRY_OLD(6, "hello", 31, (uint8_t*)"\x49\x74\x07\x6f\x2c\xed\xfa\xff\xda\xe8\x20\x1f\xc7\xce\xe7\x78\x66\xb9\x75\x3f\x5d\x6e\xb0\xa9\xb8\xb2\x46\xd1\xa1\xd6\x39");
- TRY(13, "key expansion", 0, NULL, 34, (uint8_t*)"\xd9\x09\xfa\x31\x2e\x2b\x79\x58\x3f\xde\x89\xd4\x41\xec\x2e\x62\xfd\x31\xaf\x7f\x62\xc4\x1c\xcc\x17\x6d\x0b\x30\x80\x62\x20\xb1\x52\x07");
- TRY(6, "hello", 0, NULL, 31, (uint8_t*)"\x37\xa3\xba\xd9\x7d\x2a\x2b\xd0\x7a\x7a\x01\xde\x0a\x95\xe8\x88\x1a\xbb\x21\xa2\x7d\xa8\x12\xeb\xfd\x22\xed\x32\xc5\xa0\x19");
- TRY(7, "context", 5, "abcd\xfa", 31, (uint8_t*)"\xac\x1a\x0f\x82\xd2\x97\xac\xc1\xd0\x2e\x90\xda\xcd\x70\x27\x97\xc0\x00\xf8\x8f\x9b\xa3\x0f\x22\x62\xee\x83\x55\xd9\x19\xa2");
- TRY(12, "null-context", 0, "", 31, (uint8_t*)"\x0d\xe3\xec\xd7\x82\x69\xe8\x38\xc5\xb9\x6d\x6f\xa8\x8b\xb7\xe8\x35\xd8\xfd\xfd\x63\x9d\x86\xfc\xf0\x49\x73\x0d\x26\xc9\xd7");
+ TRY(13, "key expansion", 0, NULL, 34, (uint8_t*)"\xac\x43\xa8\x49\x8f\x36\x3b\xbd\xcb\x3f\x45\x20\xac\xd5\x99\xf5\x4c\x92\x2a\x4d\xd6\x0b\xc2\x3f\xc2\xfe\xf3\xc7\x9e\x04\x70\xd3\xe1\x92");
+ TRY(6, "hello", 0, NULL, 31, (uint8_t*)"\x49\x74\x07\x6f\x2c\xed\xfa\xff\xda\xe8\x20\x1f\xc7\xce\xe7\x78\x66\xb9\x75\x3f\x5d\x6e\xb0\xa9\xb8\xb2\x46\xd1\xa1\xd6\x39");
+ TRY(7, "context", 5, "abcd\xfa", 31, (uint8_t*)"\x0a\xa9\x28\xc7\x00\xf9\x49\xe8\x5a\xd0\xb8\x68\xba\x49\xd6\x04\x78\x61\x0b\xac\x45\xe3\xfb\x9c\x82\x94\x23\x24\xa4\x02\x8e");
+ TRY(12, "null-context", 0, "", 31, (uint8_t*)"\xb1\xfa\x57\x28\x1a\x57\x20\xfd\x73\xed\xdd\xda\xf4\xf8\x9b\xec\x4d\xf5\x2d\x23\xd5\xe3\xd3\x77\x89\xeb\x54\xdd\x0e\x17\x49");
/* Try whether calling gnutls_prf() with non-null context or server-first
* param, will fail */
diff --git a/tests/tls13/supported_versions.c b/tests/tls13/supported_versions.c
index 31eb4ddbb6..ca55cf9862 100644
--- a/tests/tls13/supported_versions.c
+++ b/tests/tls13/supported_versions.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 Red Hat, Inc.
+ * Copyright (C) 2017-2018 Red Hat, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
@@ -152,12 +152,8 @@ static int client_hello_callback(gnutls_session_t session, unsigned int htype,
success("server hello:\n\t%d.%d\n",
(int)msg->data[pos], (int)msg->data[pos+1]);
-#ifdef TLS13_FINAL_VERSION
- if (msg->data[pos] != 0x03 || msg->data[pos+1] != 0x04) {
-#else
- if (msg->data[pos] != 0x7f || msg->data[pos+1] != 21) {
-#endif
- fail("fail expected TLS 1.3 in server hello, got %d.%d\n", (int)msg->data[pos], (int)msg->data[pos+1]);
+ if (msg->data[pos] != 0x03 || msg->data[pos+1] != 0x03) {
+ fail("fail expected TLS 1.2 in server hello, got %d.%d\n", (int)msg->data[pos], (int)msg->data[pos+1]);
}
server_hello_ok = 1;