summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaiki Ueno <ueno@gnu.org>2020-02-21 17:48:37 +0100
committerDaiki Ueno <ueno@gnu.org>2020-11-19 18:18:38 +0100
commitf8dc2b2fadc889df569b983b2741f0928dcf0bbc (patch)
tree0fa7dbd59d3d0ab3937adb8f381b8a5597b26f31
parente3d6a62938a5a53b89585ace73a13b0556f176a4 (diff)
downloadgnutls-f8dc2b2fadc889df569b983b2741f0928dcf0bbc.tar.gz
handshake: add callback to get notified with traffic secret change
For the use with QUIC, the change of traffic secrets must be notified _after_ a new epoch is set up for reading or writing, and we can't simply reuse the keylog mechanism. Signed-off-by: Daiki Ueno <ueno@gnu.org>
-rw-r--r--devel/libgnutls-latest-x86_64.abi1
-rw-r--r--devel/symbols.last1
-rw-r--r--doc/Makefile.am2
-rw-r--r--doc/manpages/Makefile.am1
-rw-r--r--lib/constate.c90
-rw-r--r--lib/gnutls_int.h1
-rw-r--r--lib/includes/gnutls/gnutls.h.in24
-rw-r--r--lib/libgnutls.map1
8 files changed, 121 insertions, 0 deletions
diff --git a/devel/libgnutls-latest-x86_64.abi b/devel/libgnutls-latest-x86_64.abi
index 18ae9ff945..8dbbe794b2 100644
--- a/devel/libgnutls-latest-x86_64.abi
+++ b/devel/libgnutls-latest-x86_64.abi
@@ -303,6 +303,7 @@
<elf-symbol name='gnutls_handshake_set_private_extensions' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_handshake_set_random' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_handshake_set_read_function' version='GNUTLS_3_7_0' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='gnutls_handshake_set_secret_function' version='GNUTLS_3_7_0' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_handshake_set_timeout' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_handshake_write' version='GNUTLS_3_7_0' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_hash' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
diff --git a/devel/symbols.last b/devel/symbols.last
index 5c0a8e34cc..3a9be1bc5e 100644
--- a/devel/symbols.last
+++ b/devel/symbols.last
@@ -271,6 +271,7 @@ gnutls_handshake_set_post_client_hello_function@GNUTLS_3_4
gnutls_handshake_set_private_extensions@GNUTLS_3_4
gnutls_handshake_set_random@GNUTLS_3_4
gnutls_handshake_set_read_function@GNUTLS_3_7_0
+gnutls_handshake_set_secret_function@GNUTLS_3_7_0
gnutls_handshake_set_timeout@GNUTLS_3_4
gnutls_handshake_write@GNUTLS_3_7_0
gnutls_hash@GNUTLS_3_4
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 0dd9b9e32f..fd495a83a3 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -1088,6 +1088,8 @@ FUNCS += functions/gnutls_handshake_set_random
FUNCS += functions/gnutls_handshake_set_random.short
FUNCS += functions/gnutls_handshake_set_read_function
FUNCS += functions/gnutls_handshake_set_read_function.short
+FUNCS += functions/gnutls_handshake_set_secret_function
+FUNCS += functions/gnutls_handshake_set_secret_function.short
FUNCS += functions/gnutls_handshake_set_timeout
FUNCS += functions/gnutls_handshake_set_timeout.short
FUNCS += functions/gnutls_handshake_write
diff --git a/doc/manpages/Makefile.am b/doc/manpages/Makefile.am
index 2ecd7389b9..66fb70ab56 100644
--- a/doc/manpages/Makefile.am
+++ b/doc/manpages/Makefile.am
@@ -345,6 +345,7 @@ APIMANS += gnutls_handshake_set_post_client_hello_function.3
APIMANS += gnutls_handshake_set_private_extensions.3
APIMANS += gnutls_handshake_set_random.3
APIMANS += gnutls_handshake_set_read_function.3
+APIMANS += gnutls_handshake_set_secret_function.3
APIMANS += gnutls_handshake_set_timeout.3
APIMANS += gnutls_handshake_write.3
APIMANS += gnutls_hash.3
diff --git a/lib/constate.c b/lib/constate.c
index af6a13598d..3717522d38 100644
--- a/lib/constate.c
+++ b/lib/constate.c
@@ -1109,6 +1109,67 @@ _gnutls_epoch_free(gnutls_session_t session, record_parameters_st * params)
gnutls_free(params);
}
+static int
+_gnutls_call_secret_func(gnutls_session_t session,
+ hs_stage_t stage,
+ bool for_read, bool for_write)
+{
+ const mac_entry_st *prf = NULL;
+ gnutls_record_encryption_level_t level;
+ void *secret_read = NULL, *secret_write = NULL;
+
+ if (session->internals.h_secret_func == NULL)
+ return 0;
+
+ switch (stage) {
+ case STAGE_EARLY:
+ prf = session->key.binders[0].prf;
+ level = GNUTLS_ENCRYPTION_LEVEL_EARLY;
+ if (for_read) {
+ if (unlikely(session->security_parameters.entity == GNUTLS_CLIENT))
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+ secret_read = session->key.proto.tls13.e_ckey;
+ }
+ break;
+ case STAGE_HS:
+ prf = session->security_parameters.prf;
+ level = GNUTLS_ENCRYPTION_LEVEL_HANDSHAKE;
+ if (for_read)
+ secret_read = session->security_parameters.
+ entity == GNUTLS_CLIENT ?
+ session->key.proto.tls13.hs_skey :
+ session->key.proto.tls13.hs_ckey;
+ if (for_write)
+ secret_write = session->security_parameters.
+ entity == GNUTLS_CLIENT ?
+ session->key.proto.tls13.hs_ckey :
+ session->key.proto.tls13.hs_skey;
+ break;
+ case STAGE_APP:
+ case STAGE_UPD_OURS:
+ case STAGE_UPD_PEERS:
+ prf = session->security_parameters.prf;
+ level = GNUTLS_ENCRYPTION_LEVEL_APPLICATION;
+ if (for_read)
+ secret_read = session->security_parameters.
+ entity == GNUTLS_CLIENT ?
+ session->key.proto.tls13.ap_skey :
+ session->key.proto.tls13.ap_ckey;
+ if (for_write)
+ secret_write = session->security_parameters.
+ entity == GNUTLS_CLIENT ?
+ session->key.proto.tls13.ap_ckey :
+ session->key.proto.tls13.ap_skey;
+ break;
+ default:
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+ }
+
+ return session->internals.h_secret_func(session, level,
+ secret_read, secret_write,
+ prf->output_size);
+}
+
int _tls13_connection_state_init(gnutls_session_t session, hs_stage_t stage)
{
const uint16_t epoch_next =
@@ -1126,6 +1187,10 @@ int _tls13_connection_state_init(gnutls_session_t session, hs_stage_t stage)
session->security_parameters.epoch_read = epoch_next;
session->security_parameters.epoch_write = epoch_next;
+ ret = _gnutls_call_secret_func(session, stage, 1, 1);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
return 0;
}
@@ -1145,6 +1210,10 @@ int _tls13_read_connection_state_init(gnutls_session_t session, hs_stage_t stage
session->security_parameters.epoch_read = epoch_next;
+ ret = _gnutls_call_secret_func(session, stage, 1, 0);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
return 0;
}
@@ -1164,6 +1233,10 @@ int _tls13_write_connection_state_init(gnutls_session_t session, hs_stage_t stag
session->security_parameters.epoch_write = epoch_next;
+ ret = _gnutls_call_secret_func(session, stage, 0, 1);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
return 0;
}
@@ -1186,3 +1259,20 @@ _tls13_init_record_state(gnutls_cipher_algorithm_t algo, record_state_st *state)
return 0;
}
+
+/**
+ * gnutls_handshake_set_secret_function:
+ * @session: is a #gnutls_session_t type.
+ * @func: the secret func
+ *
+ * This function will set a callback to be called when a new traffic
+ * secret is installed.
+ *
+ * Since: 3.7.0
+ */
+void
+gnutls_handshake_set_secret_function(gnutls_session_t session,
+ gnutls_handshake_secret_func func)
+{
+ session->internals.h_secret_func = func;
+}
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index b1ed6178c0..182ae6f6c9 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -1233,6 +1233,7 @@ typedef struct {
unsigned int h_type; /* the hooked type */
int16_t h_post; /* whether post-generation/receive */
gnutls_handshake_read_func h_read_func;
+ gnutls_handshake_secret_func h_secret_func;
gnutls_keylog_func keylog_func;
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index 31709117b0..0fe672fa96 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -3241,6 +3241,30 @@ gnutls_handshake_write(gnutls_session_t session,
gnutls_record_encryption_level_t level,
const void *data, size_t data_size);
+ /**
+ * gnutls_handshake_secret_func:
+ * @session: the current session
+ * @level: the encryption level
+ * @secret_read: the secret used for reading, can be %NULL if not set
+ * @secret_write: the secret used for writing, can be %NULL if not set
+ * @secret_size: the size of the secrets
+ *
+ * Function prototype for secret hooks. It is set using
+ * gnutls_handshake_set_secret_function().
+ *
+ * Returns: Non zero on error.
+ * Since: 3.7.0
+ */
+typedef int (*gnutls_handshake_secret_func) (gnutls_session_t session,
+ gnutls_record_encryption_level_t level,
+ const void *secret_read,
+ const void *secret_write,
+ size_t secret_size);
+
+void
+gnutls_handshake_set_secret_function(gnutls_session_t session,
+ gnutls_handshake_secret_func func);
+
/* FIPS140-2 related functions */
unsigned gnutls_fips140_mode_enabled(void);
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 1f9f69e45b..58db94fb78 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1335,6 +1335,7 @@ GNUTLS_3_7_0
{
global:
gnutls_handshake_set_read_function;
+ gnutls_handshake_set_secret_function;
gnutls_handshake_write;
gnutls_x509_trust_list_set_getissuer_function;
gnutls_x509_trust_list_get_ptr;