diff options
author | Daiki Ueno <dueno@redhat.com> | 2018-10-12 11:45:59 +0200 |
---|---|---|
committer | Daiki Ueno <dueno@redhat.com> | 2018-11-11 07:03:43 +0100 |
commit | 957f7537604b21653c0d456e55fabed600052508 (patch) | |
tree | 0e818d620669b1efe8f024eb1e4caf3f1d4217bd /lib/handshake.c | |
parent | f39af59c4e7f7062b548c6c97e785bb6b6284371 (diff) | |
download | gnutls-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.c | 97 |
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)) { |