diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/constate.c | 34 | ||||
-rw-r--r-- | lib/ext/pre_shared_key.c | 16 | ||||
-rw-r--r-- | lib/gnutls_int.h | 2 | ||||
-rw-r--r-- | lib/handshake-tls13.c | 8 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 53 | ||||
-rw-r--r-- | lib/kx.c | 87 | ||||
-rw-r--r-- | lib/kx.h | 7 | ||||
-rw-r--r-- | lib/libgnutls.map | 1 | ||||
-rw-r--r-- | lib/state.c | 5 |
9 files changed, 189 insertions, 24 deletions
diff --git a/lib/constate.c b/lib/constate.c index 51943ede69..a11577d7ba 100644 --- a/lib/constate.c +++ b/lib/constate.c @@ -197,6 +197,7 @@ _tls13_update_keys(gnutls_session_t session, hs_stage_t stage, char buf[65]; record_state_st *upd_state; record_parameters_st *prev = NULL; + gnutls_handshake_secret_type_t secret_type; int ret; /* generate new keys for direction needed and copy old from previous epoch */ @@ -274,6 +275,7 @@ _tls13_update_keys(gnutls_session_t session, hs_stage_t stage, ret = _tls13_expand_secret(session, "iv", 2, NULL, 0, session->key.proto.tls13.ap_ckey, iv_size, iv_block); if (ret < 0) return gnutls_assert_val(ret); + secret_type = GNUTLS_SECRET_CLIENT_TRAFFIC_SECRET; } else { ret = _tls13_expand_secret(session, APPLICATION_TRAFFIC_UPDATE, sizeof(APPLICATION_TRAFFIC_UPDATE)-1, @@ -291,8 +293,14 @@ _tls13_update_keys(gnutls_session_t session, hs_stage_t stage, ret = _tls13_expand_secret(session, "iv", 2, NULL, 0, session->key.proto.tls13.ap_skey, iv_size, iv_block); if (ret < 0) return gnutls_assert_val(ret); + secret_type = GNUTLS_SECRET_SERVER_TRAFFIC_SECRET; } + ret = _gnutls_call_secret_func(session, secret_type, + key_block, key_size); + if (ret < 0) + return gnutls_assert_val(ret); + upd_state->mac_key_size = 0; assert(key_size <= sizeof(upd_state->key)); @@ -388,7 +396,7 @@ _tls13_set_keys(gnutls_session_t session, hs_stage_t stage, record_state_st *client_write, *server_write; const char *label; unsigned label_size, hsk_len; - const char *keylog_label; + gnutls_handshake_secret_type_t secret_type; void *ckey, *skey; int ret; @@ -404,13 +412,13 @@ _tls13_set_keys(gnutls_session_t session, hs_stage_t stage, label = HANDSHAKE_CLIENT_TRAFFIC_LABEL; label_size = sizeof(HANDSHAKE_CLIENT_TRAFFIC_LABEL)-1; hsk_len = session->internals.handshake_hash_buffer.length; - keylog_label = "CLIENT_HANDSHAKE_TRAFFIC_SECRET"; + secret_type = GNUTLS_SECRET_CLIENT_HANDSHAKE_TRAFFIC_SECRET; ckey = session->key.proto.tls13.hs_ckey; } else { label = APPLICATION_CLIENT_TRAFFIC_LABEL; label_size = sizeof(APPLICATION_CLIENT_TRAFFIC_LABEL)-1; hsk_len = session->internals.handshake_hash_buffer_server_finished_len; - keylog_label = "CLIENT_TRAFFIC_SECRET_0"; + secret_type = GNUTLS_SECRET_CLIENT_TRAFFIC_SECRET; ckey = session->key.proto.tls13.ap_ckey; } @@ -422,9 +430,11 @@ _tls13_set_keys(gnutls_session_t session, hs_stage_t stage, if (ret < 0) return gnutls_assert_val(ret); - _gnutls_nss_keylog_write(session, keylog_label, - ckey, - session->security_parameters.prf->output_size); + ret = _gnutls_call_secret_func(session, secret_type, + ckey, + session->security_parameters.prf->output_size); + if (ret < 0) + return gnutls_assert_val(ret); /* client keys */ ret = _tls13_expand_secret(session, "key", 3, NULL, 0, ckey, key_size, ckey_block); @@ -439,12 +449,12 @@ _tls13_set_keys(gnutls_session_t session, hs_stage_t stage, if (stage == STAGE_HS) { label = HANDSHAKE_SERVER_TRAFFIC_LABEL; label_size = sizeof(HANDSHAKE_SERVER_TRAFFIC_LABEL)-1; - keylog_label = "SERVER_HANDSHAKE_TRAFFIC_SECRET"; + secret_type = GNUTLS_SECRET_SERVER_HANDSHAKE_TRAFFIC_SECRET; skey = session->key.proto.tls13.hs_skey; } else { label = APPLICATION_SERVER_TRAFFIC_LABEL; label_size = sizeof(APPLICATION_SERVER_TRAFFIC_LABEL)-1; - keylog_label = "SERVER_TRAFFIC_SECRET_0"; + secret_type = GNUTLS_SECRET_SERVER_TRAFFIC_SECRET; skey = session->key.proto.tls13.ap_skey; } @@ -457,9 +467,11 @@ _tls13_set_keys(gnutls_session_t session, hs_stage_t stage, if (ret < 0) return gnutls_assert_val(ret); - _gnutls_nss_keylog_write(session, keylog_label, - skey, - session->security_parameters.prf->output_size); + ret = _gnutls_call_secret_func(session, secret_type, + skey, + session->security_parameters.prf->output_size); + if (ret < 0) + return gnutls_assert_val(ret); ret = _tls13_expand_secret(session, "key", 3, NULL, 0, skey, key_size, skey_block); if (ret < 0) diff --git a/lib/ext/pre_shared_key.c b/lib/ext/pre_shared_key.c index d344922910..eef84814d6 100644 --- a/lib/ext/pre_shared_key.c +++ b/lib/ext/pre_shared_key.c @@ -203,9 +203,11 @@ generate_early_secrets(gnutls_session_t session, if (ret < 0) return gnutls_assert_val(ret); - _gnutls_nss_keylog_write(session, "CLIENT_EARLY_TRAFFIC_SECRET", - session->key.proto.tls13.e_ckey, - prf->output_size); + ret = _gnutls_call_secret_func(session, GNUTLS_SECRET_CLIENT_EARLY_TRAFFIC_SECRET, + session->key.proto.tls13.e_ckey, + prf->output_size); + if (ret < 0) + return gnutls_assert_val(ret); ret = _tls13_derive_secret2(prf, EARLY_EXPORTER_MASTER_LABEL, sizeof(EARLY_EXPORTER_MASTER_LABEL)-1, session->internals.handshake_hash_buffer.data, @@ -215,9 +217,11 @@ generate_early_secrets(gnutls_session_t session, if (ret < 0) return gnutls_assert_val(ret); - _gnutls_nss_keylog_write(session, "EARLY_EXPORTER_SECRET", - session->key.proto.tls13.ap_expkey, - prf->output_size); + ret = _gnutls_call_secret_func(session, GNUTLS_SECRET_EARLY_EXPORTER_SECRET, + session->key.proto.tls13.ap_expkey, + prf->output_size); + if (ret < 0) + return gnutls_assert_val(ret); return 0; } diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index b48805190a..cd2adc103d 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -1243,6 +1243,8 @@ typedef struct { unsigned int h_type; /* the hooked type */ int16_t h_post; /* whether post-generation/receive */ + gnutls_handshake_secret_func secret_func; + /* holds the selected certificate and key. * use _gnutls_selected_certs_deinit() and _gnutls_selected_certs_set() * to change them. diff --git a/lib/handshake-tls13.c b/lib/handshake-tls13.c index 60f8030eb3..39d002bd04 100644 --- a/lib/handshake-tls13.c +++ b/lib/handshake-tls13.c @@ -292,9 +292,11 @@ static int generate_ap_traffic_keys(gnutls_session_t session) if (ret < 0) return gnutls_assert_val(ret); - _gnutls_nss_keylog_write(session, "EXPORTER_SECRET", - session->key.proto.tls13.ap_expkey, - session->security_parameters.prf->output_size); + ret = _gnutls_call_secret_func(session, GNUTLS_SECRET_EXPORTER_SECRET, + session->key.proto.tls13.ap_expkey, + session->security_parameters.prf->output_size); + if (ret < 0) + return gnutls_assert_val(ret); _gnutls_epoch_bump(session); ret = _gnutls_epoch_dup(session, EPOCH_READ_CURRENT); diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index d05ef8e5a9..13b6c35659 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -2292,6 +2292,59 @@ void gnutls_global_set_log_function(gnutls_log_func log_func); void gnutls_global_set_audit_log_function(gnutls_audit_log_func log_func); void gnutls_global_set_log_level(int level); +/** + * gnutls_handshake_secret_type_t: + * @GNUTLS_SECRET_CLIENT_RANDOM: 48 bytes for the master secret (for SSL 3.0, + * TLS 1.0, 1.1 and 1.2) + * @GNUTLS_SECRET_CLIENT_EARLY_TRAFFIC_SECRET: the early traffic secret for the + * client side (for TLS 1.3) + * @GNUTLS_SECRET_CLIENT_HANDSHAKE_TRAFFIC_SECRET: the handshake traffic secret + * for the client side (for TLS 1.3) + * @GNUTLS_SECRET_SERVER_HANDSHAKE_TRAFFIC_SECRET: the handshake traffic secret + * for the server side (for TLS 1.3) + * @GNUTLS_SECRET_CLIENT_TRAFFIC_SECRET: the application traffic secret for the + * client side (for TLS 1.3) + * @GNUTLS_SECRET_SERVER_TRAFFIC_SECRET: the application traffic secret for the + * server side (for TLS 1.3) + * @GNUTLS_SECRET_EARLY_EXPORTER_SECRET: the early exporter secret (for TLS 1.3, + * used for 0-RTT keys). + * @GNUTLS_SECRET_EXPORTER_SECRET: the exporter secret (for TLS 1.3, used for + * 1-RTT keys) + * + * Enumeration of different types of secrets derived during handshake. + * This is used by gnutls_handshake_set_secret_function(). + * + * Since: 3.6.13 + */ +typedef enum { + GNUTLS_SECRET_CLIENT_RANDOM, + GNUTLS_SECRET_CLIENT_EARLY_TRAFFIC_SECRET, + GNUTLS_SECRET_CLIENT_HANDSHAKE_TRAFFIC_SECRET, + GNUTLS_SECRET_SERVER_HANDSHAKE_TRAFFIC_SECRET, + GNUTLS_SECRET_CLIENT_TRAFFIC_SECRET, + GNUTLS_SECRET_SERVER_TRAFFIC_SECRET, + GNUTLS_SECRET_EARLY_EXPORTER_SECRET, + GNUTLS_SECRET_EXPORTER_SECRET +} gnutls_handshake_secret_type_t; + + /** + * gnutls_handshake_secret_function: + * @session: the current session + * @type: #gnutls_handshake_secret_type_t + * @secret: the (const) data of the derived secret. + * + * Function prototype for secret derivation hooks. It is set using + * gnutls_handshake_set_secret_function(). + * + * Returns: Non zero on error. + * Since: 3.6.13 + */ +typedef int (*gnutls_handshake_secret_func) (gnutls_session_t session, + gnutls_handshake_secret_type_t type, + const gnutls_datum_t *secret); +void gnutls_handshake_set_secret_function(gnutls_session_t session, + gnutls_handshake_secret_func func); + /* Diffie-Hellman parameter handling. */ int gnutls_dh_params_init(gnutls_dh_params_t * dh_params); @@ -70,6 +70,83 @@ int _gnutls_generate_master(gnutls_session_t session, int keep_premaster) return 0; } +/** + * gnutls_handshake_set_secret_function: + * @session: is #gnutls_session_t type + * @func: is the function to be called + * + * This function will set a callback to be called when a new secret is + * derived and installed during handshake. + * + * Since: 3.6.13 + */ +void +gnutls_handshake_set_secret_function(gnutls_session_t session, + gnutls_handshake_secret_func func) +{ + session->internals.secret_func = func; +} + +int +_gnutls_call_secret_func(gnutls_session_t session, + gnutls_handshake_secret_type_t type, + const uint8_t *data, + unsigned size) +{ + if (session->internals.secret_func) { + gnutls_datum_t secret = {(void*)data, size}; + return session->internals.secret_func(session, type, &secret); + } + return 0; +} + +static const char * +secret_type_to_nss_keylog_label(gnutls_handshake_secret_type_t type) +{ + switch (type) { + case GNUTLS_SECRET_CLIENT_RANDOM: + return "CLIENT_RANDOM"; + case GNUTLS_SECRET_CLIENT_EARLY_TRAFFIC_SECRET: + return "CLIENT_EARLY_TRAFFIC_SECRET"; + case GNUTLS_SECRET_CLIENT_HANDSHAKE_TRAFFIC_SECRET: + return "CLIENT_HANDSHAKE_TRAFFIC_SECRET"; + case GNUTLS_SECRET_SERVER_HANDSHAKE_TRAFFIC_SECRET: + return "SERVER_HANDSHAKE_TRAFFIC_SECRET"; + case GNUTLS_SECRET_CLIENT_TRAFFIC_SECRET: + return "CLIENT_TRAFFIC_SECRET_0"; + case GNUTLS_SECRET_SERVER_TRAFFIC_SECRET: + return "SERVER_TRAFFIC_SECRET_0"; + case GNUTLS_SECRET_EARLY_EXPORTER_SECRET: + return "EARLY_EXPORTER_SECRET"; + case GNUTLS_SECRET_EXPORTER_SECRET: + return "EXPORTER_SECRET"; + default: + gnutls_assert(); + return NULL; + } +} + +int +_gnutls_nss_keylog_secret_func(gnutls_session_t session, + gnutls_handshake_secret_type_t type, + const gnutls_datum_t *secret) +{ + const char *label; + + /* ignore subsequent traffic secrets that are calculated from + * the previous traffic secret + */ + if (!session->internals.handshake_in_progress) + return 0; + + label = secret_type_to_nss_keylog_label(type); + if (unlikely(label == NULL)) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + + _gnutls_nss_keylog_write(session, label, secret->data, secret->size); + return 0; +} + void _gnutls_nss_keylog_write(gnutls_session_t session, const char *label, const uint8_t *secret, size_t secret_size) @@ -182,16 +259,18 @@ generate_normal_master(gnutls_session_t session, gnutls_free(shash.data); } - _gnutls_nss_keylog_write(session, "CLIENT_RANDOM", - session->security_parameters.master_secret, - GNUTLS_MASTER_SIZE); - if (!keep_premaster) _gnutls_free_temp_key_datum(premaster); if (ret < 0) return ret; + ret = _gnutls_call_secret_func(session, GNUTLS_SECRET_CLIENT_RANDOM, + session->security_parameters.master_secret, + GNUTLS_MASTER_SIZE); + if (ret < 0) + return gnutls_assert_val(ret); + _gnutls_hard_log("INT: MASTER SECRET[%d]: %s\n", GNUTLS_MASTER_SIZE, _gnutls_bin2hex(session->security_parameters. @@ -38,8 +38,15 @@ int _gnutls_recv_server_crt_request(gnutls_session_t session); int _gnutls_send_server_crt_request(gnutls_session_t session, int again); int _gnutls_recv_client_certificate_verify_message(gnutls_session_t session); +int _gnutls_call_secret_func(gnutls_session_t session, + gnutls_handshake_secret_type_t type, + const uint8_t *data, + unsigned size); void _gnutls_nss_keylog_write(gnutls_session_t session, const char *label, const uint8_t *secret, size_t secret_size); +int _gnutls_nss_keylog_secret_func(gnutls_session_t session, + gnutls_handshake_secret_type_t type, + const gnutls_datum_t *secret); #endif /* GNUTLS_LIB_KX_H */ diff --git a/lib/libgnutls.map b/lib/libgnutls.map index bf8fff8bc3..c1aace905e 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -1315,6 +1315,7 @@ GNUTLS_3_6_13 gnutls_hkdf_extract; gnutls_hkdf_expand; gnutls_pbkdf2; + gnutls_handshake_set_secret_function; } GNUTLS_3_6_12; GNUTLS_FIPS140_3_4 { diff --git a/lib/state.c b/lib/state.c index dff7312a87..f33cd5a8bc 100644 --- a/lib/state.c +++ b/lib/state.c @@ -54,6 +54,7 @@ #include "tls13/session_ticket.h" #include "ext/cert_types.h" #include "locks.h" +#include "kx.h" /* to be used by supplemental data support to disable TLS1.3 * when supplemental data have been globally registered */ @@ -587,6 +588,10 @@ int gnutls_init(gnutls_session_t * session, unsigned int flags) if (_gnutls_disable_tls13 != 0) (*session)->internals.flags |= INT_FLAG_NO_TLS13; + /* Install the default secret function */ + gnutls_handshake_set_secret_function(*session, + _gnutls_nss_keylog_secret_func); + return 0; } |