diff options
author | Daiki Ueno <ueno@gnu.org> | 2020-02-21 17:48:37 +0100 |
---|---|---|
committer | Daiki Ueno <ueno@gnu.org> | 2020-11-19 18:18:38 +0100 |
commit | f8dc2b2fadc889df569b983b2741f0928dcf0bbc (patch) | |
tree | 0fa7dbd59d3d0ab3937adb8f381b8a5597b26f31 | |
parent | e3d6a62938a5a53b89585ace73a13b0556f176a4 (diff) | |
download | gnutls-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.abi | 1 | ||||
-rw-r--r-- | devel/symbols.last | 1 | ||||
-rw-r--r-- | doc/Makefile.am | 2 | ||||
-rw-r--r-- | doc/manpages/Makefile.am | 1 | ||||
-rw-r--r-- | lib/constate.c | 90 | ||||
-rw-r--r-- | lib/gnutls_int.h | 1 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 24 | ||||
-rw-r--r-- | lib/libgnutls.map | 1 |
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; |