diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2017-06-12 14:19:23 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2017-06-14 16:07:49 +0200 |
commit | 5d927146d1c96c7230b889d6841d58115dd2f901 (patch) | |
tree | b4f301e900d51f5e55ecd085eabc2bddf617f69d | |
parent | bf6a599fcb6fdfc49dabdcb6d98a330670a19c26 (diff) | |
download | gnutls-5d927146d1c96c7230b889d6841d58115dd2f901.tar.gz |
TLS extensions: several simplifications
This allows extensions set by the application to override some
of the internal ones.
Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
-rw-r--r-- | lib/ext/safe_renegotiation.c | 2 | ||||
-rw-r--r-- | lib/extensions.c | 253 | ||||
-rw-r--r-- | lib/extensions.h | 2 | ||||
-rw-r--r-- | lib/gnutls_int.h | 12 | ||||
-rw-r--r-- | lib/handshake.c | 6 | ||||
-rw-r--r-- | lib/state.c | 2 |
6 files changed, 133 insertions, 144 deletions
diff --git a/lib/ext/safe_renegotiation.c b/lib/ext/safe_renegotiation.c index d2579f3422..d8cb933a19 100644 --- a/lib/ext/safe_renegotiation.c +++ b/lib/ext/safe_renegotiation.c @@ -219,7 +219,7 @@ int _gnutls_ext_sr_recv_cs(gnutls_session_t session) priv->safe_renegotiation_received = 1; priv->connection_using_safe_renegotiation = 1; - _gnutls_extension_list_add(session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION); + _gnutls_extension_list_add_sr(session); if (set != 0) _gnutls_ext_set_session_data(session, diff --git a/lib/extensions.c b/lib/extensions.c index a42c733615..129528b215 100644 --- a/lib/extensions.c +++ b/lib/extensions.c @@ -105,57 +105,33 @@ static gnutls_ext_parse_type_t _gnutls_ext_parse_type(gnutls_session_t session, return GNUTLS_EXT_NONE; } -static gnutls_ext_recv_func -_gnutls_ext_func_recv(gnutls_session_t session, uint16_t type, gnutls_ext_parse_type_t parse_type) +static const extension_entry_st * +_gnutls_ext_ptr(gnutls_session_t session, uint16_t type, gnutls_ext_parse_type_t parse_type) { - size_t i; + unsigned i; + const extension_entry_st *e; for (i=0;i<session->internals.rexts_size;i++) { - if (session->internals.rexts[i].type == type) - if (parse_type == GNUTLS_EXT_ANY - || session->internals.rexts[i].parse_type == parse_type) - return session->internals.rexts[i].recv_func; + if (session->internals.rexts[i].type == type) { + e = &session->internals.rexts[i]; + goto done; + } } - for (i = 0; extfunc[i] != NULL; i++) - if (extfunc[i]->type == type) - if (parse_type == GNUTLS_EXT_ANY - || extfunc[i]->parse_type == parse_type) - return extfunc[i]->recv_func; - - return NULL; -} - -static gnutls_ext_deinit_data_func _gnutls_ext_func_deinit(gnutls_session_t session, uint16_t type) -{ - size_t i; - - for (i=0;i<session->internals.rexts_size;i++) { - if (session->internals.rexts[i].type == type) - return session->internals.rexts[i].deinit_func; + for (i = 0; extfunc[i] != NULL; i++) { + if (extfunc[i]->type == type) { + e = extfunc[i]; + goto done; + } } - for (i = 0; extfunc[i] != NULL; i++) - if (extfunc[i]->type == type) - return extfunc[i]->deinit_func; - return NULL; -} - -static gnutls_ext_unpack_func _gnutls_ext_func_unpack(gnutls_session_t session, uint16_t type) -{ - size_t i; - - for (i=0;i<session->internals.rexts_size;i++) { - if (session->internals.rexts[i].type == type) - return session->internals.rexts[i].unpack_func; +done: + if (parse_type == GNUTLS_EXT_ANY || e->parse_type == parse_type) { + return e; + } else { + return NULL; } - - for (i = 0; extfunc[i] != NULL; i++) - if (extfunc[i]->type == type) - return extfunc[i]->unpack_func; - - return NULL; } @@ -186,16 +162,43 @@ const char *gnutls_ext_get_name(unsigned int ext) int _gnutls_extension_list_check(gnutls_session_t session, uint16_t type) { - int i; + unsigned i; - for (i = 0; i < session->internals.extensions_sent_size; i++) { - if (type == session->internals.extensions_sent[i]) - return 0; /* ok found */ + for (i = 0; i < session->internals.used_exts_size; i++) { + if (type == session->internals.used_exts[i]->type) + return 0; } return GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION; } +/* Adds the extension we want to send in the extensions list. + * This list is used in client side to check whether the (later) received + * extensions are the ones we requested. + * + * In server side, this list is used to ensure we don't send + * extensions that we didn't receive a corresponding value. + */ +static void _gnutls_extension_list_add(gnutls_session_t session, const struct extension_entry_st *e) +{ + + if (session->internals.used_exts_size < MAX_EXT_TYPES) { + session->internals.used_exts[session-> + internals.used_exts_size] + = e; + session->internals.used_exts_size++; + } else { + _gnutls_handshake_log + ("extensions: Increase MAX_EXT_TYPES\n"); + } +} + +void _gnutls_extension_list_add_sr(gnutls_session_t session) +{ + _gnutls_extension_list_add(session, &ext_mod_sr); +} + + int _gnutls_parse_extensions(gnutls_session_t session, gnutls_ext_parse_type_t parse_type, @@ -205,7 +208,7 @@ _gnutls_parse_extensions(gnutls_session_t session, int pos = 0; uint16_t type; const uint8_t *sdata; - gnutls_ext_recv_func ext_recv; + const extension_entry_st *ext; uint16_t size; #ifdef DEBUG @@ -259,10 +262,10 @@ _gnutls_parse_extensions(gnutls_session_t session, sdata = &data[pos]; pos += size; - ext_recv = _gnutls_ext_func_recv(session, type, parse_type); - if (ext_recv == NULL) { + ext = _gnutls_ext_ptr(session, type, parse_type); + if (ext == NULL || ext->recv_func == NULL) { _gnutls_handshake_log - ("EXT[%p]: Found extension '%s/%d'\n", session, + ("EXT[%p]: Ignoring extension '%s/%d'\n", session, gnutls_ext_get_name(type), type); continue; @@ -270,7 +273,7 @@ _gnutls_parse_extensions(gnutls_session_t session, /* only store the extension number if we support it */ if (session->security_parameters.entity == GNUTLS_SERVER) { - _gnutls_extension_list_add(session, type); + _gnutls_extension_list_add(session, ext); } _gnutls_handshake_log @@ -278,7 +281,7 @@ _gnutls_parse_extensions(gnutls_session_t session, session, gnutls_ext_get_name(type), type, size); - if ((ret = ext_recv(session, sdata, size)) < 0) { + if ((ret = ext->recv_func(session, sdata, size)) < 0) { gnutls_assert(); return ret; } @@ -293,28 +296,6 @@ _gnutls_parse_extensions(gnutls_session_t session, } -/* Adds the extension we want to send in the extensions list. - * This list is used in client side to check whether the (later) received - * extensions are the ones we requested. - * - * In server side, this list is used to ensure we don't send - * extensions that we didn't receive a corresponding value. - */ -void _gnutls_extension_list_add(gnutls_session_t session, uint16_t type) -{ - - if (session->internals.extensions_sent_size < - MAX_EXT_TYPES) { - session->internals.extensions_sent[session-> - internals.extensions_sent_size] - = type; - session->internals.extensions_sent_size++; - } else { - _gnutls_handshake_log - ("extensions: Increase MAX_EXT_TYPES\n"); - } -} - static int send_extension(gnutls_session_t session, const extension_entry_st *p, gnutls_buffer_st *extdata, gnutls_ext_parse_type_t parse_type) @@ -328,12 +309,16 @@ int send_extension(gnutls_session_t session, const extension_entry_st *p, && p->parse_type != parse_type) return 0; - /* ensure we are sending only what we received */ + /* ensure we don't send something twice (i.e, overriden extensions in + * client), and ensure we are sending only what we received in server. */ + ret = _gnutls_extension_list_check(session, p->type); + if (session->security_parameters.entity == GNUTLS_SERVER) { - if ((ret = - _gnutls_extension_list_check(session, p->type)) < 0) { + if (ret < 0) /* not advertized */ + return 0; + } else { + if (ret == 0) /* already sent */ return 0; - } } ret = _gnutls_buffer_append_prefix(extdata, 16, p->type); @@ -360,7 +345,7 @@ int send_extension(gnutls_session_t session, const extension_entry_st *p, /* add this extension to the extension list */ if (session->security_parameters.entity == GNUTLS_CLIENT) - _gnutls_extension_list_add(session, p->type); + _gnutls_extension_list_add(session, p); _gnutls_handshake_log ("EXT[%p]: Sending extension %s (%d bytes)\n", @@ -382,7 +367,6 @@ _gnutls_gen_extensions(gnutls_session_t session, int size; int pos, ret; size_t i, init_size = extdata->length; - const extension_entry_st *extp; pos = extdata->length; /* we will store length later on */ @@ -390,18 +374,16 @@ _gnutls_gen_extensions(gnutls_session_t session, if (ret < 0) return gnutls_assert_val(ret); - for (i=0;i<session->internals.rexts_size;i++) { - extp = &session->internals.rexts[i]; - - ret = send_extension(session, extp, extdata, parse_type); + for (i=0; i < session->internals.rexts_size; i++) { + ret = send_extension(session, &session->internals.rexts[i], extdata, parse_type); if (ret < 0) return gnutls_assert_val(ret); } + /* send_extension() ensures we don't send duplicates, in case + * of overriden extensions */ for (i = 0; extfunc[i] != NULL; i++) { - extp = extfunc[i]; - - ret = send_extension(session, extp, extdata, parse_type); + ret = send_extension(session, extfunc[i], extdata, parse_type); if (ret < 0) return gnutls_assert_val(ret); } @@ -420,6 +402,7 @@ _gnutls_gen_extensions(gnutls_session_t session, return size; } +/* Global deinit and init of global extensions */ int _gnutls_ext_init(void) { return GNUTLS_E_SUCCESS; @@ -455,6 +438,7 @@ int ext_register(extension_entry_st * mod) return GNUTLS_E_SUCCESS; } +/* Packing of extension data (for use in resumption) */ static int pack_extension(gnutls_session_t session, const extension_entry_st *extp, gnutls_buffer_st *packed) { @@ -500,17 +484,8 @@ int _gnutls_ext_pack(gnutls_session_t session, gnutls_buffer_st *packed) total_exts_pos = packed->length; BUFFER_APPEND_NUM(packed, 0); - for (i = 0; i < session->internals.rexts_size; i++) { - ret = pack_extension(session, &session->internals.rexts[i], packed); - if (ret < 0) - return gnutls_assert_val(ret); - - if (ret > 0) - exts++; - } - - for (i = 0; extfunc[i] != NULL; i++) { - ret = pack_extension(session, extfunc[i], packed); + for (i = 0; i < session->internals.used_exts_size; i++) { + ret = pack_extension(session, session->internals.used_exts[i], packed); if (ret < 0) return gnutls_assert_val(ret); @@ -596,11 +571,10 @@ int _gnutls_ext_unpack(gnutls_session_t session, gnutls_buffer_st * packed) { int i, ret; gnutls_ext_priv_data_t data; - gnutls_ext_unpack_func unpack; int max_exts = 0; uint16_t type; int size_for_type, cur_pos; - + const struct extension_entry_st *ext; BUFFER_POP_NUM(packed, max_exts); for (i = 0; i < max_exts; i++) { @@ -609,13 +583,13 @@ int _gnutls_ext_unpack(gnutls_session_t session, gnutls_buffer_st * packed) cur_pos = packed->length; - unpack = _gnutls_ext_func_unpack(session, type); - if (unpack == NULL) { + ext = _gnutls_ext_ptr(session, type, GNUTLS_EXT_ANY); + if (ext == NULL || ext->unpack_func == NULL) { gnutls_assert(); return GNUTLS_E_PARSING_ERROR; } - ret = unpack(packed, &data); + ret = ext->unpack_func(packed, &data); if (ret < 0) { gnutls_assert(); return ret; @@ -638,17 +612,18 @@ int _gnutls_ext_unpack(gnutls_session_t session, gnutls_buffer_st * packed) } void -_gnutls_ext_unset_session_data(gnutls_session_t session, uint16_t type) +_gnutls_ext_unset_session_data(gnutls_session_t session, + uint16_t type) { - gnutls_ext_deinit_data_func deinit; gnutls_ext_priv_data_t data; int ret, i; + const struct extension_entry_st *ext; - deinit = _gnutls_ext_func_deinit(session, type); - ret = _gnutls_ext_get_session_data(session, type, &data); + ext = _gnutls_ext_ptr(session, type, GNUTLS_EXT_ANY); - if (ret >= 0 && deinit != NULL) { - deinit(data); + ret = _gnutls_ext_get_session_data(session, type, &data); + if (ret >= 0 && ext && ext->deinit_func) { + ext->deinit_func(data); } for (i = 0; i < MAX_EXT_TYPES; i++) { @@ -664,20 +639,21 @@ static void _gnutls_ext_unset_resumed_session_data(gnutls_session_t session, uint16_t type) { - gnutls_ext_deinit_data_func deinit; gnutls_ext_priv_data_t data; int ret, i; - deinit = _gnutls_ext_func_deinit(session, type); - ret = _gnutls_ext_get_resumed_session_data(session, type, &data); + const struct extension_entry_st *ext; + + ext = _gnutls_ext_ptr(session, type, GNUTLS_EXT_ANY); - if (ret >= 0 && deinit != NULL) { - deinit(data); + ret = _gnutls_ext_get_resumed_session_data(session, type, &data); + if (ret >= 0 && ext && ext->deinit_func) { + ext->deinit_func(data); } for (i = 0; i < MAX_EXT_TYPES; i++) { if (session->internals.resumed_extension_int_data[i]. - type == type) { + type == ext->type) { session->internals.resumed_extension_int_data[i]. set = 0; return; @@ -692,18 +668,11 @@ void _gnutls_ext_free_session_data(gnutls_session_t session) { unsigned int i; - for (i = 0; i < session->internals.rexts_size; i++) { - _gnutls_ext_unset_session_data(session, session->internals.rexts[i].type); - _gnutls_ext_unset_resumed_session_data(session, - session->internals.rexts[i].type); - } - - for (i = 0; extfunc[i] != NULL; i++) { - _gnutls_ext_unset_session_data(session, extfunc[i]->type); + for (i = 0; i < session->internals.used_exts_size; i++) { + _gnutls_ext_unset_session_data(session, session->internals.used_exts[i]->type); _gnutls_ext_unset_resumed_session_data(session, - extfunc[i]->type); + session->internals.used_exts[i]->type); } - } /* This function allows an extension to store data in the current session @@ -715,17 +684,17 @@ _gnutls_ext_set_session_data(gnutls_session_t session, uint16_t type, gnutls_ext_priv_data_t data) { unsigned int i; - gnutls_ext_deinit_data_func deinit; + const struct extension_entry_st *ext; - deinit = _gnutls_ext_func_deinit(session, type); + ext = _gnutls_ext_ptr(session, type, GNUTLS_EXT_ANY); for (i = 0; i < MAX_EXT_TYPES; i++) { if (session->internals.extension_int_data[i].type == type || session->internals.extension_int_data[i].set == 0) { if (session->internals.extension_int_data[i].set != 0) { - if (deinit) - deinit(session->internals. + if (ext && ext->deinit_func) + ext->deinit_func(session->internals. extension_int_data[i].priv); } session->internals.extension_int_data[i].type = @@ -880,12 +849,32 @@ gnutls_session_ext_register(gnutls_session_t session, extension_entry_st *exts; unsigned i; - /* FIXME: handle GNUTLS_EXT_FLAG_OVERRIDE_INTERNAL for new exts */ - for (i = 0; extfunc[i] != NULL; i++) { - if (extfunc[i]->type == type) + /* reject handling any extensions which modify the TLS handshake + * in any way, or are mapped to an exported API. */ + switch(type) { + case GNUTLS_EXTENSION_SRP: + case GNUTLS_EXTENSION_ALPN: + case GNUTLS_EXTENSION_STATUS_REQUEST: + case GNUTLS_EXTENSION_CERT_TYPE: + case GNUTLS_EXTENSION_SUPPORTED_ECC: + case GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS: + case GNUTLS_EXTENSION_ETM: + case GNUTLS_EXTENSION_EXT_MASTER_SECRET: + case GNUTLS_EXTENSION_SESSION_TICKET: + case GNUTLS_EXTENSION_SAFE_RENEGOTIATION: + case GNUTLS_EXTENSION_HEARTBEAT: + case GNUTLS_EXTENSION_SRTP: + case GNUTLS_EXTENSION_SERVER_NAME: return gnutls_assert_val(GNUTLS_E_ALREADY_REGISTERED); } + if (!flags & GNUTLS_EXT_FLAG_OVERRIDE_INTERNAL) { + for (i = 0; extfunc[i] != NULL; i++) { + if (extfunc[i]->type == type) + return gnutls_assert_val(GNUTLS_E_ALREADY_REGISTERED); + } + } + tmp_mod.name = NULL; tmp_mod.free_struct = 1; tmp_mod.type = type; diff --git a/lib/extensions.h b/lib/extensions.h index b531ebae30..c50005c273 100644 --- a/lib/extensions.h +++ b/lib/extensions.h @@ -34,7 +34,7 @@ int _gnutls_gen_extensions(gnutls_session_t session, int _gnutls_ext_init(void); void _gnutls_ext_deinit(void); -void _gnutls_extension_list_add(gnutls_session_t session, uint16_t type); +void _gnutls_extension_list_add_sr(gnutls_session_t session); int _gnutls_extension_list_check(gnutls_session_t session, uint16_t type); void _gnutls_ext_free_session_data(gnutls_session_t session); diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index d4573e1859..7bb39780b6 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -892,11 +892,6 @@ typedef struct { gnutls_status_request_ocsp_func selected_ocsp_func; void *selected_ocsp_func_ptr; - /* In case of a client holds the extensions we sent to the peer; - * otherwise the extensions we received from the client. - */ - uint16_t extensions_sent[MAX_EXT_TYPES]; - uint16_t extensions_sent_size; /* is 0 if we are to send the whole PGP key, or non zero * if the fingerprint is to be sent. @@ -1057,6 +1052,13 @@ typedef struct { struct extension_entry_st *rexts; unsigned rexts_size; + + /* In case of a client holds the extensions we sent to the peer; + * otherwise the extensions we received from the client. + */ + const struct extension_entry_st *used_exts[MAX_EXT_TYPES]; + unsigned used_exts_size; + /* If you add anything here, check _gnutls_handshake_internal_state_clear(). */ } internals_st; diff --git a/lib/handshake.c b/lib/handshake.c index b2ac9359d1..d62fd5b89c 100644 --- a/lib/handshake.c +++ b/lib/handshake.c @@ -85,6 +85,7 @@ handshake_hash_buffer_empty(gnutls_session_t session) _gnutls_buffers_log("BUF[HSK]: Emptied buffer\n"); + session->internals.used_exts_size = 0; session->internals.handshake_hash_buffer_prev_len = 0; session->internals.handshake_hash_buffer.length = 0; return; @@ -2074,8 +2075,7 @@ static int send_client_hello(gnutls_session_t session, int again) copy_ciphersuites(session, &extdata, TRUE); if (session->security_parameters.entity == GNUTLS_CLIENT) - _gnutls_extension_list_add(session, - GNUTLS_EXTENSION_SAFE_RENEGOTIATION); + _gnutls_extension_list_add_sr(session); } else #endif ret = @@ -2545,7 +2545,7 @@ int gnutls_handshake(gnutls_session_t session) if (session->internals.priorities.protocol.algorithms == 0) return gnutls_assert_val(GNUTLS_E_NO_PRIORITIES_WERE_SET); - session->internals.extensions_sent_size = 0; + session->internals.used_exts_size = 0; session->internals.crt_requested = 0; session->internals.handshake_in_progress = 1; session->internals.vc_status = -1; diff --git a/lib/state.c b/lib/state.c index b1cb578742..eb69e643de 100644 --- a/lib/state.c +++ b/lib/state.c @@ -397,8 +397,6 @@ int gnutls_init(gnutls_session_t * session, unsigned int flags) _gnutls_handshake_internal_state_init(*session); - (*session)->internals.extensions_sent_size = 0; - /* emulate old gnutls behavior for old applications that do not use the priority_* * functions. */ |