diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2001-11-06 12:57:56 +0000 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2001-11-06 12:57:56 +0000 |
commit | 4f29f5da703f323769b7d6514c3e01d5fca0cc7e (patch) | |
tree | 6d83353474ffbb65a41e1714d913e6ac2405dc47 /lib | |
parent | 16aaced014f2c2ee19cf0d5d2c8a7168fe131070 (diff) | |
download | gnutls-4f29f5da703f323769b7d6514c3e01d5fca0cc7e.tar.gz |
added max_record_size extension
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile.am | 4 | ||||
-rw-r--r-- | lib/ext_dnsname.c | 1 | ||||
-rw-r--r-- | lib/ext_max_record.c | 149 | ||||
-rw-r--r-- | lib/ext_max_record.h | 7 | ||||
-rw-r--r-- | lib/ext_srp.c | 2 | ||||
-rw-r--r-- | lib/gnutls.h.in | 3 | ||||
-rw-r--r-- | lib/gnutls_constate.c | 1 | ||||
-rw-r--r-- | lib/gnutls_errors.c | 1 | ||||
-rw-r--r-- | lib/gnutls_errors_int.h | 1 | ||||
-rw-r--r-- | lib/gnutls_extensions.c | 2 | ||||
-rw-r--r-- | lib/gnutls_handshake.c | 43 | ||||
-rw-r--r-- | lib/gnutls_int.h | 12 | ||||
-rw-r--r-- | lib/gnutls_record.c | 52 |
13 files changed, 250 insertions, 28 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index 4271b123f3..5bfbd22eaf 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -17,7 +17,7 @@ EXTRA_DIST = debug.h gnutls_compress.h defines.h pkcs1.asn pkix.asn \ ext_dnsname.h gnutls_pk.h gnutls_record.h gnutls_cert.h \ gnutls_privkey.h gnutls_constate.h gnutls_global.h x509_verify.h \ gnutls_sig.h gnutls_mem.h x509_extensions.h gnutls_ui.h \ - gnutls-api.tex io_debug.h + gnutls-api.tex io_debug.h ext_max_record.h lib_LTLIBRARIES = libgnutls.la @@ -35,7 +35,7 @@ COBJECTS = gnutls_record.c gnutls_compress.c debug.c \ gnutls_global.c gnutls_privkey.c gnutls_constate.c gnutls_anon_cred.c \ x509_sig_check.c pkix_asn1_tab.c pkcs1_asn1_tab.c gnutls_mem.c \ x509_extensions.c auth_x509.c gnutls_ui.c gnutls_sig.c auth_dhe_rsa.c \ - gnutls_dh_primes.c + gnutls_dh_primes.c ext_max_record.c libgnutls_la_SOURCES = $(COBJECTS) diff --git a/lib/ext_dnsname.c b/lib/ext_dnsname.c index 3760fe29a4..f20f16779e 100644 --- a/lib/ext_dnsname.c +++ b/lib/ext_dnsname.c @@ -74,6 +74,7 @@ int _gnutls_name_ind_send_params( GNUTLS_STATE state, opaque** data) { case GNUTLS_DNSNAME: if ( (len = strlen(state->security_parameters.extensions.name.dnsname)) > 0) { /* send dnsname */ (*data) = gnutls_malloc(len+3); /* hold the size and the type also */ + if (*data==NULL) return GNUTLS_E_MEMORY_ERROR; WRITEuint16( len+1, *data); (*data)[2] = 0; diff --git a/lib/ext_max_record.c b/lib/ext_max_record.c new file mode 100644 index 0000000000..09f269df5d --- /dev/null +++ b/lib/ext_max_record.c @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2001 Nikos Mavroyanopoulos + * + * This file is part of GNUTLS. + * + * GNUTLS is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GNUTLS 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "gnutls_int.h" +#include "gnutls_errors.h" +#include "gnutls_num.h" +#include "ext_max_record.h" + +/* + * In case of a server: if a MAX_RECORD_SIZE extension type is received then it stores + * into the state the new value. The server may use gnutls_get_max_record_size(), + * in order to access it. + * + * In case of a client: If a different max record size (than the default) has + * been specified then it sends the extension. + * + */ + +int _gnutls_max_record_recv_params( GNUTLS_STATE state, const opaque* data, int data_size) { + size_t new_size; + + if (state->security_parameters.entity == GNUTLS_SERVER) { + if (data_size > 0) { + + if ( data_size != 1) { + gnutls_assert(); + return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } + + new_size = _gnutls_mre_num2record(data[0]); + + if (new_size < 0) { + gnutls_assert(); + return new_size; + } + + state->security_parameters.max_record_size = new_size; + } + } else { /* CLIENT SIDE - we must check if the sent record size is the right one + */ + if (data_size > 0) { + + if ( data_size != 1) { + gnutls_assert(); + return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } + + new_size = _gnutls_mre_num2record(data[0]); + +fprintf(stderr, "RECEIVING IT %d\n", new_size); + + if (new_size < 0 || new_size != state->security_parameters.max_record_size) { + gnutls_assert(); + return GNUTLS_E_ILLEGAL_PARAMETER; + } + + } + + + } + + return 0; +} + +/* returns data_size or a negative number on failure + * data is allocated localy + */ +int _gnutls_max_record_send_params( GNUTLS_STATE state, opaque** data) { + uint16 len; + /* this function sends the client extension data (dnsname) */ + if (state->security_parameters.entity == GNUTLS_CLIENT) { + + if (state->security_parameters.max_record_size != DEFAULT_MAX_RECORD_SIZE) { + len = 1; + (*data) = gnutls_malloc(len); /* hold the size and the type also */ + if (*data==NULL) return GNUTLS_E_MEMORY_ERROR; + + (*data)[0] = _gnutls_mre_record2num( state->security_parameters.max_record_size); + return len; + } + + } else { /* server side */ + + if (state->security_parameters.max_record_size != DEFAULT_MAX_RECORD_SIZE) { + len = 1; + (*data) = gnutls_malloc(len+2); /* hold the size and the type also */ + if (*data==NULL) return GNUTLS_E_MEMORY_ERROR; + + (*data)[0] = _gnutls_mre_record2num( state->security_parameters.max_record_size); + return len; + } + + + } + + *data = NULL; + return 0; +} + +/* Maps record size to numbers according to the + * extensions draft. + */ +int _gnutls_mre_num2record( int num) { + switch( num) { + case 1: + return 512; + case 2: + return 1024; + case 3: + return 2048; + case 4: + return 4096; + default: + return GNUTLS_E_ILLEGAL_PARAMETER; + } +} + +int _gnutls_mre_record2num( int record_size) { + switch(record_size) { + case 512: + return 1; + case 1024: + return 2; + case 2048: + return 3; + case 4096: + return 4; + default: + return GNUTLS_E_ILLEGAL_PARAMETER; + } + +} diff --git a/lib/ext_max_record.h b/lib/ext_max_record.h new file mode 100644 index 0000000000..47f72485af --- /dev/null +++ b/lib/ext_max_record.h @@ -0,0 +1,7 @@ +/* Maps record size to numbers according to the + * extensions draft. + */ +int _gnutls_mre_num2record( int num); +int _gnutls_mre_record2num( int record_size); +int _gnutls_max_record_recv_params( GNUTLS_STATE state, const opaque* data, int data_size); +int _gnutls_max_record_send_params( GNUTLS_STATE state, opaque** data); diff --git a/lib/ext_srp.c b/lib/ext_srp.c index eb373415f1..8fe9d6e771 100644 --- a/lib/ext_srp.c +++ b/lib/ext_srp.c @@ -74,6 +74,8 @@ int _gnutls_srp_send_params( GNUTLS_STATE state, opaque** data) { if (cred->username!=NULL) { /* send username */ len = strlen(cred->username); (*data) = gnutls_malloc(len+1); /* hold the size also */ + if (*data==NULL) return GNUTLS_E_MEMORY_ERROR; + (*data)[0] = len; memcpy( &(*data)[1], cred->username, len); return len + 1; diff --git a/lib/gnutls.h.in b/lib/gnutls.h.in index 4f07442561..4516f0a22b 100644 --- a/lib/gnutls.h.in +++ b/lib/gnutls.h.in @@ -237,5 +237,6 @@ typedef void (*LOG_FUNC)( const char*); void gnutls_set_push_func( GNUTLS_STATE, PUSH_FUNC push_func); void gnutls_set_pull_func( GNUTLS_STATE, PULL_FUNC pull_func); - +size_t gnutls_get_max_record_size( GNUTLS_STATE state); +size_t gnutls_set_max_record_size( GNUTLS_STATE state, size_t size); diff --git a/lib/gnutls_constate.c b/lib/gnutls_constate.c index a2784e759b..ef56c13132 100644 --- a/lib/gnutls_constate.c +++ b/lib/gnutls_constate.c @@ -151,6 +151,7 @@ int _gnutls_set_write_keys(GNUTLS_STATE state) memcpy( dst->session_id, src->session_id, TLS_MAX_SESSION_ID_SIZE); \ dst->session_id_size = src->session_id_size; \ dst->timestamp = src->timestamp; \ + dst->max_record_size = src->max_record_size; \ memcpy( &dst->extensions, &src->extensions, sizeof(TLSExtensions)); static void _gnutls_cpy_read_security_parameters( SecurityParameters * dst, SecurityParameters* src) { diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c index ef0710825f..f8c80e266b 100644 --- a/lib/gnutls_errors.c +++ b/lib/gnutls_errors.c @@ -89,6 +89,7 @@ static gnutls_error_entry error_algorithms[] = { GNUTLS_ERROR_ENTRY( GNUTLS_E_DB_ERROR, 1), GNUTLS_ERROR_ENTRY( GNUTLS_E_INVALID_PARAMETERS, 1), GNUTLS_ERROR_ENTRY( GNUTLS_E_INVALID_REQUEST, 1), + GNUTLS_ERROR_ENTRY( GNUTLS_E_ILLEGAL_PARAMETER, 1), {0} }; diff --git a/lib/gnutls_errors_int.h b/lib/gnutls_errors_int.h index 77cebf04a5..4426100b5c 100644 --- a/lib/gnutls_errors_int.h +++ b/lib/gnutls_errors_int.h @@ -55,5 +55,6 @@ #define GNUTLS_E_INTERRUPTED -52 #define GNUTLS_E_PUSH_ERROR -53 #define GNUTLS_E_PULL_ERROR -54 +#define GNUTLS_E_ILLEGAL_PARAMETER -55 #define GNUTLS_E_UNIMPLEMENTED_FEATURE -250 diff --git a/lib/gnutls_extensions.c b/lib/gnutls_extensions.c index 636fbb8f0c..9f2f6f81f3 100644 --- a/lib/gnutls_extensions.c +++ b/lib/gnutls_extensions.c @@ -23,6 +23,7 @@ #include "gnutls_errors.h" #include "ext_srp.h" #include "ext_dnsname.h" +#include "ext_max_record.h" #include "gnutls_num.h" /* Key Exchange Section */ @@ -40,6 +41,7 @@ typedef struct { static gnutls_extension_entry extensions[] = { GNUTLS_EXTENSION_ENTRY( GNUTLS_EXTENSION_SRP, _gnutls_srp_recv_params, _gnutls_srp_send_params), GNUTLS_EXTENSION_ENTRY( GNUTLS_EXTENSION_DNSNAME, _gnutls_name_ind_recv_params, _gnutls_name_ind_send_params), + GNUTLS_EXTENSION_ENTRY( GNUTLS_EXTENSION_MAX_RECORD_SIZE, _gnutls_max_record_recv_params, _gnutls_max_record_send_params), {0} }; diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c index 2b367bc67f..9dbc9c6c5e 100644 --- a/lib/gnutls_handshake.c +++ b/lib/gnutls_handshake.c @@ -1270,6 +1270,24 @@ int ret; return ret; } +/* Sends the appropriate alert, depending + * on the error message. + */ +static int _gnutls_handshake_send_appropriate_alert( SOCKET cd, GNUTLS_STATE state, int err) { +int ret; + switch (err) { /* send appropriate alert */ + case GNUTLS_E_ILLEGAL_PARAMETER: + ret = gnutls_send_alert(cd, state, GNUTLS_FATAL, GNUTLS_ILLEGAL_PARAMETER); + break; + default: + ret = gnutls_send_alert(cd, state, GNUTLS_FATAL, GNUTLS_HANDSHAKE_FAILURE); + break; + } + + return ret; +} + + /* RECEIVE A HELLO MESSAGE. This should be called from gnutls_recv_handshake_int only if a * hello message is expected. It uses the security_parameters.current_cipher_suite * and gnutls_internals.compression_method. @@ -1282,7 +1300,7 @@ int _gnutls_recv_hello(SOCKET cd, GNUTLS_STATE state, char *data, if (state->security_parameters.entity == GNUTLS_CLIENT) { ret = _gnutls_read_server_hello(state, data, datalen); if (ret < 0) { - gnutls_send_alert(cd, state, GNUTLS_FATAL, GNUTLS_HANDSHAKE_FAILURE); /* send handshake failure */ + _gnutls_handshake_send_appropriate_alert( cd, state, ret); gnutls_assert(); return ret; } @@ -1290,7 +1308,7 @@ int _gnutls_recv_hello(SOCKET cd, GNUTLS_STATE state, char *data, ret = _gnutls_read_client_hello(state, data, datalen); if (ret < 0) { - gnutls_send_alert(cd, state, GNUTLS_FATAL, GNUTLS_HANDSHAKE_FAILURE); /* send handshake failure */ + _gnutls_handshake_send_appropriate_alert( cd, state, ret); gnutls_assert(); return ret; } @@ -1405,6 +1423,7 @@ int gnutls_handshake(SOCKET cd, GNUTLS_STATE state) if (gnutls_is_fatal_error(ret)==0) return ret; \ gnutls_assert(); \ ERR( str, ret); \ + _gnutls_handshake_send_appropriate_alert( cd, state, ret); \ gnutls_clear_handshake_buffer(state); \ return ret; \ } @@ -1786,28 +1805,9 @@ int _gnutls_generate_session_id(char *session_id, uint8 * len) return 0; } -#define RENEGOTIATE int _gnutls_recv_hello_request(SOCKET cd, GNUTLS_STATE state, void *data, uint32 data_size) { -#ifndef RENEGOTIATE - int ret; - - /* only client should receive that */ - if (state->security_parameters.entity == GNUTLS_SERVER) - return GNUTLS_E_UNEXPECTED_PACKET; - - /* just return an alert that we don't like that */ - ret = - gnutls_send_alert(cd, state, GNUTLS_WARNING, - GNUTLS_NO_RENEGOTIATION); - if (ret < 0) { - gnutls_assert(); - return ret; - } - return 0; - -#else /* this does seem to work - now */ uint8 type; if (state->security_parameters.entity == GNUTLS_SERVER) { @@ -1825,7 +1825,6 @@ int _gnutls_recv_hello_request(SOCKET cd, GNUTLS_STATE state, void *data, gnutls_assert(); return GNUTLS_E_UNEXPECTED_PACKET; } -#endif } /* This function will remove algorithms that are not supported by diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 8e47874fed..ac51a5dec6 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -63,6 +63,12 @@ #define MAX_DNSNAME_SIZE 256 +/* The initial size of the receive + * buffer size. This will grow if larger + * packets are received. + */ +#define INITIAL_RECV_BUFFER_SIZE 256 + /* the default for TCP */ #define DEFAULT_LOWAT 1 @@ -70,7 +76,8 @@ #define DEFAULT_EXPIRE_TIME 3600 /* the maximum size of encrypted packets */ -#define MAX_ENC_LEN 16384 +#define DEFAULT_MAX_RECORD_SIZE 16384 +#define MAX_ENC_LEN state->security_parameters.max_record_size #define RECORD_HEADER_SIZE 5 #define MAX_RECV_SIZE 18432+RECORD_HEADER_SIZE /* 2^14+2048+RECORD_HEADER_SIZE */ @@ -133,7 +140,7 @@ typedef struct { /* STATE */ typedef enum ConnectionEnd { GNUTLS_SERVER=1, GNUTLS_CLIENT } ConnectionEnd; typedef enum BulkCipherAlgorithm { GNUTLS_NULL_CIPHER=1, GNUTLS_ARCFOUR, GNUTLS_3DES_CBC, GNUTLS_RIJNDAEL_CBC, GNUTLS_TWOFISH_CBC, GNUTLS_RIJNDAEL256_CBC } BulkCipherAlgorithm; -typedef enum Extensions { GNUTLS_EXTENSION_DNSNAME=0, GNUTLS_EXTENSION_SRP=6 } Extensions; +typedef enum Extensions { GNUTLS_EXTENSION_DNSNAME=0, GNUTLS_EXTENSION_MAX_RECORD_SIZE=1, GNUTLS_EXTENSION_SRP=6 } Extensions; typedef enum KXAlgorithm { GNUTLS_KX_RSA=1, GNUTLS_KX_DHE_DSS, GNUTLS_KX_DHE_RSA, GNUTLS_KX_DH_DSS, GNUTLS_KX_DH_RSA, GNUTLS_KX_DH_ANON, GNUTLS_KX_SRP } KXAlgorithm; typedef enum CredType { GNUTLS_X509PKI=1, GNUTLS_ANON, GNUTLS_SRP } CredType; typedef enum CipherType { CIPHER_STREAM, CIPHER_BLOCK } CipherType; @@ -280,6 +287,7 @@ typedef struct { uint8 session_id_size; time_t timestamp; TLSExtensions extensions; + uint16 max_record_size; } SecurityParameters; /* This structure holds the generated keys diff --git a/lib/gnutls_record.c b/lib/gnutls_record.c index 31e42f707b..a95eb8f21c 100644 --- a/lib/gnutls_record.c +++ b/lib/gnutls_record.c @@ -34,6 +34,7 @@ #include "gnutls_num.h" #include "gnutls_record.h" #include "gnutls_datum.h" +#include "ext_max_record.h" GNUTLS_Version gnutls_get_current_version(GNUTLS_STATE state) { GNUTLS_Version ver; @@ -114,7 +115,11 @@ int gnutls_init(GNUTLS_STATE * state, ConnectionEnd con_end) * This is allocated in order to avoid small messages, makeing * the receive procedure slow. */ - (*state)->gnutls_internals.recv_buffer.data = gnutls_malloc(256); + (*state)->gnutls_internals.recv_buffer.data = gnutls_malloc(INITIAL_RECV_BUFFER_SIZE); + + /* set the default maximum record size for TLS + */ + (*state)->security_parameters.max_record_size = DEFAULT_MAX_RECORD_SIZE; /* everything else not initialized here is initialized * as NULL or 0. This is why calloc is used. @@ -1090,3 +1095,48 @@ ssize_t gnutls_write(SOCKET cd, GNUTLS_STATE state, const void *data, size_t siz ssize_t gnutls_read(SOCKET cd, GNUTLS_STATE state, void *data, size_t sizeofdata) { return gnutls_recv_int( cd, state, GNUTLS_APPLICATION_DATA, -1, data, sizeofdata); } + +/** + * gnutls_get_max_record_size - returns the maximum record size + * @state: is a &GNUTLS_STATE structure. + * + * This function returns the maximum record size in this connection. + * The maximum record size is negotiated by the client after the + * first handshake message. + * + **/ +size_t gnutls_get_max_record_size( GNUTLS_STATE state) { + return state->security_parameters.max_record_size; +} + + +/** + * gnutls_set_max_record_size - sets the maximum record size + * @state: is a &GNUTLS_STATE structure. + * @size: is the new size + * + * This function sets the maximum record size in this connection. + * This property can only be set to clients. The server may + * choose not to accept the requested size. + * + * Acceptable values are 2^9, 2^10, 2^11 and 2^12. + * Returns the new record size. + * + **/ +size_t gnutls_set_max_record_size( GNUTLS_STATE state, size_t size) { +size_t new_size; + + if (state->security_parameters.entity==GNUTLS_SERVER) + return GNUTLS_E_INVALID_REQUEST; + + new_size = _gnutls_mre_record2num( size); + + if (new_size < 0) { + gnutls_assert(); + return new_size; + } + + state->security_parameters.max_record_size = size; + + return state->security_parameters.max_record_size; +} |