From e17703f755881efb5782e91f3b43275ea43f8a07 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Fri, 15 Sep 2017 09:11:37 +0200 Subject: handshake: generate application keys Signed-off-by: Nikos Mavrogiannopoulos --- lib/constate.c | 42 +++++++++++++++++++++++++++++++----------- lib/constate.h | 4 ++-- lib/ext/session_ticket.c | 2 +- lib/gnutls_int.h | 10 +++++++++- lib/handshake-tls13.c | 44 ++++++++++++++++++++++++++++++++++++-------- lib/handshake.c | 7 +++++++ lib/secrets.c | 4 ++++ 7 files changed, 90 insertions(+), 23 deletions(-) diff --git a/lib/constate.c b/lib/constate.c index 63c44fa229..8bf4cd1224 100644 --- a/lib/constate.c +++ b/lib/constate.c @@ -200,7 +200,7 @@ _gnutls_set_keys(gnutls_session_t session, record_parameters_st * params, } static int -_tls13_set_keys(gnutls_session_t session, record_parameters_st * params, +_tls13_set_keys(gnutls_session_t session, hs_stage_t stage, record_parameters_st * params, unsigned iv_size, unsigned key_size) { uint8_t ckey_block[MAX_CIPHER_KEY_SIZE]; @@ -209,11 +209,23 @@ _tls13_set_keys(gnutls_session_t session, record_parameters_st * params, uint8_t siv_block[MAX_CIPHER_IV_SIZE]; char buf[65]; record_state_st *client_write, *server_write; + const char *label; + unsigned label_size, hsk_len; int ret; - ret = _tls13_derive_secret(session, HANDSHAKE_CLIENT_TRAFFIC_LABEL, sizeof(HANDSHAKE_CLIENT_TRAFFIC_LABEL)-1, + if (stage == STAGE_HS) { + label = HANDSHAKE_CLIENT_TRAFFIC_LABEL; + label_size = sizeof(HANDSHAKE_CLIENT_TRAFFIC_LABEL)-1; + hsk_len = session->internals.handshake_hash_buffer.length; + } else { + label = APPLICATION_CLIENT_TRAFFIC_LABEL; + label_size = sizeof(APPLICATION_CLIENT_TRAFFIC_LABEL)-1; + hsk_len = session->internals.handshake_hash_buffer_server_finished_len; + } + + ret = _tls13_derive_secret(session, label, label_size, session->internals.handshake_hash_buffer.data, - session->internals.handshake_hash_buffer.length, + hsk_len, session->key.hs_ckey); if (ret < 0) return gnutls_assert_val(ret); @@ -228,9 +240,17 @@ _tls13_set_keys(gnutls_session_t session, record_parameters_st * params, return gnutls_assert_val(ret); /* server keys */ - ret = _tls13_derive_secret(session, HANDSHAKE_SERVER_TRAFFIC_LABEL, sizeof(HANDSHAKE_SERVER_TRAFFIC_LABEL)-1, + if (stage == STAGE_HS) { + label = HANDSHAKE_SERVER_TRAFFIC_LABEL; + label_size = sizeof(HANDSHAKE_SERVER_TRAFFIC_LABEL)-1; + } else { + label = APPLICATION_SERVER_TRAFFIC_LABEL; + label_size = sizeof(APPLICATION_SERVER_TRAFFIC_LABEL)-1; + } + + ret = _tls13_derive_secret(session, label, label_size, session->internals.handshake_hash_buffer.data, - session->internals.handshake_hash_buffer.length, + hsk_len, session->key.hs_skey); if (ret < 0) @@ -395,7 +415,7 @@ int _gnutls_epoch_dup(gnutls_session_t session) return 0; } -int _gnutls_epoch_set_keys(gnutls_session_t session, uint16_t epoch) +int _gnutls_epoch_set_keys(gnutls_session_t session, uint16_t epoch, hs_stage_t stage) { int hash_size; int IV_size; @@ -434,7 +454,7 @@ int _gnutls_epoch_set_keys(gnutls_session_t session, uint16_t epoch) if (ver->tls13_sem) { ret = _tls13_set_keys - (session, params, IV_size, key_size); + (session, stage, params, IV_size, key_size); if (ret < 0) return gnutls_assert_val(ret); @@ -530,7 +550,7 @@ int _gnutls_read_connection_state_init(gnutls_session_t session) session->security_parameters.entity == GNUTLS_CLIENT) _gnutls_set_resumed_parameters(session); - ret = _gnutls_epoch_set_keys(session, epoch_next); + ret = _gnutls_epoch_set_keys(session, epoch_next, 0); if (ret < 0) return ret; @@ -559,7 +579,7 @@ int _gnutls_write_connection_state_init(gnutls_session_t session) session->security_parameters.entity == GNUTLS_SERVER) _gnutls_set_resumed_parameters(session); - ret = _gnutls_epoch_set_keys(session, epoch_next); + ret = _gnutls_epoch_set_keys(session, epoch_next, 0); if (ret < 0) return gnutls_assert_val(ret); @@ -786,13 +806,13 @@ _gnutls_epoch_free(gnutls_session_t session, record_parameters_st * params) gnutls_free(params); } -int _tls13_connection_state_init(gnutls_session_t session) +int _tls13_connection_state_init(gnutls_session_t session, hs_stage_t stage) { const uint16_t epoch_next = session->security_parameters.epoch_next; int ret; - ret = _gnutls_epoch_set_keys(session, epoch_next); + ret = _gnutls_epoch_set_keys(session, epoch_next, stage); if (ret < 0) return ret; diff --git a/lib/constate.h b/lib/constate.h index 18c8cfe1a4..c7feb3b191 100644 --- a/lib/constate.h +++ b/lib/constate.h @@ -27,7 +27,7 @@ int _gnutls_set_cipher_suite2(gnutls_session_t session, const gnutls_cipher_suite_entry_st *cs); void _gnutls_epoch_set_null_algos(gnutls_session_t session, record_parameters_st * params); -int _gnutls_epoch_set_keys(gnutls_session_t session, uint16_t epoch); +int _gnutls_epoch_set_keys(gnutls_session_t session, uint16_t epoch, hs_stage_t stage); int _gnutls_connection_state_init(gnutls_session_t session); int _gnutls_read_connection_state_init(gnutls_session_t session); int _gnutls_write_connection_state_init(gnutls_session_t session); @@ -44,7 +44,7 @@ void _gnutls_epoch_gc(gnutls_session_t session); void _gnutls_epoch_free(gnutls_session_t session, record_parameters_st * state); -int _tls13_connection_state_init(gnutls_session_t session); +int _tls13_connection_state_init(gnutls_session_t session, hs_stage_t stage); static inline int _gnutls_epoch_is_valid(gnutls_session_t session, int epoch) diff --git a/lib/ext/session_ticket.c b/lib/ext/session_ticket.c index 432794038c..9490a80f74 100644 --- a/lib/ext/session_ticket.c +++ b/lib/ext/session_ticket.c @@ -644,7 +644,7 @@ int _gnutls_send_new_session_ticket(gnutls_session_t session, int again) ret = _gnutls_epoch_set_keys(session, session->security_parameters. - epoch_next); + epoch_next, 0); if (ret < 0) { gnutls_assert(); return ret; diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 5689fe90e5..9958e6633d 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -159,6 +159,12 @@ typedef enum transport_t { GNUTLS_DGRAM } transport_t; +/* The TLS 1.3 stage of handshake */ +typedef enum hs_stage_t { + STAGE_HS, + STAGE_APP +} hs_stage_t; + typedef enum record_flush_t { RECORD_FLUSH = 0, RECORD_CORKED, @@ -242,7 +248,7 @@ typedef enum handshake_state_t { STATE0 = 0, STATE1, STATE2, STATE20 = 20, STATE21, STATE22, STATE30 = 30, STATE31, STATE40 = 40, STATE41, STATE50 = 50, STATE100=100, STATE101, STATE102, STATE103, STATE104, - STATE105, STATE106, STATE107, STATE108, STATE109 + STATE105, STATE106, STATE107, STATE108, STATE109, STATE110 } handshake_state_t; typedef enum bye_state_t { @@ -893,6 +899,8 @@ typedef struct { * the last received message */ unsigned handshake_hash_buffer_client_kx_len;/* if non-zero it is the length of data until the * the client key exchange message */ + unsigned handshake_hash_buffer_server_finished_len;/* if non-zero it is the length of data until the + * the server finished message */ gnutls_buffer_st handshake_hash_buffer; /* used to keep the last received handshake * message */ bool resumable; /* TRUE or FALSE - if we can resume that session */ diff --git a/lib/handshake-tls13.c b/lib/handshake-tls13.c index 9502f1d69d..456442e3e9 100644 --- a/lib/handshake-tls13.c +++ b/lib/handshake-tls13.c @@ -54,6 +54,7 @@ #include "tls13/finished.h" static int generate_hs_traffic_keys(gnutls_session_t session); +static int generate_ap_traffic_keys(gnutls_session_t session); /* * _gnutls13_handshake_client @@ -115,6 +116,12 @@ int _gnutls13_handshake_client(gnutls_session_t session) ret = _gnutls13_send_finished(session, AGAIN(STATE109)); STATE = STATE109; IMED_RET("send finished", ret, 0); + /* fall through */ + case STATE110: + ret = + generate_ap_traffic_keys(session); + STATE = STATE110; + IMED_RET("generate app keys", ret, 0); STATE = STATE0; break; @@ -124,6 +131,34 @@ int _gnutls13_handshake_client(gnutls_session_t session) /* explicitly reset any false start flags */ session->internals.recv_state = RECV_STATE_0; + session->internals.initial_negotiation_completed = 1; + + return 0; +} + +static int generate_ap_traffic_keys(gnutls_session_t session) +{ + int ret; + uint8_t zero[MAX_HASH_SIZE]; + + ret = _tls13_derive_secret(session, DERIVED_LABEL, sizeof(DERIVED_LABEL)-1, + NULL, 0, session->key.temp_secret); + if (ret < 0) + return gnutls_assert_val(ret); + + memset(zero, 0, session->security_parameters.prf->output_size); + ret = _tls13_update_secret(session, zero, session->security_parameters.prf->output_size); + if (ret < 0) + return gnutls_assert_val(ret); + + _gnutls_epoch_bump(session); + ret = _gnutls_epoch_dup(session); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = _tls13_connection_state_init(session, STAGE_APP); + if (ret < 0) + return gnutls_assert_val(ret); return 0; } @@ -141,14 +176,7 @@ static int generate_hs_traffic_keys(gnutls_session_t session) return ret; } - ret = _tls13_connection_state_init(session); - if (ret < 0) { - gnutls_assert(); - return ret; - } - - ret = _tls13_derive_secret(session, DERIVED_LABEL, sizeof(DERIVED_LABEL)-1, - NULL, 0, session->key.temp_secret); + ret = _tls13_connection_state_init(session, STAGE_HS); if (ret < 0) { gnutls_assert(); return ret; diff --git a/lib/handshake.c b/lib/handshake.c index 86771ab8e7..32afb7b550 100644 --- a/lib/handshake.c +++ b/lib/handshake.c @@ -108,6 +108,7 @@ void _gnutls_handshake_hash_buffers_clear(gnutls_session_t session) { session->internals.handshake_hash_buffer_prev_len = 0; session->internals.handshake_hash_buffer_client_kx_len = 0; + session->internals.handshake_hash_buffer_server_finished_len = 0; _gnutls_buffer_clear(&session->internals.handshake_hash_buffer); } @@ -1190,6 +1191,9 @@ handshake_hash_add_recvd(gnutls_session_t session, if (recv_type == GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE) session->internals.handshake_hash_buffer_client_kx_len = session->internals.handshake_hash_buffer.length; + if (recv_type == GNUTLS_HANDSHAKE_FINISHED && session->security_parameters.entity == GNUTLS_CLIENT) + session->internals.handshake_hash_buffer_server_finished_len = + session->internals.handshake_hash_buffer.length; return 0; } @@ -1236,6 +1240,9 @@ handshake_hash_add_sent(gnutls_session_t session, if (type == GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE) session->internals.handshake_hash_buffer_client_kx_len = session->internals.handshake_hash_buffer.length; + if (type == GNUTLS_HANDSHAKE_FINISHED && session->security_parameters.entity == GNUTLS_SERVER) + session->internals.handshake_hash_buffer_server_finished_len = + session->internals.handshake_hash_buffer.length; return 0; } diff --git a/lib/secrets.c b/lib/secrets.c index f5a3433695..2f0750dc92 100644 --- a/lib/secrets.c +++ b/lib/secrets.c @@ -146,6 +146,10 @@ int _tls13_expand_secret(gnutls_session_t session, } #if 0 + _gnutls_hard_log("INT: hkdf label: %d,%s\n", + out_size, + _gnutls_bin2hex(str.data, str.length, + (char*)tmp, sizeof(tmp), NULL)); _gnutls_hard_log("INT: secret expanded for '%.*s': %d,%s\n", (int)label_size, label, out_size, _gnutls_bin2hex(out, out_size, -- cgit v1.2.1