/* 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);
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);
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;
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",
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;
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)
* 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();
/* 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;
/* 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,
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;
}
}
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();
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);
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);
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);
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;
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)) {
(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;
* (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
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;
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;
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);
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,
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 :