summaryrefslogtreecommitdiff
path: root/lib/handshake.c
diff options
context:
space:
mode:
authorDaiki Ueno <dueno@redhat.com>2018-10-12 11:45:59 +0200
committerDaiki Ueno <dueno@redhat.com>2018-11-11 07:03:43 +0100
commit957f7537604b21653c0d456e55fabed600052508 (patch)
tree0e818d620669b1efe8f024eb1e4caf3f1d4217bd /lib/handshake.c
parentf39af59c4e7f7062b548c6c97e785bb6b6284371 (diff)
downloadgnutls-957f7537604b21653c0d456e55fabed600052508.tar.gz
handshake: handle early data
This plumbers early data handling in the handshake processes, which consists of: - traffic key updates taking into account of client_early_traffic_secret - early data buffering in both server and client - the EndOfEarlyData message handling - making use of max_early_data_size extension in NewSessionTicket Signed-off-by: Daiki Ueno <dueno@redhat.com>
Diffstat (limited to 'lib/handshake.c')
-rw-r--r--lib/handshake.c97
1 files changed, 92 insertions, 5 deletions
diff --git a/lib/handshake.c b/lib/handshake.c
index f0ed91f976..5080756c28 100644
--- a/lib/handshake.c
+++ b/lib/handshake.c
@@ -1620,6 +1620,7 @@ _gnutls_recv_handshake(gnutls_session_t session,
case GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY:
case GNUTLS_HANDSHAKE_SUPPLEMENTAL:
case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET:
+ case GNUTLS_HANDSHAKE_END_OF_EARLY_DATA:
ret = hsk.data.length;
break;
default:
@@ -1783,6 +1784,26 @@ no_resume:
}
+static int generate_early_traffic_secret(gnutls_session_t session,
+ const mac_entry_st *prf)
+{
+ int ret;
+
+ ret = _tls13_derive_secret2(prf, EARLY_TRAFFIC_LABEL, sizeof(EARLY_TRAFFIC_LABEL)-1,
+ session->internals.handshake_hash_buffer.data,
+ session->internals.handshake_hash_buffer_client_hello_len,
+ session->key.proto.tls13.temp_secret,
+ session->key.proto.tls13.e_ckey);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ _gnutls_nss_keylog_write(session, "CLIENT_EARLY_TRAFFIC_SECRET",
+ session->key.proto.tls13.e_ckey,
+ prf->output_size);
+
+ return 0;
+}
+
/* This function reads and parses the server hello handshake message.
* This function also restores resumed parameters if we are resuming a
* session.
@@ -1971,7 +1992,8 @@ read_server_hello(gnutls_session_t session,
return gnutls_assert_val(ret);
/* Calculate TLS 1.3 Early Secret */
- if (vers->tls13_sem) {
+ if (vers->tls13_sem &&
+ !(session->internals.hsk_flags & HSK_EARLY_DATA_IN_FLIGHT)) {
if (session->internals.hsk_flags & HSK_PSK_SELECTED) {
psk = session->key.binders[0].psk.data;
psk_size = session->key.binders[0].psk.size;
@@ -1983,7 +2005,7 @@ read_server_hello(gnutls_session_t session,
ret = _tls13_init_secret(session, psk, psk_size);
if (ret < 0) {
gnutls_assert();
- goto cleanup;
+ return ret;
}
}
@@ -2019,6 +2041,56 @@ append_null_comp(gnutls_session_t session,
return ret;
}
+/* Calculate TLS 1.3 Early Secret and client_early_traffic_secret,
+ * assuming that the PSK we offer will be accepted by the server */
+static int
+generate_early_traffic_secret_from_ticket(gnutls_session_t session)
+{
+ int ret = 0;
+ const uint8_t *psk;
+ size_t psk_size;
+ const mac_entry_st *prf;
+
+ if (!(session->internals.hsk_flags & HSK_TLS13_TICKET_SENT)) {
+ ret = GNUTLS_E_INVALID_REQUEST;
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ psk = session->key.binders[0].psk.data;
+ psk_size = session->key.binders[0].psk.size;
+ prf = session->key.binders[0].prf;
+
+ if (psk_size == 0) {
+ ret = GNUTLS_E_INVALID_REQUEST;
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = _tls13_init_secret2(prf, psk, psk_size,
+ session->key.proto.tls13.temp_secret);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ session->key.proto.tls13.temp_secret_size = prf->output_size;
+
+ ret = generate_early_traffic_secret(session, prf);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ return ret;
+
+ cleanup:
+ /* If any of the above calculation fails, we are not going to
+ * send early data. */
+ session->internals.hsk_flags &= ~HSK_EARLY_DATA_IN_FLIGHT;
+
+ return ret;
+}
+
/* This function sends the client hello handshake message.
*/
static int send_client_hello(gnutls_session_t session, int again)
@@ -2230,9 +2302,10 @@ static int send_client_hello(gnutls_session_t session, int again)
bufel = _gnutls_buffer_to_mbuffer(&extdata);
}
- return
- _gnutls_send_handshake(session, bufel,
- GNUTLS_HANDSHAKE_CLIENT_HELLO);
+ ret = _gnutls_send_handshake(session, bufel,
+ GNUTLS_HANDSHAKE_CLIENT_HELLO);
+
+ return ret;
cleanup:
_gnutls_buffer_clear(&extdata);
@@ -2252,6 +2325,7 @@ int _gnutls_send_server_hello(gnutls_session_t session, int again)
unsigned extflag = 0;
const uint8_t *psk = NULL;
size_t psk_size = 0;
+ const mac_entry_st *prf = session->security_parameters.prf;
gnutls_ext_parse_type_t etype;
_gnutls_buffer_init(&buf);
@@ -2266,6 +2340,7 @@ int _gnutls_send_server_hello(gnutls_session_t session, int again)
if (session->internals.hsk_flags & HSK_PSK_SELECTED) {
psk = session->key.binders[0].psk.data;
psk_size = session->key.binders[0].psk.size;
+ prf = session->key.binders[0].prf;
}
ret = _tls13_init_secret(session, psk, psk_size);
@@ -2274,6 +2349,12 @@ int _gnutls_send_server_hello(gnutls_session_t session, int again)
goto fail;
}
+ ret = generate_early_traffic_secret(session, prf);
+ if (ret < 0) {
+ gnutls_assert();
+ goto fail;
+ }
+
vbytes[0] = 0x03; /* TLS1.2 */
vbytes[1] = 0x03;
extflag |= GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO;
@@ -2714,6 +2795,8 @@ int gnutls_handshake(gnutls_session_t session)
_gnutls_handshake_internal_state_clear(session);
+ _gnutls_buffer_clear(&session->internals.record_presend_buffer);
+
_gnutls_epoch_bump(session);
}
@@ -2841,6 +2924,10 @@ static int handshake_client(gnutls_session_t session)
ret = send_client_hello(session, AGAIN(STATE1));
STATE = STATE1;
IMED_RET("send hello", ret, 1);
+ if (session->internals.hsk_flags & HSK_EARLY_DATA_IN_FLIGHT) {
+ ret = generate_early_traffic_secret_from_ticket(session);
+ IMED_RET_FATAL("generate early traffic keys from ticket", ret, 0);
+ }
FALLTHROUGH;
case STATE2:
if (IS_DTLS(session)) {