diff options
-rw-r--r-- | lib/buffers.c | 4 | ||||
-rw-r--r-- | lib/gnutls_int.h | 11 | ||||
-rw-r--r-- | lib/handshake.c | 53 | ||||
-rw-r--r-- | lib/hello_ext.c | 23 | ||||
-rw-r--r-- | lib/hello_ext.h | 16 |
5 files changed, 101 insertions, 6 deletions
diff --git a/lib/buffers.c b/lib/buffers.c index 414ea50307..b0f33099fb 100644 --- a/lib/buffers.c +++ b/lib/buffers.c @@ -50,6 +50,7 @@ #include <system.h> #include <constate.h> /* gnutls_epoch_get */ #include <handshake.h> /* remaining_time() */ +#include <hello_ext.h> /* _gnutls_ext_set_full_client_hello */ #include <errno.h> #include <system.h> #include "debug.h" @@ -1252,6 +1253,9 @@ int _gnutls_parse_record_buffered_msgs(gnutls_session_t session) /* if packet is complete then return it */ if (recv_buf[0].length == recv_buf[0].data.length) { + /* Reference the full ClientHello in case an extension needs it */ + if (recv_buf->htype == GNUTLS_HANDSHAKE_CLIENT_HELLO) + _gnutls_ext_set_full_client_hello(session, recv_buf); return 0; } bufel = diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index bb422ddbe9..98b66acb64 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -1173,6 +1173,17 @@ typedef struct { * they are reset to zero prior to handshake start by gnutls_handshake. */ unsigned hsk_flags; time_t last_key_update; + unsigned tls13_psk_selected; + gnutls_datum_t tls13_psk; + /* Read-only pointer to the full ClientHello message */ + gnutls_buffer_st full_client_hello; + /* The offset at which extensions start in the ClientHello buffer */ + int extensions_offset; + + unsigned crt_requested; /* 1 if client auth was requested (i.e., client cert). + * In case of a server this holds 1 if we should wait + * for a client certificate verify + */ gnutls_buffer_st hb_local_data; gnutls_buffer_st hb_remote_data; diff --git a/lib/handshake.c b/lib/handshake.c index 179fcb8009..9e309e6189 100644 --- a/lib/handshake.c +++ b/lib/handshake.c @@ -83,6 +83,7 @@ handshake_hash_buffer_reset(gnutls_session_t session) session->internals.handshake_hash_buffer_server_finished_len = 0; session->internals.handshake_hash_buffer_prev_len = 0; session->internals.handshake_hash_buffer.length = 0; + session->internals.full_client_hello.length = 0; return; } @@ -108,6 +109,7 @@ void _gnutls_handshake_hash_buffers_clear(gnutls_session_t session) { handshake_hash_buffer_reset(session); _gnutls_buffer_clear(&session->internals.handshake_hash_buffer); + _gnutls_buffer_clear(&session->internals.full_client_hello); } /* Replace handshake message buffer, with the special synthetic message @@ -1624,6 +1626,8 @@ read_server_hello(gnutls_session_t session, int len = datalen; const version_entry_st *vers; gnutls_ext_flags_t ext_parse_flag; + const uint8_t *psk = NULL; + size_t psk_size = 0; if (datalen < GNUTLS_RANDOM_SIZE+2) { gnutls_assert(); @@ -1762,6 +1766,30 @@ read_server_hello(gnutls_session_t session, if (ret < 0) return gnutls_assert_val(ret); + if (vers->tls13_sem) { + /* TLS 1.3 Early Secret */ + if (session->internals.tls13_psk_selected) { + psk = session->internals.tls13_psk.data; + psk_size = session->internals.tls13_psk.size; + } + + ret = _tls13_init_secret(session, psk, psk_size); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + ret = _tls13_derive_secret(session, DERIVED_LABEL, sizeof(DERIVED_LABEL)-1, + NULL, 0, session->key.temp_secret); + if (ret < 0) + gnutls_assert(); + } + +cleanup: + + if (session->internals.tls13_psk_selected) + _gnutls_free_datum(&session->internals.tls13_psk); + return ret; } @@ -1987,6 +2015,8 @@ int _gnutls_send_server_hello(gnutls_session_t session, int again) char tmpbuf[2 * GNUTLS_MAX_SESSION_ID_SIZE + 1]; const version_entry_st *vers; gnutls_ext_flags_t ext_parse_flag; + const uint8_t *psk = NULL; + size_t psk_size = 0; _gnutls_buffer_init(&buf); @@ -1997,9 +2027,16 @@ int _gnutls_send_server_hello(gnutls_session_t session, int again) if (vers->tls13_sem) { /* TLS 1.3 Early Secret */ - ret = _tls13_init_secret(session, NULL, 0); - if (ret < 0) - return gnutls_assert_val(ret); + if (session->internals.tls13_psk_selected) { + psk = session->internals.tls13_psk.data; + psk_size = session->internals.tls13_psk.size; + } + + ret = _tls13_init_secret(session, psk, psk_size); + if (ret < 0) { + gnutls_assert(); + goto fail; + } ext_parse_flag = GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO; } else { @@ -2007,8 +2044,10 @@ int _gnutls_send_server_hello(gnutls_session_t session, int again) } ret = _gnutls_buffer_init_handshake_mbuffer(&buf); - if (ret < 0) - return gnutls_assert_val(ret); + if (ret < 0) { + gnutls_assert(); + goto fail; + } ret = _gnutls_buffer_append_data(&buf, &vers->major, 1); if (ret < 0) { @@ -2091,7 +2130,9 @@ int _gnutls_send_server_hello(gnutls_session_t session, int again) _gnutls_send_handshake(session, bufel, GNUTLS_HANDSHAKE_SERVER_HELLO); - fail: +fail: + if (session->internals.tls13_psk_selected) + _gnutls_free_temp_key_datum(&session->internals.tls13_psk); _gnutls_buffer_clear(&buf); return ret; } diff --git a/lib/hello_ext.c b/lib/hello_ext.c index 4a4b2cc675..7d8085b3d1 100644 --- a/lib/hello_ext.c +++ b/lib/hello_ext.c @@ -352,6 +352,7 @@ _gnutls_gen_hello_extensions(gnutls_session_t session, return gnutls_assert_val(ret); pos = ret; + _gnutls_ext_set_extensions_offset(session, pos); for (i=0; i < session->internals.rexts_size; i++) { ctx.ext = &session->internals.rexts[i]; @@ -481,6 +482,28 @@ int _gnutls_hello_ext_pack(gnutls_session_t session, gnutls_buffer_st *packed) return 0; } +void _gnutls_ext_set_full_client_hello(gnutls_session_t session, + handshake_buffer_st *recv_buf) +{ + gnutls_buffer_st *buf = &session->internals.full_client_hello; + _gnutls_buffer_clear(buf); + _gnutls_buffer_append_prefix(buf, 8, recv_buf->htype); + _gnutls_buffer_append_prefix(buf, 24, recv_buf->data.length); + _gnutls_buffer_append_data(buf, recv_buf->data.data, recv_buf->data.length); +} + +int _gnutls_ext_get_full_client_hello(gnutls_session_t session, + gnutls_datum_t *datum) +{ + gnutls_buffer_st *buf = &session->internals.full_client_hello; + + if (!datum) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + + _gnutls_set_datum(datum, buf->data, buf->length); + return buf->length; +} + static void _gnutls_ext_set_resumed_session_data(gnutls_session_t session, extensions_t id, diff --git a/lib/hello_ext.h b/lib/hello_ext.h index 577775d08a..5fa42f42c7 100644 --- a/lib/hello_ext.h +++ b/lib/hello_ext.h @@ -63,6 +63,22 @@ inline static void _gnutls_ext_set_msg(gnutls_session_t session, gnutls_ext_flag session->internals.ext_msg = msg; } +inline static void _gnutls_ext_set_extensions_offset(gnutls_session_t session, + int offset) +{ + session->internals.extensions_offset = offset; +} + +inline static int _gnutls_ext_get_extensions_offset(gnutls_session_t session) +{ + return session->internals.extensions_offset; +} + +void _gnutls_ext_set_full_client_hello(gnutls_session_t session, + handshake_buffer_st *recv_buf); +int _gnutls_ext_get_full_client_hello(gnutls_session_t session, + gnutls_datum_t *datum); + /* for session packing */ int _gnutls_hello_ext_pack(gnutls_session_t session, gnutls_buffer_st * packed); int _gnutls_hello_ext_unpack(gnutls_session_t session, |