summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2001-11-06 12:57:56 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2001-11-06 12:57:56 +0000
commit4f29f5da703f323769b7d6514c3e01d5fca0cc7e (patch)
tree6d83353474ffbb65a41e1714d913e6ac2405dc47 /lib
parent16aaced014f2c2ee19cf0d5d2c8a7168fe131070 (diff)
downloadgnutls-4f29f5da703f323769b7d6514c3e01d5fca0cc7e.tar.gz
added max_record_size extension
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am4
-rw-r--r--lib/ext_dnsname.c1
-rw-r--r--lib/ext_max_record.c149
-rw-r--r--lib/ext_max_record.h7
-rw-r--r--lib/ext_srp.c2
-rw-r--r--lib/gnutls.h.in3
-rw-r--r--lib/gnutls_constate.c1
-rw-r--r--lib/gnutls_errors.c1
-rw-r--r--lib/gnutls_errors_int.h1
-rw-r--r--lib/gnutls_extensions.c2
-rw-r--r--lib/gnutls_handshake.c43
-rw-r--r--lib/gnutls_int.h12
-rw-r--r--lib/gnutls_record.c52
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;
+}