an alert to the peer.
- Made receive buffer dynamic. Normaly if no large chunks are receive
it occupies less space.
+- Added max_record_size extension
+- Bugfixes session handling
Version 0.2.10 (5/11/2001)
- Corrected bugs and improved non blocking IO
GNUTLS_MAJOR_VERSION=0
GNUTLS_MINOR_VERSION=2
-GNUTLS_MICRO_VERSION=10
+GNUTLS_MICRO_VERSION=11
GNUTLS_VERSION=$GNUTLS_MAJOR_VERSION.$GNUTLS_MINOR_VERSION.$GNUTLS_MICRO_VERSION
AC_DEFINE_UNQUOTED(GNUTLS_VERSION, "$GNUTLS_VERSION")
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
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)
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;
--- /dev/null
+/*
+ * 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;
+ }
+
+}
--- /dev/null
+/* 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);
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;
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);
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) {
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}
};
#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
#include "gnutls_errors.h"
#include "ext_srp.h"
#include "ext_dnsname.h"
+#include "ext_max_record.h"
#include "gnutls_num.h"
/* Key Exchange Section */
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}
};
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.
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;
}
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;
}
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; \
}
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) {
gnutls_assert();
return GNUTLS_E_UNEXPECTED_PACKET;
}
-#endif
}
/* This function will remove algorithms that are not supported by
#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
#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 */
/* 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;
uint8 session_id_size;
time_t timestamp;
TLSExtensions extensions;
+ uint16 max_record_size;
} SecurityParameters;
/* This structure holds the generated keys
#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;
* 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.
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;
+}
#include "../lib/gnutls.h"
#include <sys/time.h>
+#include <dmalloc.h>
+
#ifndef SHUT_WR
# define SHUT_WR 1
#endif