From 163c32a8d6b107eca08bf404ee076b0d240bf942 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Thu, 11 Apr 2019 12:00:46 +0200 Subject: handshake: move early secrets calculation to pre_shared_key TLS 1.3 Early Secret and the derived keys are calculated upon a PSK being selected, thus the code fits better in ext/pre_shared_key.c. Signed-off-by: Daiki Ueno --- lib/ext/pre_shared_key.c | 70 ++++++++++++++++++++- lib/ext/pre_shared_key.h | 2 + lib/handshake.c | 159 +++++++++++------------------------------------ lib/state.c | 2 +- 4 files changed, 109 insertions(+), 124 deletions(-) diff --git a/lib/ext/pre_shared_key.c b/lib/ext/pre_shared_key.c index 771092fa9c..42f728286b 100644 --- a/lib/ext/pre_shared_key.c +++ b/lib/ext/pre_shared_key.c @@ -24,6 +24,7 @@ #include "gnutls_int.h" #include "auth/psk.h" #include "handshake.h" +#include "kx.h" #include "secrets.h" #include "tls13/anti_replay.h" #include "tls13/psk_ext_parser.h" @@ -188,6 +189,58 @@ error: return ret; } +static int +generate_early_secrets(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; +} + +/* Calculate TLS 1.3 Early Secret and the derived secrets from the + * selected PSK. */ +int +_gnutls_generate_early_secrets_for_psk(gnutls_session_t session) +{ + const uint8_t *psk; + size_t psk_size; + const mac_entry_st *prf; + int ret; + + psk = session->key.binders[0].psk.data; + psk_size = session->key.binders[0].psk.size; + prf = session->key.binders[0].prf; + + if (unlikely(psk_size == 0)) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + ret = _tls13_init_secret2(prf, psk, psk_size, + session->key.proto.tls13.temp_secret); + if (ret < 0) + return gnutls_assert_val(ret); + + session->key.proto.tls13.temp_secret_size = prf->output_size; + + ret = generate_early_secrets(session, session->key.binders[0].prf); + if (ret < 0) + return gnutls_assert_val(ret); + + return 0; +} + static int client_send_params(gnutls_session_t session, gnutls_buffer_t extdata, @@ -651,6 +704,12 @@ static int server_recv_params(gnutls_session_t session, session->key.binders[0].prf = prf; session->key.binders[0].resumption = resuming; + ret = _gnutls_generate_early_secrets_for_psk(session); + if (ret < 0) { + gnutls_assert(); + goto fail; + } + return 0; fail: @@ -742,6 +801,7 @@ static int _gnutls_psk_recv_params(gnutls_session_t session, unsigned i; gnutls_psk_server_credentials_t pskcred; const version_entry_st *vers = get_version(session); + int ret; if (!vers || !vers->tls13_sem) return 0; @@ -759,9 +819,15 @@ static int _gnutls_psk_recv_params(gnutls_session_t session, _gnutls_handshake_log("EXT[%p]: selected PSK mode\n", session); } - /* ensure that selected binder is set on (our) index zero */ - if (i != 0) + /* different PSK is selected, than the one we calculated early secrets */ + if (i != 0) { + /* ensure that selected binder is set on (our) index zero */ swap_binders(session); + + ret = _gnutls_generate_early_secrets_for_psk(session); + if (ret < 0) + return gnutls_assert_val(ret); + } session->internals.hsk_flags |= HSK_PSK_SELECTED; } } diff --git a/lib/ext/pre_shared_key.h b/lib/ext/pre_shared_key.h index 4ad7b240f3..71116e5d10 100644 --- a/lib/ext/pre_shared_key.h +++ b/lib/ext/pre_shared_key.h @@ -18,4 +18,6 @@ unsigned _gnutls_have_psk_credentials(const gnutls_psk_client_credentials_t cred return 0; } +int _gnutls_generate_early_secrets_for_psk(gnutls_session_t session); + #endif diff --git a/lib/handshake.c b/lib/handshake.c index 45bf99a6f7..1e6164cabe 100644 --- a/lib/handshake.c +++ b/lib/handshake.c @@ -45,6 +45,7 @@ #include "constate.h" #include #include +#include #include #include #include @@ -826,6 +827,14 @@ read_client_hello(gnutls_session_t session, uint8_t * data, return ret; } + /* Calculate TLS 1.3 Early Secret */ + if (session->security_parameters.pversion->tls13_sem && + !(session->internals.hsk_flags & HSK_PSK_SELECTED)) { + ret = _tls13_init_secret(session, NULL, 0); + if (ret < 0) + return gnutls_assert_val(ret); + } + ret = set_auth_types(session); if (ret < 0) { gnutls_assert(); @@ -1265,7 +1274,7 @@ _gnutls_send_handshake2(gnutls_session_t session, mbuffer_st * bufel, /* Here we keep the handshake messages in order to hash them... */ - if (!IS_ASYNC(type, vers)) + if (!IS_ASYNC(type, vers)) { if ((ret = handshake_hash_add_sent(session, type, data, datasize)) < 0) { @@ -1273,6 +1282,19 @@ _gnutls_send_handshake2(gnutls_session_t session, mbuffer_st * bufel, _mbuffer_xfree(&bufel); return ret; } + /* If we are sending a PSK, generate early secrets here. + * This cannot be done in pre_shared_key.c, because it + * relies on transcript hash of a Client Hello. */ + if (type == GNUTLS_HANDSHAKE_CLIENT_HELLO && + session->key.binders[0].prf != NULL) { + ret = _gnutls_generate_early_secrets_for_psk(session); + if (ret < 0) { + gnutls_assert(); + _mbuffer_xfree(&bufel); + return ret; + } + } + } ret = _gnutls_call_hook_func(session, type, GNUTLS_HOOK_PRE, 0, _mbuffer_get_udata_ptr(bufel), _mbuffer_get_udata_size(bufel)); @@ -1807,26 +1829,6 @@ 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. @@ -1840,12 +1842,10 @@ read_server_hello(gnutls_session_t session, uint8_t *cs_pos, *comp_pos, *srandom_pos; uint8_t major, minor; int pos = 0; - int ret = 0; + int ret; int len = datalen; unsigned ext_parse_flag = 0; const version_entry_st *vers, *saved_vers; - const uint8_t *psk = NULL; - size_t psk_size = 0; if (datalen < GNUTLS_RANDOM_SIZE+2) { gnutls_assert(); @@ -1925,6 +1925,13 @@ read_server_hello(gnutls_session_t session, if (ret < 0) return gnutls_assert_val(ret); + /* reset keys and binders if we are not using TLS 1.3 */ + if (!vers->tls13_sem) { + gnutls_memset(&session->key.proto.tls13, 0, + sizeof(session->key.proto.tls13)); + reset_binders(session); + } + /* check if we are resuming and set the appropriate * values; */ @@ -2016,31 +2023,17 @@ read_server_hello(gnutls_session_t session, /* Calculate TLS 1.3 Early Secret */ 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; - - if (psk_size == 0) - return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); - } - - ret = _tls13_init_secret(session, psk, psk_size); - if (ret < 0) { - gnutls_assert(); - return ret; - } + !(session->internals.hsk_flags & HSK_PSK_SELECTED)) { + ret = _tls13_init_secret(session, NULL, 0); + if (ret < 0) + return gnutls_assert_val(ret); } ret = set_auth_types(session); - if (ret < 0) { - gnutls_assert(); - goto cleanup; - } - -cleanup: + if (ret < 0) + return gnutls_assert_val(ret); - return ret; + return 0; } /* This function copies the appropriate compression methods, to a locally allocated buffer @@ -2064,56 +2057,6 @@ 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) @@ -2349,9 +2292,6 @@ int _gnutls_send_server_hello(gnutls_session_t session, int again) const version_entry_st *vers; uint8_t vbytes[2]; 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); @@ -2362,25 +2302,6 @@ int _gnutls_send_server_hello(gnutls_session_t session, int again) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); if (vers->tls13_sem) { - /* TLS 1.3 Early Secret */ - 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); - if (ret < 0) { - gnutls_assert(); - 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; @@ -2971,10 +2892,6 @@ 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)) { diff --git a/lib/state.c b/lib/state.c index fe40bd980a..97461e6722 100644 --- a/lib/state.c +++ b/lib/state.c @@ -345,7 +345,7 @@ static void deinit_keys(gnutls_session_t session) gnutls_pk_params_release(&session->key.kshare.ecdh_params); gnutls_pk_params_release(&session->key.kshare.dh_params); - if (!vers->tls13_sem) { + if (!vers->tls13_sem && session->key.binders[0].prf == NULL) { gnutls_pk_params_release(&session->key.proto.tls12.ecdh.params); gnutls_pk_params_release(&session->key.proto.tls12.dh.params); zrelease_temp_mpi_key(&session->key.proto.tls12.ecdh.x); -- cgit v1.2.1