From 3607979dcd6329cf932feb71154850fc4108206e Mon Sep 17 00:00:00 2001 From: Simon Josefsson Date: Thu, 3 Jul 2008 17:28:44 +0200 Subject: Add APIs to register TLS extension handlers. --- includes/gnutls/gnutls.h.in | 23 +++++ lib/gnutls_extensions.c | 222 ++++++++++++++++++++++++++++---------------- lib/gnutls_extensions.h | 25 +---- lib/gnutls_global.c | 10 ++ lib/gnutls_handshake.c | 12 ++- lib/gnutls_int.h | 12 --- 6 files changed, 187 insertions(+), 117 deletions(-) diff --git a/includes/gnutls/gnutls.h.in b/includes/gnutls/gnutls.h.in index 1bd5d03876..13d507bdfe 100644 --- a/includes/gnutls/gnutls.h.in +++ b/includes/gnutls/gnutls.h.in @@ -480,6 +480,29 @@ extern "C" /* TLS Extensions */ + typedef int (*gnutls_ext_recv_func) (gnutls_session_t session, + const unsigned char *data, size_t len); + typedef int (*gnutls_ext_send_func) (gnutls_session_t session, + unsigned char *data, size_t len); + + /* This flag indicates for an extension whether + * it is useful to application level or TLS level only. + * This is (only) used to parse the application level extensions + * before the user_hello callback is called. + */ + typedef enum + { + GNUTLS_EXT_ANY, + GNUTLS_EXT_APPLICATION, + GNUTLS_EXT_TLS + } gnutls_ext_parse_type_t; + + int gnutls_ext_register (int type, + const char *name, + gnutls_ext_parse_type_t parse_type, + gnutls_ext_recv_func recv_func, + gnutls_ext_send_func send_func); + typedef enum { GNUTLS_NAME_DNS = 1 diff --git a/lib/gnutls_extensions.c b/lib/gnutls_extensions.c index fd43f7d4e0..3a9b650a17 100644 --- a/lib/gnutls_extensions.c +++ b/lib/gnutls_extensions.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008 Free Software Foundation * - * Author: Nikos Mavrogiannopoulos + * Author: Nikos Mavrogiannopoulos, Simon Josefsson * * This file is part of GNUTLS. * @@ -38,86 +38,42 @@ #include #include -/* Key Exchange Section */ -#define GNUTLS_EXTENSION_ENTRY(type, parse_type, ext_func_recv, ext_func_send) \ - { #type, type, parse_type, ext_func_recv, ext_func_send } - - -#define MAX_EXT_SIZE 10 -const int _gnutls_extensions_size = MAX_EXT_SIZE; - -gnutls_extension_entry _gnutls_extensions[MAX_EXT_SIZE] = { - GNUTLS_EXTENSION_ENTRY (GNUTLS_EXTENSION_MAX_RECORD_SIZE, - EXTENSION_TLS, - _gnutls_max_record_recv_params, - _gnutls_max_record_send_params), - GNUTLS_EXTENSION_ENTRY (GNUTLS_EXTENSION_CERT_TYPE, - EXTENSION_TLS, - _gnutls_cert_type_recv_params, - _gnutls_cert_type_send_params), - GNUTLS_EXTENSION_ENTRY (GNUTLS_EXTENSION_SERVER_NAME, - EXTENSION_APPLICATION, - _gnutls_server_name_recv_params, - _gnutls_server_name_send_params), -#ifdef ENABLE_OPRFI - GNUTLS_EXTENSION_ENTRY (GNUTLS_EXTENSION_OPAQUE_PRF_INPUT, - EXTENSION_TLS, - _gnutls_oprfi_recv_params, - _gnutls_oprfi_send_params), -#endif -#ifdef ENABLE_SRP - GNUTLS_EXTENSION_ENTRY (GNUTLS_EXTENSION_SRP, - EXTENSION_TLS, - _gnutls_srp_recv_params, - _gnutls_srp_send_params), -#endif - GNUTLS_EXTENSION_ENTRY (GNUTLS_EXTENSION_INNER_APPLICATION, - EXTENSION_TLS, - _gnutls_inner_application_recv_params, - _gnutls_inner_application_send_params), - {NULL, 0, 0, NULL, NULL} -}; - -#define GNUTLS_EXTENSION_LOOP2(b) \ - gnutls_extension_entry *p; \ - for(p = _gnutls_extensions; p->name != NULL; p++) { b ; } - -#define GNUTLS_EXTENSION_LOOP(a) \ - GNUTLS_EXTENSION_LOOP2( if(p->type == type) { a; break; } ) - - -/* EXTENSION functions */ - -ext_recv_func -_gnutls_ext_func_recv (uint16_t type, tls_ext_parse_type_t parse_type) +typedef struct { - ext_recv_func ret = NULL; - GNUTLS_EXTENSION_LOOP (if - (parse_type == EXTENSION_ANY - || p->parse_type == parse_type) ret = - p->gnutls_ext_func_recv); - return ret; + const char *name; + uint16_t type; + gnutls_ext_parse_type_t parse_type; + gnutls_ext_recv_func recv_func; + gnutls_ext_send_func send_func; +} gnutls_extension_entry; -} +size_t extfunc_size = 0; +static gnutls_extension_entry *extfunc = NULL; -ext_send_func -_gnutls_ext_func_send (uint16_t type) +static gnutls_ext_recv_func +_gnutls_ext_func_recv (uint16_t type, gnutls_ext_parse_type_t parse_type) { - ext_send_func ret = NULL; - GNUTLS_EXTENSION_LOOP (ret = p->gnutls_ext_func_send); - return ret; + size_t i; + for (i = 0; i < extfunc_size; 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; } const char * _gnutls_extension_get_name (uint16_t type) { - const char *ret = NULL; + size_t i; - /* avoid prefix */ - GNUTLS_EXTENSION_LOOP (ret = p->name + sizeof ("GNUTLS_EXTENSION_") - 1); + for (i = 0; i < extfunc_size; i++) + if (extfunc[i].type == type) + return extfunc[i].name; - return ret; + return NULL; } /* Checks if the extension we just received is one of the @@ -129,11 +85,13 @@ _gnutls_extension_list_check (gnutls_session_t session, uint16_t type) if (session->security_parameters.entity == GNUTLS_CLIENT) { int i; + for (i = 0; i < session->internals.extensions_sent_size; i++) { if (type == session->internals.extensions_sent[i]) return 0; /* ok found */ } + return GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION; } @@ -142,14 +100,14 @@ _gnutls_extension_list_check (gnutls_session_t session, uint16_t type) int _gnutls_parse_extensions (gnutls_session_t session, - tls_ext_parse_type_t parse_type, + gnutls_ext_parse_type_t parse_type, const opaque * data, int data_size) { int next, ret; int pos = 0; uint16_t type; const opaque *sdata; - ext_recv_func ext_recv; + gnutls_ext_recv_func ext_recv; uint16_t size; #ifdef DEBUG @@ -222,9 +180,8 @@ _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[session->internals. + extensions_sent_size] = type; session->internals.extensions_sent_size++; } else @@ -242,8 +199,7 @@ _gnutls_gen_extensions (gnutls_session_t session, opaque * data, uint16_t pos = 0; opaque *sdata; int sdata_size; - ext_send_func ext_send; - gnutls_extension_entry *p; + size_t i; if (data_size < 2) { @@ -262,12 +218,14 @@ _gnutls_gen_extensions (gnutls_session_t session, opaque * data, } pos += 2; - for (p = _gnutls_extensions; p->name != NULL; p++) + for (i = 0; i < extfunc_size; i++) { - ext_send = _gnutls_ext_func_send (p->type); - if (ext_send == NULL) + gnutls_extension_entry *p = &extfunc[i]; + + if (p->send_func == NULL) continue; - size = ext_send (session, sdata, sdata_size); + + size = p->send_func (session, sdata, sdata_size); if (size > 0) { if (data_size < pos + (size_t) size + 4) @@ -292,8 +250,8 @@ _gnutls_gen_extensions (gnutls_session_t session, opaque * data, */ _gnutls_extension_list_add (session, p->type); - _gnutls_debug_log ("EXT[%x]: Sending extension %s\n", session, - _gnutls_extension_get_name (p->type)); + _gnutls_debug_log ("EXT[%x]: Sending extension %s\n", + session, p->name); } else if (size < 0) { @@ -317,3 +275,103 @@ _gnutls_gen_extensions (gnutls_session_t session, opaque * data, return size; } + +int +_gnutls_ext_init (void) +{ + int ret; + + ret = gnutls_ext_register (GNUTLS_EXTENSION_MAX_RECORD_SIZE, + "MAX_RECORD_SIZE", + GNUTLS_EXT_TLS, + _gnutls_max_record_recv_params, + _gnutls_max_record_send_params); + if (ret != GNUTLS_E_SUCCESS) + return ret; + + ret = gnutls_ext_register (GNUTLS_EXTENSION_CERT_TYPE, + "CERT_TYPE", + GNUTLS_EXT_TLS, + _gnutls_cert_type_recv_params, + _gnutls_cert_type_send_params); + if (ret != GNUTLS_E_SUCCESS) + return ret; + + ret = gnutls_ext_register (GNUTLS_EXTENSION_SERVER_NAME, + "SERVER_NAME", + GNUTLS_EXT_APPLICATION, + _gnutls_server_name_recv_params, + _gnutls_server_name_send_params); + if (ret != GNUTLS_E_SUCCESS) + return ret; + +#ifdef ENABLE_OPRFI + ret = gnutls_ext_register (GNUTLS_EXTENSION_OPAQUE_PRF_INPUT, + "OPAQUE_PRF_INPUT", + GNUTLS_EXT_TLS, + _gnutls_oprfi_recv_params, + _gnutls_oprfi_send_params); + if (ret != GNUTLS_E_SUCCESS) + return ret; +#endif + +#ifdef ENABLE_SRP + ret = gnutls_ext_register (GNUTLS_EXTENSION_SRP, + "SRP", + GNUTLS_EXT_TLS, + _gnutls_srp_recv_params, + _gnutls_srp_send_params); + if (ret != GNUTLS_E_SUCCESS) + return ret; +#endif + + ret = gnutls_ext_register (GNUTLS_EXTENSION_INNER_APPLICATION, + "INNER_APPLICATION", + GNUTLS_EXT_TLS, + _gnutls_inner_application_recv_params, + _gnutls_inner_application_send_params); + if (ret != GNUTLS_E_SUCCESS) + return ret; + + return GNUTLS_E_SUCCESS; +} + +/** + * gnutls_ext_register - Register a handler for a TLS extension + * @type: the 16-bit integer referring to the extension type + * @name: human printable name of the extension used for debugging + * @parse_type: either #GNUTLS_EXT_TLS or %GNUTLS_EXT_APPLICATION. + * @recv_func: a function to receive extension data + * @send_func: a function to send extension data + * + * This function is used to register a new TLS extension handler. + * + * Returns: %GNUTLS_E_SUCCESS on success, or an error code. + **/ +int +gnutls_ext_register (int type, + const char *name, + gnutls_ext_parse_type_t parse_type, + gnutls_ext_recv_func recv_func, + gnutls_ext_send_func send_func) +{ + gnutls_extension_entry *p; + + p = gnutls_realloc (extfunc, sizeof (*extfunc) * (extfunc_size + 1)); + if (!p) + { + gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + extfunc = p; + + extfunc[extfunc_size].type = type; + extfunc[extfunc_size].name = name; + extfunc[extfunc_size].parse_type = parse_type; + extfunc[extfunc_size].recv_func = recv_func; + extfunc[extfunc_size].send_func = send_func; + + extfunc_size++; + + return GNUTLS_E_SUCCESS; +} diff --git a/lib/gnutls_extensions.h b/lib/gnutls_extensions.h index c305846c14..03e79881fc 100644 --- a/lib/gnutls_extensions.h +++ b/lib/gnutls_extensions.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008 Free Software Foundation * * Author: Nikos Mavrogiannopoulos * @@ -22,24 +22,9 @@ * */ -#include - -const char *_gnutls_extension_get_name (uint16_t type); -int _gnutls_parse_extensions (gnutls_session_t, tls_ext_parse_type_t, const opaque *, int); +int _gnutls_parse_extensions (gnutls_session_t session, + gnutls_ext_parse_type_t parse_type, + const opaque *data, int data_size); int _gnutls_gen_extensions (gnutls_session_t session, opaque * data, size_t data_size); - -typedef int (*ext_recv_func) (gnutls_session_t, const opaque *, size_t); /* recv data */ -typedef int (*ext_send_func) (gnutls_session_t, opaque *, size_t); /* send data */ - -ext_send_func _gnutls_ext_func_send (uint16_t type); -ext_recv_func _gnutls_ext_func_recv (uint16_t type, tls_ext_parse_type_t); - -typedef struct -{ - const char *name; - uint16_t type; - tls_ext_parse_type_t parse_type; - ext_recv_func gnutls_ext_func_recv; - ext_send_func gnutls_ext_func_send; -} gnutls_extension_entry; +int _gnutls_ext_init (void); diff --git a/lib/gnutls_global.c b/lib/gnutls_global.c index 17d5ab6a72..ad0dde6c62 100644 --- a/lib/gnutls_global.c +++ b/lib/gnutls_global.c @@ -29,6 +29,8 @@ #include #include +#include /* for _gnutls_ext_init */ + #ifdef HAVE_WINSOCK # include #endif @@ -303,6 +305,14 @@ gnutls_global_init (void) goto out; } + /* Initialize the default TLS extensions */ + result = _gnutls_ext_init (); + if (result < 0) + { + gnutls_assert (); + goto out; + } + out: return result; } diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c index 3375fe445f..29fa071dcb 100644 --- a/lib/gnutls_handshake.c +++ b/lib/gnutls_handshake.c @@ -440,7 +440,9 @@ _gnutls_read_client_hello (gnutls_session_t session, opaque * data, */ if (neg_version >= GNUTLS_TLS1) { - ret = _gnutls_parse_extensions (session, EXTENSION_APPLICATION, &data[pos], len); /* len is the rest of the parsed length */ + ret = _gnutls_parse_extensions (session, GNUTLS_EXT_APPLICATION, + &data[pos], len); + /* len is the rest of the parsed length */ if (ret < 0) { gnutls_assert (); @@ -457,7 +459,9 @@ _gnutls_read_client_hello (gnutls_session_t session, opaque * data, if (neg_version >= GNUTLS_TLS1) { - ret = _gnutls_parse_extensions (session, EXTENSION_TLS, &data[pos], len); /* len is the rest of the parsed length */ + ret = _gnutls_parse_extensions (session, GNUTLS_EXT_TLS, + &data[pos], len); + /* len is the rest of the parsed length */ if (ret < 0) { gnutls_assert (); @@ -1559,7 +1563,9 @@ _gnutls_read_server_hello (gnutls_session_t session, */ if (version >= GNUTLS_TLS1) { - ret = _gnutls_parse_extensions (session, EXTENSION_ANY, &data[pos], len); /* len is the rest of the parsed length */ + ret = _gnutls_parse_extensions (session, GNUTLS_EXT_ANY, + &data[pos], len); + /* len is the rest of the parsed length */ if (ret < 0) { gnutls_assert (); diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index eb392e77de..87d1debe6a 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -282,18 +282,6 @@ typedef struct uint16_t oprfi_server_len; } tls_ext_st; -/* This flag indicates for an extension whether - * it is useful to application level or TLS level only. - * This is used to parse the application level extensions - * before the user_hello callback is called. - */ -typedef enum tls_ext_parse_type_t -{ - EXTENSION_ANY, - EXTENSION_APPLICATION, - EXTENSION_TLS -} tls_ext_parse_type_t; - /* auth_info_t structures now MAY contain malloced * elements. */ -- cgit v1.2.1