]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
handshake: generate application keys
authorNikos Mavrogiannopoulos <nmav@redhat.com>
Fri, 15 Sep 2017 07:11:37 +0000 (09:11 +0200)
committerNikos Mavrogiannopoulos <nmav@redhat.com>
Mon, 19 Feb 2018 14:29:34 +0000 (15:29 +0100)
Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
lib/constate.c
lib/constate.h
lib/ext/session_ticket.c
lib/gnutls_int.h
lib/handshake-tls13.c
lib/handshake.c
lib/secrets.c

index 8582fed879df629e039a2b6f7d3669faa3dbb791..634b4054edae0bd378176e76f436f9872e205844 100644 (file)
@@ -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);
 
@@ -531,7 +551,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;
 
@@ -560,7 +580,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);
 
@@ -787,13 +807,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;
 
index 18c8cfe1a4057440f960fa1254284eca25c69241..c7feb3b191c2f2e8e678bba3013657cddf2ecf32 100644 (file)
@@ -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)
index 432794038c9c487a20f8be5ac6f08b213d910483..9490a80f7477e9361490bbcc8e21137e6967cce1 100644 (file)
@@ -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;
index af2e9ad766513e5949c2b0f7a20e19e725af28f6..248d401169a2897249ffb427e9a3e91ccd8d54ed 100644 (file)
@@ -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 */
index 9502f1d69d704035924e7dd1780d456cf8bc5661..456442e3e91ced54202092aa0f313518d780b5e8 100644 (file)
@@ -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;
index 86771ab8e7893affaf71ce8562f79ec9a3ee1859..32afb7b550adef3d02f037bb919e01f8f576ba10 100644 (file)
@@ -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;
        }
index f5a34336957f9b1b6dac3a782550b07bc4301b05..2f0750dc92ead02de08c785b457df6106808348e 100644 (file)
@@ -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,