summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2017-09-18 10:52:51 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2017-09-18 14:37:36 +0200
commite42543b8599e5feb70b117e6d0c366af4ef99203 (patch)
tree119c26b316ffda97185f9f79b728e26eac7983dc
parent15737adc7a03ce59263953b3c2c7e550367eb836 (diff)
downloadgnutls-e42543b8599e5feb70b117e6d0c366af4ef99203.tar.gz
extensions: TLS extension handling functions use state
That is, they can now store and accept a structure to store information neeeded to retrieve and send extensions. That is necessary to handle extensions which are only valid for specific messages but not for the global session. Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
-rw-r--r--lib/Makefile.am4
-rw-r--r--lib/algorithms/ciphersuites.c3
-rw-r--r--lib/extensions.c427
-rw-r--r--lib/extensions.h21
-rw-r--r--lib/extv.c344
-rw-r--r--lib/extv.h69
-rw-r--r--lib/gnutls_int.h38
-rw-r--r--lib/handshake.c93
-rw-r--r--lib/state.c2
-rw-r--r--lib/x509.c3
10 files changed, 575 insertions, 429 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 3442a6c443..98256a03a6 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -79,7 +79,7 @@ COBJECTS = range.c record.c compress.c debug.c cipher.c \
safe-memfuncs.c system/inet_pton.c atfork.c atfork.h randomart.c \
system-keys.h urls.c urls.h prf.c auto-verify.c dh-session.c \
cert-session.c handshake-checks.c dtls-sw.c dh-primes.c openpgp_compat.c \
- crypto-selftests.c crypto-selftests-pk.c secrets.c
+ crypto-selftests.c crypto-selftests-pk.c secrets.c extv.c
if WINDOWS
COBJECTS += system/keys-win.c
@@ -110,7 +110,7 @@ HFILES = abstract_int.h debug.h cipher.h \
srp.h auth/srp_kx.h auth/srp_passwd.h \
file.h supplemental.h crypto.h random.h system.h\
locks.h mbuffers.h ecc.h pin.h fips.h \
- priority_options.h secrets.h
+ priority_options.h secrets.h extv.h
if ENABLE_PKCS11
HFILES += pkcs11_int.h pkcs11x.h
diff --git a/lib/algorithms/ciphersuites.c b/lib/algorithms/ciphersuites.c
index 0c562012f6..6448d7ab79 100644
--- a/lib/algorithms/ciphersuites.c
+++ b/lib/algorithms/ciphersuites.c
@@ -31,6 +31,7 @@
#include <auth/anon.h>
#include <auth/psk.h>
#include <ext/safe_renegotiation.h>
+#include "extv.h"
#ifndef ENABLE_SSL3
# define GNUTLS_SSL3 GNUTLS_TLS1
@@ -1457,7 +1458,7 @@ _gnutls_figure_common_ciphersuite(gnutls_session_t session,
* by RFC4492, probably to allow SSLv2 hellos negotiate elliptic curve
* ciphersuites */
if (session->internals.cand_ec_group == NULL &&
- _gnutls_extension_list_check(session, GNUTLS_EXTENSION_SUPPORTED_ECC) < 0) {
+ _gnutls_extv_check_saved(&session->internals.hello_ext, GNUTLS_EXTENSION_SUPPORTED_ECC) < 0) {
session->internals.cand_ec_group = _gnutls_id_to_group(DEFAULT_EC_GROUP);
}
diff --git a/lib/extensions.c b/lib/extensions.c
index c3ff1f5bde..2b94f016b7 100644
--- a/lib/extensions.c
+++ b/lib/extensions.c
@@ -48,14 +48,11 @@
#include <ext/key_share.h>
#include <ext/etm.h>
#include <num.h>
-
-static void
-unset_ext_data(gnutls_session_t session, const struct extension_entry_st *, unsigned idx);
+#include "extv.h"
static int ext_register(extension_entry_st * mod);
-static void unset_resumed_ext_data(gnutls_session_t session, const struct extension_entry_st *, unsigned idx);
-static extension_entry_st const *extfunc[MAX_EXT_TYPES+1] = {
+extension_entry_st const *_gnutls_extfunc[MAX_EXT_TYPES+1] = {
&ext_mod_max_record_size,
&ext_mod_ext_master_secret,
&ext_mod_supported_versions,
@@ -91,22 +88,22 @@ static extension_entry_st const *extfunc[MAX_EXT_TYPES+1] = {
NULL
};
-static const extension_entry_st *
-_gnutls_ext_ptr(gnutls_session_t session, uint16_t id, gnutls_ext_parse_type_t parse_type)
+const extension_entry_st *
+_gnutls_ext_ptr(tls_ext_vals_st *v, uint16_t id, gnutls_ext_parse_type_t parse_type)
{
unsigned i;
const extension_entry_st *e;
- for (i=0;i<session->internals.rexts_size;i++) {
- if (session->internals.rexts[i].id == id) {
- e = &session->internals.rexts[i];
+ for (i=0;i<v->rexts_size;i++) {
+ if (v->rexts[i].id == id) {
+ e = &v->rexts[i];
goto done;
}
}
- for (i = 0; extfunc[i] != NULL; i++) {
- if (extfunc[i]->id == id) {
- e = extfunc[i];
+ for (i = 0; _gnutls_extfunc[i] != NULL; i++) {
+ if (_gnutls_extfunc[i]->id == id) {
+ e = _gnutls_extfunc[i];
goto done;
}
}
@@ -134,282 +131,17 @@ const char *gnutls_ext_get_name(unsigned int ext)
{
size_t i;
- for (i = 0; extfunc[i] != NULL; i++)
- if (extfunc[i]->id == ext)
- return extfunc[i]->name;
+ for (i = 0; _gnutls_extfunc[i] != NULL; i++)
+ if (_gnutls_extfunc[i]->id == ext)
+ return _gnutls_extfunc[i]->name;
return NULL;
}
-/* Checks if the extension @id provided has been requested
- * by us (in client side). In that case it returns zero,
- * otherwise a negative error value.
- */
-int
-_gnutls_extension_list_check(gnutls_session_t session, uint16_t id)
-{
- unsigned i;
-
- for (i = 0; i < session->internals.used_exts_size; i++) {
- if (id == session->internals.used_exts[i]->id)
- 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.
- *
- * Returns zero if failed, non-zero on success.
- */
-static unsigned _gnutls_extension_list_add(gnutls_session_t session, const struct extension_entry_st *e, unsigned check_dup)
-{
- unsigned i;
-
- if (check_dup) {
- for (i=0;i<session->internals.used_exts_size;i++) {
- if (session->internals.used_exts[i]->id == e->id)
- return 0;
- }
- }
-
- if (session->internals.used_exts_size < MAX_EXT_TYPES) {
- session->internals.used_exts[session->
- internals.used_exts_size]
- = e;
- session->internals.used_exts_size++;
- return 1;
- } else {
- _gnutls_handshake_log
- ("extensions: Increase MAX_EXT_TYPES\n");
- return 0;
- }
-}
void _gnutls_extension_list_add_sr(gnutls_session_t session)
{
- _gnutls_extension_list_add(session, &ext_mod_sr, 1);
-}
-
-
-int
-_gnutls_parse_extensions(gnutls_session_t session,
- gnutls_ext_flags_t msg,
- gnutls_ext_parse_type_t parse_type,
- const uint8_t * data, int data_size)
-{
- int next, ret;
- int pos = 0;
- uint16_t id;
- const uint8_t *sdata;
- const extension_entry_st *ext;
- uint16_t size;
-
- if (data_size == 0)
- return 0;
-
- DECR_LENGTH_RET(data_size, 2, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
- next = _gnutls_read_uint16(data);
- pos += 2;
-
- DECR_LENGTH_RET(data_size, next, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
-
- if (next == 0 && data_size == 0) /* field is present, but has zero length? Ignore it. */
- return 0;
- else if (data_size > 0) /* forbid unaccounted data */
- return gnutls_assert_val(GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
-
- do {
- DECR_LENGTH_RET(next, 2, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
- id = _gnutls_read_uint16(&data[pos]);
- pos += 2;
-
- if (session->security_parameters.entity == GNUTLS_CLIENT) {
- if ((ret =
- _gnutls_extension_list_check(session, id)) < 0) {
- _gnutls_debug_log("EXT[%p]: Received unexpected extension '%s/%d'\n", session,
- gnutls_ext_get_name(id), (int)id);
- gnutls_assert();
- return ret;
- }
- }
-
- DECR_LENGTH_RET(next, 2, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
- size = _gnutls_read_uint16(&data[pos]);
- pos += 2;
-
- DECR_LENGTH_RET(next, size, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
- sdata = &data[pos];
- pos += size;
-
- ext = _gnutls_ext_ptr(session, id, parse_type);
- if (ext == NULL || ext->recv_func == NULL) {
- _gnutls_handshake_log
- ("EXT[%p]: Ignoring extension '%s/%d'\n", session,
- gnutls_ext_get_name(id), id);
-
- continue;
- }
-
-
- if ((ext->validity & msg) == 0) {
-
- _gnutls_debug_log("EXT[%p]: Received unexpected extension (%s/%d) for '%s'\n", session,
- gnutls_ext_get_name(id), (int)id,
- ext_msg_validity_to_str(msg));
- return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
- }
-
- if (session->security_parameters.entity == GNUTLS_SERVER) {
- ret = _gnutls_extension_list_add(session, ext, 1);
- if (ret == 0)
- return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
- }
-
- _gnutls_handshake_log
- ("EXT[%p]: Parsing extension '%s/%d' (%d bytes)\n",
- session, gnutls_ext_get_name(id), id,
- size);
-
- if ((ret = ext->recv_func(session, sdata, size)) < 0) {
- gnutls_assert();
- return ret;
- }
- }
- while (next > 2);
-
- /* forbid leftovers */
- if (next > 0)
- return gnutls_assert_val(GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
-
- return 0;
-
-}
-
-static
-int send_extension(gnutls_session_t session, const extension_entry_st *p,
- gnutls_buffer_st *extdata,
- gnutls_ext_flags_t msg,
- gnutls_ext_parse_type_t parse_type)
-{
- int size_pos, appended, ret;
- size_t size_prev;
-
- if (p->send_func == NULL)
- return 0;
-
- if (parse_type != GNUTLS_EXT_ANY
- && p->parse_type != parse_type)
- return 0;
-
- if ((msg & p->validity) == 0) {
- _gnutls_handshake_log("EXT[%p]: Not sending extension (%s/%d) for '%s'\n", session,
- gnutls_ext_get_name(p->id), (int)p->id,
- ext_msg_validity_to_str(msg));
- return 0;
- }
-
- /* 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->id);
-
- if (session->security_parameters.entity == GNUTLS_SERVER) {
- if (ret < 0) /* not advertized */
- return 0;
- } else {
- if (ret == 0) /* already sent */
- return 0;
- }
-
- ret = _gnutls_buffer_append_prefix(extdata, 16, p->id);
- if (ret < 0)
- return gnutls_assert_val(ret);
-
- size_pos = extdata->length;
- ret = _gnutls_buffer_append_prefix(extdata, 16, 0);
- if (ret < 0)
- return gnutls_assert_val(ret);
-
- size_prev = extdata->length;
- ret = p->send_func(session, extdata);
- if (ret < 0 && ret != GNUTLS_E_INT_RET_0) {
- return gnutls_assert_val(ret);
- }
-
- /* returning GNUTLS_E_INT_RET_0 means to send an empty
- * extension of this type.
- */
- appended = extdata->length - size_prev;
-
- if (appended > 0 || ret == GNUTLS_E_INT_RET_0) {
- if (ret == GNUTLS_E_INT_RET_0)
- appended = 0;
-
- /* write the real size */
- _gnutls_write_uint16(appended,
- &extdata->data[size_pos]);
-
- /* add this extension to the extension list
- */
- if (session->security_parameters.entity == GNUTLS_CLIENT)
- _gnutls_extension_list_add(session, p, 0);
-
- _gnutls_handshake_log
- ("EXT[%p]: Sending extension %s/%d (%d bytes)\n",
- session, p->name, p->id, appended);
- } else if (appended == 0)
- extdata->length -= 4; /* reset type and size */
-
- return 0;
-}
-
-int
-_gnutls_gen_extensions(gnutls_session_t session,
- gnutls_buffer_st * extdata,
- gnutls_ext_flags_t msg,
- gnutls_ext_parse_type_t parse_type)
-{
- int size;
- int pos, ret;
- size_t i, init_size = extdata->length;
-
- pos = extdata->length; /* we will store length later on */
-
- ret = _gnutls_buffer_append_prefix(extdata, 16, 0);
- if (ret < 0)
- return gnutls_assert_val(ret);
-
- for (i=0; i < session->internals.rexts_size; i++) {
- ret = send_extension(session, &session->internals.rexts[i], extdata, msg, 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++) {
- ret = send_extension(session, extfunc[i], extdata, msg, parse_type);
- if (ret < 0)
- return gnutls_assert_val(ret);
- }
-
- /* remove any initial data, and the size of the header */
- size = extdata->length - init_size - 2;
-
- if (size > UINT16_MAX) /* sent too many extensions */
- return gnutls_assert_val(GNUTLS_E_HANDSHAKE_TOO_LARGE);
-
- if (size > 0)
- _gnutls_write_uint16(size, &extdata->data[pos]);
- else if (size == 0)
- extdata->length -= 2; /* the length bytes */
-
- return size;
+ _gnutls_extv_add_saved(&session->internals.hello_ext, &ext_mod_sr, 1);
}
/* Global deinit and init of global extensions */
@@ -421,11 +153,11 @@ int _gnutls_ext_init(void)
void _gnutls_ext_deinit(void)
{
unsigned i;
- for (i = 0; extfunc[i] != NULL; i++) {
- if (extfunc[i]->free_struct != 0) {
- gnutls_free((void*)extfunc[i]->name);
- gnutls_free((void*)extfunc[i]);
- extfunc[i] = NULL;
+ for (i = 0; _gnutls_extfunc[i] != NULL; i++) {
+ if (_gnutls_extfunc[i]->free_struct != 0) {
+ gnutls_free((void*)_gnutls_extfunc[i]->name);
+ gnutls_free((void*)_gnutls_extfunc[i]);
+ _gnutls_extfunc[i] = NULL;
}
}
}
@@ -435,7 +167,7 @@ int ext_register(extension_entry_st * mod)
{
unsigned i = 0;
- while(extfunc[i] != NULL) {
+ while(_gnutls_extfunc[i] != NULL) {
i++;
}
@@ -443,8 +175,8 @@ int ext_register(extension_entry_st * mod)
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
}
- extfunc[i] = mod;
- extfunc[i+1] = NULL;
+ _gnutls_extfunc[i] = mod;
+ _gnutls_extfunc[i+1] = NULL;
return GNUTLS_E_SUCCESS;
}
@@ -490,12 +222,13 @@ int _gnutls_ext_pack(gnutls_session_t session, gnutls_buffer_st *packed)
int ret;
int total_exts_pos;
int exts = 0;
+ tls_ext_vals_st *v = &session->internals.hello_ext;
total_exts_pos = packed->length;
BUFFER_APPEND_NUM(packed, 0);
- for (i = 0; i < session->internals.used_exts_size; i++) {
- ret = pack_extension(session, session->internals.used_exts[i], packed);
+ for (i = 0; i < v->used_exts_size; i++) {
+ ret = pack_extension(session, v->used_exts[i], packed);
if (ret < 0)
return gnutls_assert_val(ret);
@@ -515,19 +248,20 @@ _gnutls_ext_set_resumed_session_data(gnutls_session_t session,
{
int i;
const struct extension_entry_st *ext;
+ tls_ext_vals_st *vals = &session->internals.hello_ext;
- ext = _gnutls_ext_ptr(session, id, GNUTLS_EXT_ANY);
+ ext = _gnutls_ext_ptr(vals, id, GNUTLS_EXT_ANY);
for (i = 0; i < MAX_EXT_TYPES; i++) {
- if (session->internals.ext_data[i].id == id
- || (!session->internals.ext_data[i].resumed_set && !session->internals.ext_data[i].set)) {
+ if (vals->ext_data[i].id == id
+ || (!vals->ext_data[i].resumed_set && !vals->ext_data[i].set)) {
- if (session->internals.ext_data[i].resumed_set != 0)
- unset_resumed_ext_data(session, ext, i);
+ if (vals->ext_data[i].resumed_set != 0)
+ _gnutls_extv_data_unset_resumed(&vals->ext_data[i], ext);
- session->internals.ext_data[i].id = id;
- session->internals.ext_data[i].resumed_priv = data;
- session->internals.ext_data[i].resumed_set = 1;
+ vals->ext_data[i].id = id;
+ vals->ext_data[i].resumed_priv = data;
+ vals->ext_data[i].resumed_set = 1;
return;
}
}
@@ -549,7 +283,7 @@ int _gnutls_ext_unpack(gnutls_session_t session, gnutls_buffer_st * packed)
cur_pos = packed->length;
- ext = _gnutls_ext_ptr(session, id, GNUTLS_EXT_ANY);
+ ext = _gnutls_ext_ptr(&session->internals.hello_ext, id, GNUTLS_EXT_ANY);
if (ext == NULL || ext->unpack_func == NULL) {
gnutls_assert();
return GNUTLS_E_PARSING_ERROR;
@@ -577,61 +311,30 @@ int _gnutls_ext_unpack(gnutls_session_t session, gnutls_buffer_st * packed)
return ret;
}
-static void
-unset_ext_data(gnutls_session_t session, const struct extension_entry_st *ext, unsigned idx)
-{
- if (session->internals.ext_data[idx].set == 0)
- return;
-
- if (ext && ext->deinit_func && session->internals.ext_data[idx].priv != NULL)
- ext->deinit_func(session->internals.ext_data[idx].priv);
- session->internals.ext_data[idx].set = 0;
-}
-
void
_gnutls_ext_unset_session_data(gnutls_session_t session,
- uint16_t id)
+ uint16_t id)
{
int i;
const struct extension_entry_st *ext;
- ext = _gnutls_ext_ptr(session, id, GNUTLS_EXT_ANY);
+ ext = _gnutls_ext_ptr(&session->internals.hello_ext, id, GNUTLS_EXT_ANY);
for (i = 0; i < MAX_EXT_TYPES; i++) {
- if (session->internals.ext_data[i].id == id) {
- unset_ext_data(session, ext, i);
+ if (session->internals.hello_ext.ext_data[i].id == id) {
+ _gnutls_extv_data_unset(&session->internals.hello_ext.ext_data[i], ext);
return;
}
}
}
-static void unset_resumed_ext_data(gnutls_session_t session, const struct extension_entry_st *ext, unsigned idx)
-{
- if (session->internals.ext_data[idx].resumed_set == 0)
- return;
- if (ext && ext->deinit_func && session->internals.ext_data[idx].resumed_priv) {
- ext->deinit_func(session->internals.ext_data[idx].resumed_priv);
- }
- session->internals.ext_data[idx].resumed_set = 0;
-}
/* Deinitializes all data that are associated with TLS extensions.
*/
void _gnutls_ext_free_session_data(gnutls_session_t session)
{
- unsigned int i;
- const struct extension_entry_st *ext;
-
- for (i = 0; i < MAX_EXT_TYPES; i++) {
- if (!session->internals.ext_data[i].set && !session->internals.ext_data[i].resumed_set)
- continue;
-
- ext = _gnutls_ext_ptr(session, session->internals.ext_data[i].id, GNUTLS_EXT_ANY);
-
- unset_ext_data(session, ext, i);
- unset_resumed_ext_data(session, ext, i);
- }
+ _gnutls_extv_deinit(&session->internals.hello_ext);
}
/* This function allows an extension to store data in the current session
@@ -644,19 +347,20 @@ _gnutls_ext_set_session_data(gnutls_session_t session, uint16_t id,
{
unsigned int i;
const struct extension_entry_st *ext;
+ tls_ext_vals_st *v = &session->internals.hello_ext;
- ext = _gnutls_ext_ptr(session, id, GNUTLS_EXT_ANY);
+ ext = _gnutls_ext_ptr(v, id, GNUTLS_EXT_ANY);
for (i = 0; i < MAX_EXT_TYPES; i++) {
- if (session->internals.ext_data[i].id == id ||
- (!session->internals.ext_data[i].set && !session->internals.ext_data[i].resumed_set)) {
+ if (v->ext_data[i].id == id ||
+ (!v->ext_data[i].set && !v->ext_data[i].resumed_set)) {
- if (session->internals.ext_data[i].set != 0) {
- unset_ext_data(session, ext, i);
+ if (v->ext_data[i].set != 0) {
+ _gnutls_extv_data_unset(&v->ext_data[i], ext);
}
- session->internals.ext_data[i].id = id;
- session->internals.ext_data[i].priv = data;
- session->internals.ext_data[i].set = 1;
+ v->ext_data[i].id = id;
+ v->ext_data[i].priv = data;
+ v->ext_data[i].set = 1;
return;
}
}
@@ -667,13 +371,14 @@ _gnutls_ext_get_session_data(gnutls_session_t session,
uint16_t id, gnutls_ext_priv_data_t * data)
{
int i;
+ tls_ext_vals_st *v = &session->internals.hello_ext;
for (i = 0; i < MAX_EXT_TYPES; i++) {
- if (session->internals.ext_data[i].set != 0 &&
- session->internals.ext_data[i].id == id)
+ if (v->ext_data[i].set != 0 &&
+ v->ext_data[i].id == id)
{
*data =
- session->internals.ext_data[i].priv;
+ v->ext_data[i].priv;
return 0;
}
}
@@ -686,12 +391,13 @@ _gnutls_ext_get_resumed_session_data(gnutls_session_t session,
gnutls_ext_priv_data_t * data)
{
int i;
+ tls_ext_vals_st *v = &session->internals.hello_ext;
for (i = 0; i < MAX_EXT_TYPES; i++) {
- if (session->internals.ext_data[i].resumed_set != 0
- && session->internals.ext_data[i].id == id) {
+ if (v->ext_data[i].resumed_set != 0
+ && v->ext_data[i].id == id) {
*data =
- session->internals.ext_data[i].resumed_priv;
+ v->ext_data[i].resumed_priv;
return 0;
}
}
@@ -736,8 +442,8 @@ gnutls_ext_register(const char *name, int id, gnutls_ext_parse_type_t parse_type
int ret;
unsigned i;
- for (i = 0; extfunc[i] != NULL; i++) {
- if (extfunc[i]->id == id)
+ for (i = 0; _gnutls_extfunc[i] != NULL; i++) {
+ if (_gnutls_extfunc[i]->id == id)
return gnutls_assert_val(GNUTLS_E_ALREADY_REGISTERED);
}
@@ -813,14 +519,15 @@ gnutls_session_ext_register(gnutls_session_t session,
extension_entry_st tmp_mod;
extension_entry_st *exts;
unsigned i;
+ tls_ext_vals_st *v = &session->internals.hello_ext;
/* reject handling any extensions which modify the TLS handshake
* in any way, or are mapped to an exported API. */
- for (i = 0; extfunc[i] != NULL; i++) {
- if (extfunc[i]->id == id) {
+ for (i = 0; _gnutls_extfunc[i] != NULL; i++) {
+ if (_gnutls_extfunc[i]->id == id) {
if (!(flags & GNUTLS_EXT_FLAG_OVERRIDE_INTERNAL)) {
return gnutls_assert_val(GNUTLS_E_ALREADY_REGISTERED);
- } else if (extfunc[i]->cannot_be_overriden) {
+ } else if (_gnutls_extfunc[i]->cannot_be_overriden) {
return gnutls_assert_val(GNUTLS_E_ALREADY_REGISTERED);
}
break;
@@ -842,15 +549,15 @@ gnutls_session_ext_register(gnutls_session_t session,
tmp_mod.validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO|GNUTLS_EXT_FLAG_EE;
}
- exts = gnutls_realloc(session->internals.rexts, (session->internals.rexts_size+1)*sizeof(*exts));
+ exts = gnutls_realloc(v->rexts, (v->rexts_size+1)*sizeof(*exts));
if (exts == NULL) {
return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
}
- session->internals.rexts = exts;
+ v->rexts = exts;
- memcpy(&session->internals.rexts[session->internals.rexts_size], &tmp_mod, sizeof(extension_entry_st));
- session->internals.rexts_size++;
+ memcpy(&v->rexts[v->rexts_size], &tmp_mod, sizeof(extension_entry_st));
+ v->rexts_size++;
return 0;
}
diff --git a/lib/extensions.h b/lib/extensions.h
index 3ef9d445c2..ce36a034a0 100644
--- a/lib/extensions.h
+++ b/lib/extensions.h
@@ -25,26 +25,20 @@
#include <gnutls/gnutls.h>
-int _gnutls_parse_extensions(gnutls_session_t session,
- gnutls_ext_flags_t msg,
- gnutls_ext_parse_type_t parse_type,
- const uint8_t * data, int data_size);
-int _gnutls_gen_extensions(gnutls_session_t session,
- gnutls_buffer_st * extdata,
- gnutls_ext_flags_t msg,
- gnutls_ext_parse_type_t);
+
+/* Session and generic TLS extensions handling functions */
+
int _gnutls_ext_init(void);
void _gnutls_ext_deinit(void);
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);
/* functions to be used by extensions internally
*/
-void _gnutls_ext_unset_session_data(gnutls_session_t session,
- uint16_t type);
+void _gnutls_ext_unset_session_data(gnutls_session_t session, uint16_t id);
+
void _gnutls_ext_set_session_data(gnutls_session_t session, uint16_t type,
gnutls_ext_priv_data_t);
int _gnutls_ext_get_session_data(gnutls_session_t session, uint16_t type,
@@ -118,4 +112,9 @@ typedef struct extension_entry_st {
int _gnutls_ext_register(extension_entry_st *);
+const extension_entry_st *
+_gnutls_ext_ptr(tls_ext_vals_st *v, uint16_t id, gnutls_ext_parse_type_t parse_type);
+
+extern extension_entry_st const *_gnutls_extfunc[];
+
#endif
diff --git a/lib/extv.c b/lib/extv.c
new file mode 100644
index 0000000000..fe9126465a
--- /dev/null
+++ b/lib/extv.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2001-2016 Free Software Foundation, Inc.
+ * Copyright (C) 2015-2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos, Simon Josefsson
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/* Functions that relate to TLS extension parsing.
+ */
+
+#include "gnutls_int.h"
+#include "extv.h"
+#include "extensions.h"
+
+void
+_gnutls_extv_data_unset_resumed(struct ext_data_st *data, const struct extension_entry_st *ext)
+{
+ if (data->resumed_set == 0)
+ return;
+
+ if (ext && ext->deinit_func && data->resumed_priv) {
+ ext->deinit_func(data->resumed_priv);
+ }
+ data->resumed_set = 0;
+}
+
+void
+_gnutls_extv_data_unset(struct ext_data_st *data, const struct extension_entry_st *ext)
+{
+ if (data->set == 0)
+ return;
+
+ if (ext && ext->deinit_func && data->priv != NULL)
+ ext->deinit_func(data->priv);
+ data->set = 0;
+}
+
+void _gnutls_extv_deinit(tls_ext_vals_st *v)
+{
+ unsigned int i;
+ const struct extension_entry_st *ext;
+
+ v->used_exts_size = 0;
+
+ for (i = 0; i < MAX_EXT_TYPES; i++) {
+ if (!v->ext_data[i].set && !v->ext_data[i].resumed_set)
+ continue;
+
+ ext = _gnutls_ext_ptr(v, v->ext_data[i].id, GNUTLS_EXT_ANY);
+
+ _gnutls_extv_data_unset(&v->ext_data[i], ext);
+ _gnutls_extv_data_unset_resumed(&v->ext_data[i], ext);
+ }
+
+ gnutls_free(v->rexts);
+ v->rexts = NULL;
+}
+
+/* Checks if the extension @id provided has been requested
+ * by us (in client side). In that case it returns zero,
+ * otherwise a negative error value.
+ */
+int
+_gnutls_extv_check_saved(tls_ext_vals_st *v, uint16_t id)
+{
+ unsigned i;
+
+ for (i = 0; i < v->used_exts_size; i++) {
+ if (id == v->used_exts[i]->id)
+ 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.
+ *
+ * Returns zero if failed, non-zero on success.
+ */
+unsigned _gnutls_extv_add_saved(tls_ext_vals_st *v, const struct extension_entry_st *e, unsigned check_dup)
+{
+ unsigned i;
+
+ if (check_dup) {
+ for (i=0;i<v->used_exts_size;i++) {
+ if (v->used_exts[i]->id == e->id)
+ return 0;
+ }
+ }
+
+ if (v->used_exts_size < MAX_EXT_TYPES) {
+ v->used_exts[v->used_exts_size] = e;
+ v->used_exts_size++;
+ return 1;
+ } else {
+ _gnutls_handshake_log
+ ("extensions: Increase MAX_EXT_TYPES\n");
+ return 0;
+ }
+}
+
+int
+_gnutls_extv_parse(gnutls_session_t session,
+ gnutls_ext_flags_t msg,
+ gnutls_ext_parse_type_t parse_type,
+ const uint8_t * data, int data_size,
+ tls_ext_vals_st *out,
+ unsigned extv_flags)
+{
+ int next, ret;
+ int pos = 0;
+ uint16_t id;
+ const uint8_t *sdata;
+ const extension_entry_st *ext;
+ uint16_t size;
+
+ if (data_size == 0)
+ return 0;
+
+ DECR_LENGTH_RET(data_size, 2, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
+ next = _gnutls_read_uint16(data);
+ pos += 2;
+
+ DECR_LENGTH_RET(data_size, next, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
+
+ if (next == 0 && data_size == 0) /* field is present, but has zero length? Ignore it. */
+ return 0;
+ else if (data_size > 0) /* forbid unaccounted data */
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
+
+ do {
+ DECR_LENGTH_RET(next, 2, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
+ id = _gnutls_read_uint16(&data[pos]);
+ pos += 2;
+
+ if (extv_flags & EXTV_CHECK_UNADVERTIZED) {
+ if ((ret =
+ _gnutls_extv_check_saved(out, id)) < 0) {
+ _gnutls_debug_log("EXT[%p]: Received unexpected extension '%s/%d'\n", session,
+ gnutls_ext_get_name(id), (int)id);
+ gnutls_assert();
+ return ret;
+ }
+ }
+
+ DECR_LENGTH_RET(next, 2, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
+ size = _gnutls_read_uint16(&data[pos]);
+ pos += 2;
+
+ DECR_LENGTH_RET(next, size, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
+ sdata = &data[pos];
+ pos += size;
+
+ ext = _gnutls_ext_ptr(out, id, parse_type);
+ if (ext == NULL || ext->recv_func == NULL) {
+ _gnutls_handshake_log
+ ("EXT[%p]: Ignoring extension '%s/%d'\n", session,
+ gnutls_ext_get_name(id), id);
+
+ continue;
+ }
+
+
+ if ((ext->validity & msg) == 0) {
+
+ _gnutls_debug_log("EXT[%p]: Received unexpected extension (%s/%d) for '%s'\n", session,
+ gnutls_ext_get_name(id), (int)id,
+ ext_msg_validity_to_str(msg));
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
+ }
+
+ if (extv_flags & EXTV_SAVE_RECEIVED) {
+ ret = _gnutls_extv_add_saved(out, ext, 1);
+ if (ret == 0)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
+ }
+
+ _gnutls_handshake_log
+ ("EXT[%p]: Parsing extension '%s/%d' (%d bytes)\n",
+ session, gnutls_ext_get_name(id), id,
+ size);
+
+ if ((ret = ext->recv_func(session, sdata, size)) < 0) {
+ gnutls_assert();
+ return ret;
+ }
+ }
+ while (next > 2);
+
+ /* forbid leftovers */
+ if (next > 0)
+ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
+
+ return 0;
+}
+
+static
+int send_extension(gnutls_session_t session,
+ tls_ext_vals_st *v,
+ const extension_entry_st *p,
+ gnutls_buffer_st *extdata,
+ gnutls_ext_flags_t msg,
+ gnutls_ext_parse_type_t parse_type,
+ unsigned extv_flags)
+{
+ int size_pos, appended, ret;
+ size_t size_prev;
+
+ if (p->send_func == NULL)
+ return 0;
+
+ if (parse_type != GNUTLS_EXT_ANY
+ && p->parse_type != parse_type)
+ return 0;
+
+ if ((msg & p->validity) == 0) {
+ _gnutls_handshake_log("EXT[%p]: Not sending extension (%s/%d) for '%s'\n", session,
+ gnutls_ext_get_name(p->id), (int)p->id,
+ ext_msg_validity_to_str(msg));
+ return 0;
+ }
+
+ /* 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_extv_check_saved(v, p->id);
+
+ if (extv_flags & EXTV_SEND_SAVED_ONLY) {
+ if (ret < 0) /* not advertized */
+ return 0;
+ }
+
+ if (session->security_parameters.entity == GNUTLS_CLIENT) {
+ if (ret == 0) /* already sent */
+ return 0;
+ }
+
+ ret = _gnutls_buffer_append_prefix(extdata, 16, p->id);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ size_pos = extdata->length;
+ ret = _gnutls_buffer_append_prefix(extdata, 16, 0);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ size_prev = extdata->length;
+ ret = p->send_func(session, extdata);
+ if (ret < 0 && ret != GNUTLS_E_INT_RET_0) {
+ return gnutls_assert_val(ret);
+ }
+
+ /* returning GNUTLS_E_INT_RET_0 means to send an empty
+ * extension of this type.
+ */
+ appended = extdata->length - size_prev;
+
+ if (appended > 0 || ret == GNUTLS_E_INT_RET_0) {
+ if (ret == GNUTLS_E_INT_RET_0)
+ appended = 0;
+
+ /* write the real size */
+ _gnutls_write_uint16(appended,
+ &extdata->data[size_pos]);
+
+ /* add this extension to the extension list
+ */
+ if (session->security_parameters.entity == GNUTLS_CLIENT)
+ _gnutls_extv_add_saved(v, p, 0);
+
+ _gnutls_handshake_log
+ ("EXT[%p]: Sending extension %s/%d (%d bytes)\n",
+ session, p->name, p->id, appended);
+ } else if (appended == 0)
+ extdata->length -= 4; /* reset type and size */
+
+ return 0;
+}
+
+int
+_gnutls_extv_gen(gnutls_session_t session,
+ tls_ext_vals_st *v,
+ gnutls_buffer_st * extdata,
+ gnutls_ext_flags_t msg,
+ gnutls_ext_parse_type_t parse_type,
+ unsigned extv_flags)
+{
+ int size;
+ int pos, ret;
+ size_t i, init_size = extdata->length;
+
+ pos = extdata->length; /* we will store length later on */
+
+ ret = _gnutls_buffer_append_prefix(extdata, 16, 0);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ for (i=0; i < v->rexts_size; i++) {
+ ret = send_extension(session, v, &v->rexts[i], extdata, msg, parse_type, extv_flags);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ }
+
+ /* send_extension() ensures we don't send duplicates, in case
+ * of overriden extensions */
+ for (i = 0; _gnutls_extfunc[i] != NULL; i++) {
+ ret = send_extension(session, v, _gnutls_extfunc[i], extdata, msg, parse_type, extv_flags);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ }
+
+ /* remove any initial data, and the size of the header */
+ size = extdata->length - init_size - 2;
+
+ if (size > UINT16_MAX) /* sent too many extensions */
+ return gnutls_assert_val(GNUTLS_E_HANDSHAKE_TOO_LARGE);
+
+ if (size > 0)
+ _gnutls_write_uint16(size, &extdata->data[pos]);
+ else if (size == 0)
+ extdata->length -= 2; /* the length bytes */
+
+ return size;
+}
diff --git a/lib/extv.h b/lib/extv.h
new file mode 100644
index 0000000000..ed706019e4
--- /dev/null
+++ b/lib/extv.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_EXTV_H
+#define GNUTLS_EXTV_H
+
+#include <gnutls/gnutls.h>
+
+/* ext-val handling functions */
+
+#define _gnutls_extv_init(v) \
+ memset(v, 0, sizeof(tls_ext_vals_st))
+
+void _gnutls_extv_deinit(tls_ext_vals_st *v);
+
+/* check whether any non-advertized extension is present.
+ * Requires a vals updated by extv_gen */
+#define EXTV_CHECK_UNADVERTIZED 1
+
+/* Server-behavior for hello. Save extensions received, and
+ * check for duplicates */
+#define EXTV_SAVE_RECEIVED (1<<1)
+
+/* When sending, do not send any extensions that have not
+ * been advertized by the other party */
+#define EXTV_SEND_SAVED_ONLY (1<<2)
+
+int _gnutls_extv_parse(gnutls_session_t session,
+ gnutls_ext_flags_t msg,
+ gnutls_ext_parse_type_t parse_type,
+ const uint8_t * data, int data_size,
+ tls_ext_vals_st *out,
+ unsigned extv_flags);
+
+int _gnutls_extv_gen(gnutls_session_t session,
+ tls_ext_vals_st *vals,
+ gnutls_buffer_st * extdata,
+ gnutls_ext_flags_t msg,
+ gnutls_ext_parse_type_t,
+ unsigned extv_flags);
+
+void
+_gnutls_extv_data_unset(struct ext_data_st *data, const struct extension_entry_st *ext);
+void
+_gnutls_extv_data_unset_resumed(struct ext_data_st *data, const struct extension_entry_st *ext);
+
+int _gnutls_extv_check_saved(tls_ext_vals_st *v, uint16_t id);
+unsigned _gnutls_extv_add_saved(tls_ext_vals_st *v, const struct extension_entry_st *e, unsigned check_dup);
+
+#endif
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index 52c1c72e65..db3d655b25 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -853,6 +853,26 @@ typedef struct tfo_st {
socklen_t connect_addrlen;
} tfo_st;
+typedef struct tls_ext_vals_st
+{
+ /* 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;
+
+ struct extension_entry_st *rexts;
+ unsigned rexts_size;
+
+ struct ext_data_st {
+ uint16_t id;
+ gnutls_ext_priv_data_t priv;
+ gnutls_ext_priv_data_t resumed_priv;
+ uint8_t set;
+ uint8_t resumed_set;
+ } ext_data[MAX_EXT_TYPES];
+} tls_ext_vals_st;
+
typedef struct {
/* holds all the parsed data received by the record layer */
mbuffer_head_st record_buffer;
@@ -1121,22 +1141,8 @@ typedef struct {
struct gnutls_supplemental_entry_st *rsup;
unsigned rsup_size;
- struct extension_entry_st *rexts;
- unsigned rexts_size;
-
- struct {
- uint16_t id;
- gnutls_ext_priv_data_t priv;
- gnutls_ext_priv_data_t resumed_priv;
- uint8_t set;
- uint8_t resumed_set;
- } ext_data[MAX_EXT_TYPES];
-
- /* 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;
+ /* extensions received during client or server hello */
+ tls_ext_vals_st hello_ext;
/* this is not the negotiated max_record_recv_size, but the actual maximum
* receive size */
diff --git a/lib/handshake.c b/lib/handshake.c
index cfaa290505..4745e2e72f 100644
--- a/lib/handshake.c
+++ b/lib/handshake.c
@@ -38,6 +38,7 @@
#include "hash_int.h"
#include "db.h"
#include "extensions.h"
+#include "extv.h"
#include "supplemental.h"
#include "auth.h"
#include "sslv2_compat.h"
@@ -79,7 +80,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.hello_ext.used_exts_size = 0;
session->internals.handshake_hash_buffer_prev_len = 0;
session->internals.handshake_hash_buffer.length = 0;
return;
@@ -544,9 +545,11 @@ read_client_hello(gnutls_session_t session, uint8_t * data,
* resumed ones.
*/
ret =
- _gnutls_parse_extensions(session, GNUTLS_EXT_FLAG_CLIENT_HELLO,
+ _gnutls_extv_parse(session, GNUTLS_EXT_FLAG_CLIENT_HELLO,
GNUTLS_EXT_MANDATORY,
- ext_ptr, ext_size);
+ ext_ptr, ext_size,
+ &session->internals.hello_ext,
+ EXTV_SAVE_RECEIVED);
if (ret < 0) {
gnutls_assert();
return ret;
@@ -585,9 +588,11 @@ read_client_hello(gnutls_session_t session, uint8_t * data,
* Unconditionally try to parse extensions; safe renegotiation uses them in
* sslv3 and higher, even though sslv3 doesn't officially support them.
*/
- ret = _gnutls_parse_extensions(session, GNUTLS_EXT_FLAG_CLIENT_HELLO,
+ ret = _gnutls_extv_parse(session, GNUTLS_EXT_FLAG_CLIENT_HELLO,
GNUTLS_EXT_APPLICATION,
- ext_ptr, ext_size);
+ ext_ptr, ext_size,
+ &session->internals.hello_ext,
+ EXTV_SAVE_RECEIVED);
/* len is the rest of the parsed length */
if (ret < 0) {
gnutls_assert();
@@ -603,8 +608,10 @@ read_client_hello(gnutls_session_t session, uint8_t * data,
/* Session tickets are parsed in this point */
ret =
- _gnutls_parse_extensions(session, GNUTLS_EXT_FLAG_CLIENT_HELLO,
- GNUTLS_EXT_TLS, ext_ptr, ext_size);
+ _gnutls_extv_parse(session, GNUTLS_EXT_FLAG_CLIENT_HELLO,
+ GNUTLS_EXT_TLS, ext_ptr, ext_size,
+ &session->internals.hello_ext,
+ EXTV_SAVE_RECEIVED);
if (ret < 0) {
gnutls_assert();
return ret;
@@ -658,8 +665,10 @@ read_client_hello(gnutls_session_t session, uint8_t * data,
/* call extensions that are intended to be parsed after the ciphersuite/cert
* are known. */
ret =
- _gnutls_parse_extensions(session, GNUTLS_EXT_FLAG_CLIENT_HELLO,
- _GNUTLS_EXT_TLS_POST_CS, ext_ptr, ext_size);
+ _gnutls_extv_parse(session, GNUTLS_EXT_FLAG_CLIENT_HELLO,
+ _GNUTLS_EXT_TLS_POST_CS, ext_ptr, ext_size,
+ &session->internals.hello_ext,
+ EXTV_SAVE_RECEIVED);
if (ret < 0) {
gnutls_assert();
return ret;
@@ -1572,9 +1581,11 @@ read_server_hello(gnutls_session_t session,
DECR_LEN(len, 2 + 1);
ret =
- _gnutls_parse_extensions(session, GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
+ _gnutls_extv_parse(session, GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
GNUTLS_EXT_MANDATORY,
- &data[pos], len);
+ &data[pos], len,
+ &session->internals.hello_ext,
+ EXTV_CHECK_UNADVERTIZED);
if (ret < 0) {
gnutls_assert();
return ret;
@@ -1610,34 +1621,42 @@ read_server_hello(gnutls_session_t session,
/* Parse extensions in order.
*/
ret =
- _gnutls_parse_extensions(session,
- ext_parse_flag,
- GNUTLS_EXT_MANDATORY,
- &data[pos], len);
+ _gnutls_extv_parse(session,
+ ext_parse_flag,
+ GNUTLS_EXT_MANDATORY,
+ &data[pos], len,
+ &session->internals.hello_ext,
+ EXTV_CHECK_UNADVERTIZED);
if (ret < 0)
return gnutls_assert_val(ret);
ret =
- _gnutls_parse_extensions(session,
- ext_parse_flag,
- GNUTLS_EXT_APPLICATION,
- &data[pos], len);
+ _gnutls_extv_parse(session,
+ ext_parse_flag,
+ GNUTLS_EXT_APPLICATION,
+ &data[pos], len,
+ &session->internals.hello_ext,
+ EXTV_CHECK_UNADVERTIZED);
if (ret < 0)
return gnutls_assert_val(ret);
ret =
- _gnutls_parse_extensions(session,
- ext_parse_flag,
- GNUTLS_EXT_TLS,
- &data[pos], len);
+ _gnutls_extv_parse(session,
+ ext_parse_flag,
+ GNUTLS_EXT_TLS,
+ &data[pos], len,
+ &session->internals.hello_ext,
+ EXTV_CHECK_UNADVERTIZED);
if (ret < 0)
return gnutls_assert_val(ret);
ret =
- _gnutls_parse_extensions(session,
- ext_parse_flag,
- _GNUTLS_EXT_TLS_POST_CS,
- &data[pos], len);
+ _gnutls_extv_parse(session,
+ ext_parse_flag,
+ _GNUTLS_EXT_TLS_POST_CS,
+ &data[pos], len,
+ &session->internals.hello_ext,
+ EXTV_CHECK_UNADVERTIZED);
if (ret < 0)
return gnutls_assert_val(ret);
@@ -1835,9 +1854,10 @@ static int send_client_hello(gnutls_session_t session, int again)
}
ret =
- _gnutls_gen_extensions(session, &extdata,
+ _gnutls_extv_gen(session, &session->internals.hello_ext,
+ &extdata,
GNUTLS_EXT_FLAG_CLIENT_HELLO,
- type);
+ type, 0);
if (ret < 0) {
gnutls_assert();
goto cleanup;
@@ -1900,12 +1920,13 @@ static int send_server_hello(gnutls_session_t session, int again)
ext_parse_flag = GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO;
ret =
- _gnutls_gen_extensions(session, &extdata,
- ext_parse_flag,
- (session->internals.resumed ==
- RESUME_TRUE) ?
- GNUTLS_EXT_MANDATORY :
- GNUTLS_EXT_ANY);
+ _gnutls_extv_gen(session, &session->internals.hello_ext,
+ &extdata,
+ ext_parse_flag,
+ (session->internals.resumed == RESUME_TRUE) ?
+ GNUTLS_EXT_MANDATORY :
+ GNUTLS_EXT_ANY,
+ EXTV_SEND_SAVED_ONLY);
if (ret < 0) {
gnutls_assert();
goto fail;
@@ -2250,7 +2271,7 @@ int gnutls_handshake(gnutls_session_t session)
if (ret < 0)
return gnutls_assert_val(ret);
- session->internals.used_exts_size = 0;
+ session->internals.hello_ext.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 6167fb954f..68937cd998 100644
--- a/lib/state.c
+++ b/lib/state.c
@@ -397,8 +397,6 @@ void gnutls_deinit(gnutls_session_t session)
_gnutls_free_datum(&session->internals.resumption_data);
- gnutls_free(session->internals.rexts);
-
gnutls_free(session->internals.rsup);
gnutls_credentials_clear(session);
diff --git a/lib/x509.c b/lib/x509.c
index 29435647b0..64e5d4e743 100644
--- a/lib/x509.c
+++ b/lib/x509.c
@@ -48,6 +48,7 @@
#include "read-file.h"
#include "system-keys.h"
#include "urls.h"
+#include "extv.h"
#ifdef _WIN32
#include <wincrypt.h>
#endif
@@ -235,7 +236,7 @@ _gnutls_ocsp_verify_mandatory_stapling(gnutls_session_t session,
*
* To proceed, first check whether we have requested the certificate status
*/
- if (_gnutls_extension_list_check(session, GNUTLS_EXTENSION_STATUS_REQUEST) < 0) {
+ if (_gnutls_extv_check_saved(&session->internals.hello_ext, GNUTLS_EXTENSION_STATUS_REQUEST) < 0) {
return 0;
}