summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2018-03-08 13:57:05 +0100
committerNikos Mavrogiannopoulos <nmav@redhat.com>2018-03-09 17:02:23 +0100
commit70db923871d9cdf17a458790e98708828f1e5b1c (patch)
tree92ae2b4091231ae3c6dc0d0bd848639cd47e1a6a
parent28e65c00ae7092c67f1fe0a86b87cd55a1d9a630 (diff)
downloadgnutls-70db923871d9cdf17a458790e98708828f1e5b1c.tar.gz
Hello retry request matches server hello
That also distinguishes between them by using the special random value, and implements the version check as in draft-ietf-tls-tls13-24. Resolves #391 #390 #392 Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
-rw-r--r--lib/buffers.c15
-rw-r--r--lib/ext/dumbfw.c2
-rw-r--r--lib/ext/supported_versions.c3
-rw-r--r--lib/gnutls_int.h11
-rw-r--r--lib/handshake.c12
-rw-r--r--lib/includes/gnutls/gnutls.h.in4
-rw-r--r--lib/tls13/hello_retry.c62
7 files changed, 89 insertions, 20 deletions
diff --git a/lib/buffers.c b/lib/buffers.c
index 414ea50307..52729f3723 100644
--- a/lib/buffers.c
+++ b/lib/buffers.c
@@ -900,17 +900,17 @@ parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel,
return
gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
- hsk->htype = GNUTLS_HANDSHAKE_CLIENT_HELLO_V2;
+ hsk->rtype = hsk->htype = GNUTLS_HANDSHAKE_CLIENT_HELLO_V2;
hsk->sequence = 0;
hsk->start_offset = 0;
hsk->end_offset = hsk->length;
} else
#endif
- { /* TLS or DTLS handshake headers */
+ { /* TLS or DTLS handshake headers */
- hsk->htype = dataptr[0];
+ hsk->rtype = hsk->htype = dataptr[0];
/* we do not use DECR_LEN because we know
* that the packet has enough data.
@@ -932,6 +932,15 @@ parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel,
MIN((_mbuffer_get_udata_size(bufel) -
handshake_header_size), hsk->length);
}
+
+ /* TLS1.3: distinguish server hello versus hello retry request.
+ * The epitome of slick protocol design. */
+ if (hsk->htype == GNUTLS_HANDSHAKE_SERVER_HELLO && hsk->start_offset == 0 && !IS_DTLS(session)) {
+ if (_mbuffer_get_udata_size(bufel) > handshake_header_size+2+GNUTLS_RANDOM_SIZE &&
+ memcmp(dataptr+handshake_header_size+2, HRR_RANDOM, GNUTLS_RANDOM_SIZE) == 0) {
+ hsk->htype = GNUTLS_HANDSHAKE_HELLO_RETRY_REQUEST;
+ }
+ }
}
data_size = _mbuffer_get_udata_size(bufel) - handshake_header_size;
diff --git a/lib/ext/dumbfw.c b/lib/ext/dumbfw.c
index 3ffeeca560..7faff65693 100644
--- a/lib/ext/dumbfw.c
+++ b/lib/ext/dumbfw.c
@@ -40,7 +40,7 @@ const hello_ext_entry_st ext_mod_dumbfw = {
.tls_id = 21,
.gid = GNUTLS_EXTENSION_DUMBFW,
.parse_type = GNUTLS_EXT_APPLICATION,
- .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_HRR,
+ .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO,
.recv_func = NULL,
.send_func = _gnutls_dumbfw_send_params,
diff --git a/lib/ext/supported_versions.c b/lib/ext/supported_versions.c
index c7fc82d8d9..b2eff6be80 100644
--- a/lib/ext/supported_versions.c
+++ b/lib/ext/supported_versions.c
@@ -41,7 +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|GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO|GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO,
+ .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO|
+ GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO|GNUTLS_EXT_FLAG_HRR,
.parse_type = GNUTLS_EXT_VERSION_NEG, /* force parsing prior to EXT_TLS extensions */
.recv_func = supported_versions_recv_params,
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index c4d8524a27..1d75c4a09f 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -134,6 +134,13 @@ typedef struct {
#define GNUTLS_MASTER_SIZE 48
#define GNUTLS_RANDOM_SIZE 32
+#define HRR_RANDOM \
+ "\xCF\x21\xAD\x74\xE5\x9A\x61\x11\xBE\x1D\x8C\x02\x1E\x65\xB8\x91" \
+ "\xC2\xA2\x11\x16\x7A\xBB\x8C\x5E\x07\x9E\x09\xE2\xC8\xA8\x33\x9C"
+
+/* Under TLS1.3 a hello retry request is sent as server hello */
+#define REAL_HSK_TYPE(t) ((t)==GNUTLS_HANDSHAKE_HELLO_RETRY_REQUEST?GNUTLS_HANDSHAKE_SERVER_HELLO:t)
+
/* Enable: Appendix D4. Middlebox Compatibility Mode */
#define TLS13_APPENDIX_D4 1
@@ -366,6 +373,10 @@ typedef enum content_type_t {
typedef struct {
/* Handshake layer type and sequence of message */
gnutls_handshake_description_t htype;
+
+ /* The "real" type received; that is, it does not distinguish
+ * HRR from server hello, while htype does */
+ gnutls_handshake_description_t rtype;
uint32_t length;
/* valid in DTLS */
diff --git a/lib/handshake.c b/lib/handshake.c
index d96d21cce6..955fd5dd08 100644
--- a/lib/handshake.c
+++ b/lib/handshake.c
@@ -1143,7 +1143,7 @@ _gnutls_send_handshake(gnutls_session_t session, mbuffer_st * bufel,
i_datasize = _mbuffer_get_udata_size(bufel);
datasize = i_datasize + _mbuffer_get_uhead_size(bufel);
- data[pos++] = (uint8_t) type;
+ data[pos++] = (uint8_t) REAL_HSK_TYPE(type);
_gnutls_write_uint24(_mbuffer_get_udata_size(bufel), &data[pos]);
pos += 3;
@@ -1389,7 +1389,7 @@ _gnutls_recv_handshake(gnutls_session_t session,
goto cleanup;
}
- ret = handshake_hash_add_recvd(session, hsk.htype,
+ ret = handshake_hash_add_recvd(session, hsk.rtype,
hsk.header, hsk.header_size,
hsk.data.data,
hsk.data.length);
@@ -1658,7 +1658,7 @@ read_server_hello(gnutls_session_t session,
int ret = 0;
int len = datalen;
unsigned ext_parse_flag = 0;
- const version_entry_st *vers;
+ const version_entry_st *vers, *saved_vers;
if (datalen < GNUTLS_RANDOM_SIZE+2) {
gnutls_assert();
@@ -1672,6 +1672,8 @@ read_server_hello(gnutls_session_t session,
major = data[pos];
minor = data[pos+1];
+ saved_vers = get_version(session); /* will be non-null if HRR has been received */
+
vers = nversion_to_entry(major, minor);
if (unlikely(vers == NULL))
return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET);
@@ -1770,6 +1772,10 @@ read_server_hello(gnutls_session_t session,
/* check if ciphersuite matches */
if (memcmp(cs_pos, session->internals.hrr_cs, 2) != 0)
return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
+ /* check if HRR version matches this version */
+ if (vers != saved_vers)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
}
if (*comp_pos != 0)
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index 976ba7322a..5b449d148c 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -534,7 +534,6 @@ typedef enum {
GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST = 3,
GNUTLS_HANDSHAKE_NEW_SESSION_TICKET = 4,
GNUTLS_HANDSHAKE_END_OF_EARLY_DATA = 5,
- GNUTLS_HANDSHAKE_HELLO_RETRY_REQUEST = 6,
GNUTLS_HANDSHAKE_ENCRYPTED_EXTENSIONS = 8,
GNUTLS_HANDSHAKE_CERTIFICATE_PKT = 11,
GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE = 12,
@@ -547,7 +546,8 @@ typedef enum {
GNUTLS_HANDSHAKE_SUPPLEMENTAL = 23,
GNUTLS_HANDSHAKE_KEY_UPDATE = 24,
GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC = 254,
- GNUTLS_HANDSHAKE_CLIENT_HELLO_V2 = 1024
+ GNUTLS_HANDSHAKE_CLIENT_HELLO_V2 = 1024,
+ GNUTLS_HANDSHAKE_HELLO_RETRY_REQUEST = 1025,
} gnutls_handshake_description_t;
#define GNUTLS_HANDSHAKE_ANY ((unsigned int)-1)
diff --git a/lib/tls13/hello_retry.c b/lib/tls13/hello_retry.c
index 59f965cd57..51f545ec00 100644
--- a/lib/tls13/hello_retry.c
+++ b/lib/tls13/hello_retry.c
@@ -34,6 +34,7 @@ int _gnutls13_send_hello_retry_request(gnutls_session_t session, unsigned again)
mbuffer_st *bufel = NULL;
gnutls_buffer_st buf;
const version_entry_st *ver;
+ const uint8_t vbuf[2] = {0x03, 0x03};
if (again == 0) {
ver = get_version(session);
@@ -44,11 +45,21 @@ int _gnutls13_send_hello_retry_request(gnutls_session_t session, unsigned again)
if (ret < 0)
return gnutls_assert_val(ret);
- ret = _gnutls_buffer_append_data(&buf, &ver->major, 1);
+ ret = _gnutls_buffer_append_data(&buf, vbuf, 2);
if (ret < 0)
return gnutls_assert_val(ret);
- ret = _gnutls_buffer_append_data(&buf, &ver->minor, 1);
+ ret = _gnutls_buffer_append_data(&buf,
+ HRR_RANDOM,
+ GNUTLS_RANDOM_SIZE);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = _gnutls_buffer_append_data_prefix(&buf, 8,
+ session->security_parameters.session_id,
+ session->security_parameters.session_id_size);
if (ret < 0) {
gnutls_assert();
goto cleanup;
@@ -60,6 +71,13 @@ int _gnutls13_send_hello_retry_request(gnutls_session_t session, unsigned again)
goto cleanup;
}
+ /* compression */
+ ret = _gnutls_buffer_append_prefix(&buf, 8, 0);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
ret = _gnutls_gen_hello_extensions(session, &buf,
GNUTLS_EXT_FLAG_HRR,
GNUTLS_EXT_ANY);
@@ -85,11 +103,12 @@ int
_gnutls13_recv_hello_retry_request(gnutls_session_t session,
gnutls_buffer_st *buf)
{
- const version_entry_st *vers;
int ret;
uint8_t tmp[2];
const gnutls_cipher_suite_entry_st *cs;
const mac_entry_st *prf;
+ gnutls_datum_t session_id;
+ uint8_t random[GNUTLS_RANDOM_SIZE];
/* only under TLS 1.3 */
if (IS_DTLS(session))
@@ -100,20 +119,27 @@ _gnutls13_recv_hello_retry_request(gnutls_session_t session,
session->internals.hsk_flags |= HSK_HRR_RECEIVED;
+ /* version */
ret = _gnutls_buffer_pop_data(buf, tmp, 2);
if (ret < 0)
return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
- vers = nversion_to_entry(tmp[0], tmp[1]);
- if (unlikely(vers == NULL))
+ if (unlikely(tmp[0] != 0x03 || tmp[1] != 0x03))
return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET);
- if (_gnutls_version_is_supported(session, vers->id) == 0)
- return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET);
+ ret = _gnutls_buffer_pop_data(buf, random, GNUTLS_RANDOM_SIZE);
+ if (ret < 0)
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
- if (_gnutls_set_current_version(session, vers->id) < 0)
- return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET);
+ if (memcmp(random, HRR_RANDOM, GNUTLS_RANDOM_SIZE) != 0) {
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+ }
+ ret = _gnutls_buffer_pop_datum_prefix8(buf, &session_id);
+ if (ret < 0)
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ /* read ciphersuites */
ret = _gnutls_buffer_pop_data(buf, tmp, 2);
if (ret < 0)
return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
@@ -123,13 +149,20 @@ _gnutls13_recv_hello_retry_request(gnutls_session_t session,
return gnutls_assert_val(GNUTLS_E_UNKNOWN_CIPHER_SUITE);
_gnutls_handshake_log("EXT[%p]: Hello Retry Request with %s\n", session, cs->name);
-
memcpy(session->internals.hrr_cs, cs->id, 2);
prf = mac_to_entry(cs->prf);
if (unlikely(prf == NULL))
return gnutls_assert_val(GNUTLS_E_UNKNOWN_CIPHER_SUITE);
+ /* compression */
+ ret = _gnutls_buffer_pop_data(buf, tmp, 1);
+ if (ret < 0)
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+
+ if (unlikely(tmp[0] != 0))
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+
ret = _gnutls13_handshake_hash_buffers_synth(session, prf, 1);
if (ret < 0)
return gnutls_assert_val(ret);
@@ -139,6 +172,15 @@ _gnutls13_recv_hello_retry_request(gnutls_session_t session,
return gnutls_assert_val(GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
}
+ /* figure version first */
+ ret =
+ _gnutls_parse_hello_extensions(session, GNUTLS_EXT_FLAG_HRR,
+ GNUTLS_EXT_VERSION_NEG,
+ buf->data, buf->length);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ /* parse the rest of extensions */
ret = _gnutls_parse_hello_extensions(session, GNUTLS_EXT_FLAG_HRR, GNUTLS_EXT_ANY,
buf->data, buf->length);
if (ret < 0)