summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2017-09-15 09:11:37 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2017-10-10 18:09:00 +0200
commite17703f755881efb5782e91f3b43275ea43f8a07 (patch)
treef0049e0272da259b726922fb50967d9675dc76b7
parent561e0a47964c60e21bde5be71a89c0a743f85c5b (diff)
downloadgnutls-e17703f755881efb5782e91f3b43275ea43f8a07.tar.gz
handshake: generate application keys
Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
-rw-r--r--lib/constate.c42
-rw-r--r--lib/constate.h4
-rw-r--r--lib/ext/session_ticket.c2
-rw-r--r--lib/gnutls_int.h10
-rw-r--r--lib/handshake-tls13.c44
-rw-r--r--lib/handshake.c7
-rw-r--r--lib/secrets.c4
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,