summaryrefslogtreecommitdiff
path: root/lib/handshake.c
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2017-09-29 10:10:48 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2018-02-19 15:29:35 +0100
commit0acb5e17686fb6261f6129391aa7f81cc959114a (patch)
treebf5f8da7b0de35ad2d1c7a7cc8372c52dd294f28 /lib/handshake.c
parent344633626c9c497a61d975f22f83f227934b4c21 (diff)
downloadgnutls-0acb5e17686fb6261f6129391aa7f81cc959114a.tar.gz
handshake: accept hello retry request in client side
Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
Diffstat (limited to 'lib/handshake.c')
-rw-r--r--lib/handshake.c81
1 files changed, 67 insertions, 14 deletions
diff --git a/lib/handshake.c b/lib/handshake.c
index 2a041ec611..22b984050b 100644
--- a/lib/handshake.c
+++ b/lib/handshake.c
@@ -88,18 +88,18 @@ handshake_hash_buffer_reset(gnutls_session_t session)
static int
handshake_hash_add_recvd(gnutls_session_t session,
- gnutls_handshake_description_t recv_type,
- uint8_t * header, uint16_t header_size,
- uint8_t * dataptr, uint32_t datalen);
+ gnutls_handshake_description_t recv_type,
+ uint8_t * header, uint16_t header_size,
+ uint8_t * dataptr, uint32_t datalen);
static int
handshake_hash_add_sent(gnutls_session_t session,
- gnutls_handshake_description_t type,
- uint8_t * dataptr, uint32_t datalen);
+ gnutls_handshake_description_t type,
+ uint8_t * dataptr, uint32_t datalen);
static int
recv_hello_verify_request(gnutls_session_t session,
- uint8_t * data, int datalen);
+ uint8_t * data, int datalen);
/* Clears the handshake hash buffers and handles.
@@ -112,19 +112,26 @@ void _gnutls_handshake_hash_buffers_clear(gnutls_session_t session)
/* Replace handshake message buffer, with the special synthetic message
* needed by TLS1.3 when HRR is sent. */
-int _gnutls13_handshake_hash_buffers_synth(gnutls_session_t session)
+int _gnutls13_handshake_hash_buffers_synth(gnutls_session_t session,
+ const mac_entry_st *prf,
+ unsigned client)
{
int ret;
uint8_t hdata[4+MAX_HASH_SIZE];
+ size_t length;
+
+ if (client)
+ length = session->internals.handshake_hash_buffer_prev_len;
+ else
+ length = session->internals.handshake_hash_buffer.length;
/* calculate hash */
hdata[0] = 254;
- _gnutls_write_uint24(session->security_parameters.prf->output_size, &hdata[1]);
+ _gnutls_write_uint24(prf->output_size, &hdata[1]);
- ret = gnutls_hash_fast((gnutls_digest_algorithm_t)session->security_parameters.prf->id,
+ ret = gnutls_hash_fast((gnutls_digest_algorithm_t)prf->id,
session->internals.handshake_hash_buffer.data,
- session->internals.handshake_hash_buffer.length,
- hdata+4);
+ length, hdata+4);
if (ret < 0)
return gnutls_assert_val(ret);
@@ -133,12 +140,12 @@ int _gnutls13_handshake_hash_buffers_synth(gnutls_session_t session)
ret =
_gnutls_buffer_append_data(&session->internals.
handshake_hash_buffer,
- hdata, session->security_parameters.prf->output_size+4);
+ hdata, prf->output_size+4);
if (ret < 0)
return gnutls_assert_val(ret);
_gnutls_buffers_log("BUF[HSK]: Replaced handshake buffer with synth message (%d bytes)\n",
- session->security_parameters.prf->output_size+4);
+ prf->output_size+4);
return 0;
}
@@ -1201,7 +1208,7 @@ handshake_hash_add_recvd(gnutls_session_t session,
if ((vers->id != GNUTLS_DTLS0_9 &&
recv_type == GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST) ||
- recv_type == GNUTLS_HANDSHAKE_HELLO_REQUEST)
+ recv_type == GNUTLS_HANDSHAKE_HELLO_REQUEST)
return 0;
CHECK_SIZE(header_size + datalen);
@@ -1378,6 +1385,34 @@ _gnutls_recv_handshake(gnutls_session_t session,
}
break;
+ case GNUTLS_HANDSHAKE_HELLO_RETRY_REQUEST: {
+ /* hash buffer synth message is generated during hello retry parsing */
+ gnutls_datum_t hrr = {hsk.data.data, hsk.data.length};
+ ret =
+ _gnutls13_recv_hello_retry_request(session,
+ &hsk.data);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ } else {
+ /* during hello retry parsing, we reset handshake hash buffer,
+ * re-add this message */
+ ret = handshake_hash_add_recvd(session, hsk.htype,
+ hsk.header, hsk.header_size,
+ hrr.data,
+ hrr.size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ /* Signal our caller we have received a retry request
+ and ClientHello needs to be sent again. */
+ ret = 1;
+ }
+
+ break;
+ }
case GNUTLS_HANDSHAKE_SERVER_HELLO_DONE:
if (hsk.data.length == 0)
ret = 0;
@@ -1646,6 +1681,12 @@ read_server_hello(gnutls_session_t session,
}
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)
+ 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);
@@ -2483,6 +2524,18 @@ static int handshake_client(gnutls_session_t session)
STATE = STATE0;
return 1;
}
+ } else {
+ ret =
+ _gnutls_recv_handshake(session,
+ GNUTLS_HANDSHAKE_HELLO_RETRY_REQUEST,
+ 1, NULL);
+ STATE = STATE2;
+ IMED_RET("recv hello retry", ret, 1);
+
+ if (ret == 1) {
+ STATE = STATE0;
+ return 1;
+ }
}
/* fall through */
case STATE3: