From dc1122e7b6c6437a0e20d93679e0f8af5b3869c7 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Tue, 24 Jul 2001 18:26:51 +0000 Subject: corrected bug in b64 decoding. Added support for multiple TLS protocol versions. --- NEWS | 1 + lib/cert_b64.c | 52 ++++++++++++++++++------------------ lib/gnutls.h.in | 12 ++++----- lib/gnutls_algorithms.c | 55 +++++++++++++++++++++++++++++++++++--- lib/gnutls_algorithms.h | 4 +++ lib/gnutls_buffers.c | 8 +++--- lib/gnutls_buffers.h | 4 +-- lib/gnutls_cert.c | 18 ++++++++++--- lib/gnutls_constate.c | 4 +-- lib/gnutls_handshake.c | 45 ++++++++++++++++++++----------- lib/gnutls_int.h | 18 ++++++++----- lib/gnutls_priority.c | 47 +++++++++++++++++++++++++++++++++ lib/gnutls_priority.h | 9 ++++--- lib/gnutls_record.c | 70 +++++++++++++++++++++++++++++++------------------ lib/gnutls_v2_compat.c | 15 ++++++++--- src/serv.c | 3 ++- 16 files changed, 265 insertions(+), 100 deletions(-) diff --git a/NEWS b/NEWS index e85639673e..8caee5fb43 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ Version 0.1.5 - Reentracy fixes in ASN.1 Parsing. - Optimizations in hash/hmac functions - (Error) message handling has changed +- Better Protocol Version handling Version 0.1.4 (22/06/2001) - Corrected (srp) base64 encoding. diff --git a/lib/cert_b64.c b/lib/cert_b64.c index 9613e455b4..d953c4dd2c 100644 --- a/lib/cert_b64.c +++ b/lib/cert_b64.c @@ -296,49 +296,51 @@ inline static int cpydata(uint8 * data, int data_size, uint8 ** result) /* decodes data and puts the result into result (localy alocated) * The result_size is the return value - * FIXME: This function is a mess */ #define ENDSTR "-----\n" int _gnutls_fbase64_decode( uint8 * data, int data_size, uint8 ** result) { - int i, ret; - char top[80]; - char bottom[80]; + int ret; + char top[] = "-----BEGIN "; + char bottom[] = "\n-----END "; uint8 *rdata; int rdata_size; uint8 *kdata; int kdata_size; - strcpy(top, "-----BEGIN "); - - strcpy(bottom, "\n-----END "); - - i = 0; - do { - rdata = &data[i]; - data_size --; - i++; - } while (data_size > 0 && strncmp(rdata, top, strlen(top)) != 0); + rdata = strstr( data, top); + if (rdata==NULL) { + gnutls_assert(); + return -1; + } + data_size -= (int)rdata-(int)data; if (data_size < 4 + strlen(bottom)) { gnutls_assert(); return -1; } - - do { - data_size--; - rdata++; - } while( ( strncmp( rdata, ENDSTR, strlen(ENDSTR)) != 0) && data_size > 0) ; + kdata = strstr( rdata, ENDSTR); + if (kdata==NULL) { + gnutls_assert(); + return -1; + } data_size -= strlen(ENDSTR); - rdata += strlen(ENDSTR); + data_size -= (int)kdata-(int)rdata; + + rdata = kdata + strlen(ENDSTR); + + /* position is now after the ---BEGIN--- headers */ - rdata_size = 0; - do { - rdata_size++; - } while (rdata_size < data_size - && strncmp(&rdata[rdata_size], bottom, strlen(bottom)) != 0); + kdata = strstr( rdata, bottom); + if (kdata==NULL) { + gnutls_assert(); + return -1; + } + /* position of kdata is before the ----END--- footer + */ + rdata_size = (int)kdata-(int)rdata; if (rdata_size < 4) { gnutls_assert(); diff --git a/lib/gnutls.h.in b/lib/gnutls.h.in index 3ca2c23bdb..30c0e45623 100644 --- a/lib/gnutls.h.in +++ b/lib/gnutls.h.in @@ -38,7 +38,7 @@ typedef enum AlertDescription { GNUTLS_CLOSE_NOTIFY, GNUTLS_UNEXPECTED_MESSAGE=1 GNUTLS_NO_RENEGOTIATION=100 } AlertDescription; -typedef enum GNUTLS_Version { GNUTLS_TLS1, GNUTLS_SSL3 } GNUTLS_Version; +typedef enum GNUTLS_Version { GNUTLS_SSL3=1, GNUTLS_TLS1 } GNUTLS_Version; #define SOCKET int #define LIST ... @@ -97,14 +97,14 @@ ssize_t gnutls_write(SOCKET cd, GNUTLS_STATE state, void *data, size_t sizeofdat ssize_t gnutls_read(SOCKET cd, GNUTLS_STATE state, void *data, size_t sizeofdata); /* functions to set priority of cipher suites */ -void gnutls_set_cipher_priority( GNUTLS_STATE state, LIST); -void gnutls_set_mac_priority( GNUTLS_STATE state, LIST); -void gnutls_set_compression_priority( GNUTLS_STATE state, LIST); -void gnutls_set_kx_priority( GNUTLS_STATE state, LIST); +int gnutls_set_cipher_priority( GNUTLS_STATE state, LIST); +int gnutls_set_mac_priority( GNUTLS_STATE state, LIST); +int gnutls_set_compression_priority( GNUTLS_STATE state, LIST); +int gnutls_set_kx_priority( GNUTLS_STATE state, LIST); +int gnutls_set_protocol_priority( GNUTLS_STATE state, LIST); /* set our version - 0 for TLS 1.0 and 1 for SSL3 */ -void gnutls_set_current_version(GNUTLS_STATE state, GNUTLS_Version version); GNUTLS_Version gnutls_get_current_version(GNUTLS_STATE state); const char *gnutls_version_get_name(GNUTLS_Version version); diff --git a/lib/gnutls_algorithms.c b/lib/gnutls_algorithms.c index 4aacabc7e8..f15504a3e3 100644 --- a/lib/gnutls_algorithms.c +++ b/lib/gnutls_algorithms.c @@ -34,6 +34,7 @@ #define MAX_KX 256 #define MAX_CIPHERSUITE 256 #define MAX_COMPRESSION 256 +#define MAX_VERSION 256 /* Cred type mappings to KX algorithms */ @@ -74,6 +75,7 @@ typedef struct { static const gnutls_version_entry sup_versions[] = { {"SSL 3.0", GNUTLS_SSL3, 3, 0, 1}, {"TLS 1.0", GNUTLS_TLS1, 3, 1, 1}, + {"UNKNOWN", GNUTLS_VERSION_UNKNOWN, 0, 0, 1}, {0} }; @@ -700,6 +702,48 @@ int _gnutls_kx_is_ok(KXAlgorithm algorithm) return ret; } +/* Version */ +int _gnutls_version_priority(GNUTLS_STATE state, + GNUTLS_Version version) +{ /* actually returns the priority */ + int i; + + if (state->gnutls_internals.ProtocolPriority.algorithm_priority==NULL) { + gnutls_assert(); + return -1; + } + + for (i = 0; + i < + state->gnutls_internals.ProtocolPriority.algorithms; + i++) { + if (state->gnutls_internals. + ProtocolPriority.algorithm_priority[i] == + version) + return i; + } + return -1; +} + +GNUTLS_Version _gnutls_version_lowest(GNUTLS_STATE state) +{ /* returns the lowest version supported */ + if (state->gnutls_internals.ProtocolPriority.algorithm_priority==NULL) { + return GNUTLS_VERSION_UNKNOWN; + } else + return state->gnutls_internals.ProtocolPriority. + algorithm_priority[state->gnutls_internals.ProtocolPriority.algorithms-1]; +} + +GNUTLS_Version _gnutls_version_max(GNUTLS_STATE state) +{ /* returns the maximum version supported */ + if (state->gnutls_internals.ProtocolPriority.algorithm_priority==NULL) { + return GNUTLS_VERSION_UNKNOWN; + } else + return state->gnutls_internals.ProtocolPriority. + algorithm_priority[0]; +} + + /** * gnutls_version_get_name - Returns a string with the name of the specified SSL/TLS version * @version: is a (gnutls) version number @@ -754,10 +798,15 @@ int _gnutls_version_is_supported(GNUTLS_STATE state, const GNUTLS_Version version) { - size_t ret = 0; - /* FIXME: make it to read it from the state */ +int ret; + GNUTLS_VERSION_ALG_LOOP(ret = p->supported); - return ret; + if (ret == 0) return 0; + + if (_gnutls_version_priority( state, version) < 0) + return 0; /* disabled by the user */ + else + return 1; } /* Type to KX mappings */ diff --git a/lib/gnutls_algorithms.h b/lib/gnutls_algorithms.h index 1b869606f7..e7c643b247 100644 --- a/lib/gnutls_algorithms.h +++ b/lib/gnutls_algorithms.h @@ -21,6 +21,10 @@ #include "gnutls_auth.h" /* functions for version */ + +GNUTLS_Version _gnutls_version_lowest( GNUTLS_STATE state); +GNUTLS_Version _gnutls_version_max( GNUTLS_STATE state); +int _gnutls_version_priority(GNUTLS_STATE state, GNUTLS_Version version); int _gnutls_version_is_supported(GNUTLS_STATE state, const GNUTLS_Version version); int _gnutls_version_get_major( GNUTLS_Version ver); int _gnutls_version_get_minor( GNUTLS_Version ver); diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c index f31fc48ea2..f368e88a0c 100644 --- a/lib/gnutls_buffers.c +++ b/lib/gnutls_buffers.c @@ -213,7 +213,7 @@ ssize_t _gnutls_Write(int fd, const void *iptr, size_t n, int flags) return n; } -ssize_t _gnutls_Send_int(int fd, GNUTLS_STATE state, ContentType type, void *iptr, size_t n) +ssize_t _gnutls_Send_int(int fd, GNUTLS_STATE state, ContentType type, HandshakeType htype, void *iptr, size_t n) { size_t left; ssize_t i = 0; @@ -221,7 +221,7 @@ ssize_t _gnutls_Send_int(int fd, GNUTLS_STATE state, ContentType type, void *ipt left = n; while (left > 0) { - i = gnutls_send_int(fd, state, type, &ptr[i], left, 0); + i = gnutls_send_int(fd, state, type, htype, &ptr[i], left, 0); if (i <= 0) { return i; } @@ -232,7 +232,7 @@ ssize_t _gnutls_Send_int(int fd, GNUTLS_STATE state, ContentType type, void *ipt } -ssize_t _gnutls_Recv_int(int fd, GNUTLS_STATE state, ContentType type, void *iptr, size_t sizeOfPtr) +ssize_t _gnutls_Recv_int(int fd, GNUTLS_STATE state, ContentType type, HandshakeType htype, void *iptr, size_t sizeOfPtr) { size_t left; ssize_t i=0; @@ -240,7 +240,7 @@ ssize_t _gnutls_Recv_int(int fd, GNUTLS_STATE state, ContentType type, void *ipt left = sizeOfPtr; while (left > 0) { - i = gnutls_recv_int(fd, state, type, &ptr[i], left, 0); + i = gnutls_recv_int(fd, state, type, htype, &ptr[i], left, 0); if (i < 0) { return i; } else { diff --git a/lib/gnutls_buffers.h b/lib/gnutls_buffers.h index 6b23f60397..7ecbfe88f9 100644 --- a/lib/gnutls_buffers.h +++ b/lib/gnutls_buffers.h @@ -31,5 +31,5 @@ int gnutls_readHashDataFromBuffer( GNUTLS_STATE state, char *data, int length); int gnutls_insertHashDataBuffer( GNUTLS_STATE state, char *data, int length); int gnutls_clearHashDataBuffer( GNUTLS_STATE state); -ssize_t _gnutls_Recv_int(int fd, GNUTLS_STATE state, ContentType type, void *iptr, size_t sizeOfPtr); -ssize_t _gnutls_Send_int(int fd, GNUTLS_STATE state, ContentType type, void *iptr, size_t n); +ssize_t _gnutls_Recv_int(int fd, GNUTLS_STATE, ContentType, HandshakeType, void *, size_t); +ssize_t _gnutls_Send_int(int fd, GNUTLS_STATE, ContentType, HandshakeType, void *, size_t); diff --git a/lib/gnutls_cert.c b/lib/gnutls_cert.c index 7a62eddb58..81f683fdc4 100644 --- a/lib/gnutls_cert.c +++ b/lib/gnutls_cert.c @@ -221,11 +221,26 @@ gnutls_datum tmp; res->ca_list = NULL; +{FILE* fd; +fd = fopen("/tmp/aaa1", "w"); +fwrite( ptr, siz, 1, fd); +fclose(fd); + +} + + do { siz2 = _gnutls_fbase64_decode(ptr, siz, &b64); siz-=siz2; /* FIXME: this is not enough */ +{FILE* fd; +fd = fopen("/tmp/test1", "w"); +fwrite( b64, siz2, 1, fd); +fclose(fd); + +} + if (siz2 < 0) { gnutls_assert(); gnutls_free(b64); @@ -385,9 +400,6 @@ int gnutls_set_x509_trust(X509PKI_CREDENTIALS res, char* CAFILE, char* CRLFILE) { int ret; -/* FIXME: This function fails (DER parsing) if it is called - * after gnutls_set_x509_key(). why? - */ if ( (ret=read_ca_file( res, CAFILE)) < 0) return ret; diff --git a/lib/gnutls_constate.c b/lib/gnutls_constate.c index 61cf259b24..7550a59f61 100644 --- a/lib/gnutls_constate.c +++ b/lib/gnutls_constate.c @@ -236,7 +236,7 @@ int rc; _gnutls_set_read_keys(state); -#ifdef DEBUG +#ifdef HANDSHAKE_DEBUG fprintf(stderr, "Cipher Suite: %s\n", _gnutls_cipher_suite_get_name(state-> security_parameters.current_cipher_suite)); @@ -381,7 +381,7 @@ int rc; _gnutls_set_write_keys(state); -#ifdef DEBUG +#ifdef HANDSHAKE_DEBUG fprintf(stderr, "Cipher Suite: %s\n", _gnutls_cipher_suite_get_name(state-> security_parameters.current_cipher_suite)); diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c index 3a3ed0f7a0..e46b4958bc 100644 --- a/lib/gnutls_handshake.c +++ b/lib/gnutls_handshake.c @@ -39,7 +39,7 @@ #include "gnutls_cert.h" #include "gnutls_constate.h" -#ifdef DEBUG +#ifdef HANDSHAKE_DEBUG #define ERR(x, y) fprintf(stderr, "GNUTLS Error: %s (%d)\n", x,y) #else #define ERR(x, y) @@ -243,6 +243,7 @@ int _gnutls_read_client_hello(GNUTLS_STATE state, opaque * data, int len = datalen; int err; opaque random[TLS_RANDOM_SIZE]; + GNUTLS_Version ver; if (state->gnutls_internals.v2_hello != 0) { /* version 2.0 */ return _gnutls_read_client_hello_v2(state, data, datalen); @@ -250,7 +251,7 @@ int _gnutls_read_client_hello(GNUTLS_STATE state, opaque * data, DECR_LEN(len, 2); -#ifdef DEBUG +#ifdef HANDSHAKE_DEBUG fprintf(stderr, "Client's version: %d.%d\n", data[pos], data[pos + 1]); #endif @@ -259,12 +260,24 @@ int _gnutls_read_client_hello(GNUTLS_STATE state, opaque * data, /* if we do not support that version */ if (_gnutls_version_is_supported(state, version) == 0) { + /* If he requested something we do not support + * then we send him the lowest we support. + */ + ver = _gnutls_version_lowest( state); + } else { + ver = version; + } + + /* he should have send us the highest version + * he supports. + */ + if (ver==GNUTLS_VERSION_UNKNOWN || ver > version) { gnutls_assert(); return GNUTLS_E_UNSUPPORTED_VERSION_PACKET; - } else { - gnutls_set_current_version(state, version); } + _gnutls_set_current_version(state, ver); + pos += 2; DECR_LEN(len, TLS_RANDOM_SIZE); @@ -341,7 +354,7 @@ int _gnutls_read_client_hello(GNUTLS_STATE state, opaque * data, (state->security_parameters. current_cipher_suite)); if (state->gnutls_internals.auth_struct == NULL) { -#ifdef DEBUG +#ifdef HANDSHAKE_DEBUG fprintf(stderr, "Cannot find the appropriate handler for the KX algorithm\n"); #endif @@ -589,7 +602,7 @@ int _gnutls_send_handshake(SOCKET cd, GNUTLS_STATE state, void *i_data, gnutls_insertHashDataBuffer(state, data, i_datasize); ret = - _gnutls_Send_int(cd, state, GNUTLS_HANDSHAKE, data, + _gnutls_Send_int(cd, state, GNUTLS_HANDSHAKE, type, data, i_datasize); gnutls_free(data); @@ -615,7 +628,7 @@ int _gnutls_recv_handshake(SOCKET cd, GNUTLS_STATE state, uint8 ** data, dataptr = gnutls_malloc(HANDSHAKE_HEADERS_SIZE); ret = - _gnutls_Recv_int(cd, state, GNUTLS_HANDSHAKE, dataptr, + _gnutls_Recv_int(cd, state, GNUTLS_HANDSHAKE, type, dataptr, SSL2_HEADERS); if (ret < 0) { gnutls_assert(); @@ -632,7 +645,7 @@ int _gnutls_recv_handshake(SOCKET cd, GNUTLS_STATE state, uint8 ** data, || type != GNUTLS_CLIENT_HELLO) { ret = - _gnutls_Recv_int(cd, state, GNUTLS_HANDSHAKE, + _gnutls_Recv_int(cd, state, GNUTLS_HANDSHAKE, type, &dataptr[SSL2_HEADERS], HANDSHAKE_HEADERS_SIZE - SSL2_HEADERS); @@ -698,7 +711,7 @@ int _gnutls_recv_handshake(SOCKET cd, GNUTLS_STATE state, uint8 ** data, sum = handshake_headers; do { ret = - _gnutls_Recv_int(cd, state, GNUTLS_HANDSHAKE, + _gnutls_Recv_int(cd, state, GNUTLS_HANDSHAKE, type, &dataptr[sum], length32); sum += ret; } while (((sum - handshake_headers) < length32) && (ret > 0)); @@ -811,7 +824,7 @@ static int _gnutls_read_server_hello(GNUTLS_STATE state, char *data, gnutls_assert(); return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; } -#ifdef DEBUG +#ifdef HANDSHAKE_DEBUG fprintf(stderr, "Server's version: %d.%d\n", data[pos], data[pos + 1]); #endif @@ -821,7 +834,7 @@ static int _gnutls_read_server_hello(GNUTLS_STATE state, char *data, gnutls_assert(); return GNUTLS_E_UNSUPPORTED_VERSION_PACKET; } else { - gnutls_set_current_version(state, version); + _gnutls_set_current_version(state, version); } pos += 2; @@ -922,7 +935,7 @@ static int _gnutls_read_server_hello(GNUTLS_STATE state, char *data, _gnutls_kx_auth_struct(_gnutls_cipher_suite_get_kx_algo (cipher_suite)); if (state->gnutls_internals.auth_struct == NULL) { -#ifdef DEBUG +#ifdef HANDSHAKE_DEBUG fprintf(stderr, "Cannot find the appropriate handler for the KX algorithm\n"); #endif @@ -978,6 +991,7 @@ static int _gnutls_send_client_hello(SOCKET cd, GNUTLS_STATE state) int i, datalen, ret = 0; uint16 x; opaque random[TLS_RANDOM_SIZE]; + GNUTLS_Version hver; opaque *SessionID = state->gnutls_internals.resumed_security_parameters.session_id; @@ -994,10 +1008,11 @@ static int _gnutls_send_client_hello(SOCKET cd, GNUTLS_STATE state) */ data = gnutls_malloc(datalen); + hver = _gnutls_version_max(state); data[pos++] = - _gnutls_version_get_major(state->connection_state.version); + _gnutls_version_get_major( hver); data[pos++] = - _gnutls_version_get_minor(state->connection_state.version); + _gnutls_version_get_minor( hver); _gnutls_create_random(random); _gnutls_set_client_random(state, random); @@ -1408,7 +1423,7 @@ static int _gnutls_recv_handshake_final(SOCKET cd, GNUTLS_STATE state, int ret = 0; ret = - gnutls_recv_int(cd, state, GNUTLS_CHANGE_CIPHER_SPEC, + gnutls_recv_int(cd, state, GNUTLS_CHANGE_CIPHER_SPEC, -1, NULL, 0, 0); if (ret < 0) { ERR("recv ChangeCipherSpec", ret); diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 5f0e8a8a14..7fa6719463 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -30,9 +30,9 @@ #define HARD_DEBUG #define BUFFERS_DEBUG #define RECORD_DEBUG -#define HANDSHAKE_DEBUG*/ +#define HANDSHAKE_DEBUG #define DEBUG - +*/ #define SOCKET int #define LIST ... @@ -268,7 +268,10 @@ typedef struct { */ } CipherSpecs; -typedef enum GNUTLS_Version { GNUTLS_TLS1, GNUTLS_SSL3, GNUTLS_VERSION_UNKNOWN=0xff } GNUTLS_Version; +/* Versions should be in order of the oldest + * (eg. SSL3 is before TLS1) + */ +typedef enum GNUTLS_Version { GNUTLS_SSL3=1, GNUTLS_TLS1, GNUTLS_VERSION_UNKNOWN=0xff } GNUTLS_Version; typedef struct { GNUTLS_Version version; @@ -290,6 +293,7 @@ typedef struct { #define MACAlgorithm_Priority GNUTLS_Priority #define KXAlgorithm_Priority GNUTLS_Priority #define CompressionMethod_Priority GNUTLS_Priority +#define Protocol_Priority GNUTLS_Priority typedef struct { gnutls_datum buffer; @@ -305,6 +309,8 @@ typedef struct { MACAlgorithm_Priority MACAlgorithmPriority; KXAlgorithm_Priority KXAlgorithmPriority; CompressionMethod_Priority CompressionMethodPriority; + Protocol_Priority ProtocolPriority; + /* resumed session */ ResumableSession resumed; /* TRUE or FALSE - if we are resuming a session */ SecurityParameters resumed_security_parameters; @@ -344,10 +350,10 @@ int gnutls_close(SOCKET cd, GNUTLS_STATE state); svoid *gnutls_PRF( opaque * secret, int secret_size, uint8 * label, int label_size, opaque * seed, int seed_size, int total_bytes); -void gnutls_set_current_version(GNUTLS_STATE state, GNUTLS_Version version); +void _gnutls_set_current_version(GNUTLS_STATE state, GNUTLS_Version version); GNUTLS_Version gnutls_get_current_version(GNUTLS_STATE state); -ssize_t gnutls_send_int(SOCKET cd, GNUTLS_STATE state, ContentType type, const void* data, size_t sizeofdata, int flags); -ssize_t gnutls_recv_int(SOCKET cd, GNUTLS_STATE state, ContentType type, char* data, size_t sizeofdata, int flags); +ssize_t gnutls_send_int(SOCKET cd, GNUTLS_STATE state, ContentType type, HandshakeType htype, const void* data, size_t sizeofdata, int flags); +ssize_t gnutls_recv_int(SOCKET cd, GNUTLS_STATE state, ContentType type, HandshakeType, char* data, size_t sizeofdata, int flags); int _gnutls_send_change_cipher_spec(SOCKET cd, GNUTLS_STATE state); int _gnutls_version_cmp(GNUTLS_Version ver1, GNUTLS_Version ver2); #define _gnutls_version_ssl3(x) _gnutls_version_cmp(x, GNUTLS_SSL3) diff --git a/lib/gnutls_priority.c b/lib/gnutls_priority.c index 4cf098c3b9..94af37847b 100644 --- a/lib/gnutls_priority.c +++ b/lib/gnutls_priority.c @@ -185,3 +185,50 @@ int gnutls_set_compression_priority( GNUTLS_STATE state, LIST) { va_end(ap); return 0; } + +/** + * gnutls_set_protocol_priority - Sets the priority on the protocol versions supported by gnutls. + * @state: is a &GNUTLS_STATE structure. + * @LIST: is a 0 terminated list of GNUTLS_Version elements. + * + * Sets the priority on the protocol versions supported by gnutls. + * Priority is higher for protocols specified before others. + * After specifying the protocols you want, you should add 0. + * Note that the priority is set on the client. The server does + * not use the protocols's priority except for disabling + * protocols that were not specified. + **/ +int gnutls_set_protocol_priority( GNUTLS_STATE state, LIST) { + + va_list ap; + int i,num=0; + va_list _ap; + + va_start( ap, state); + _ap = ap; + + while( va_arg( ap, int) != 0) { + num++; + } + + if (state->gnutls_internals.ProtocolPriority.algorithm_priority!=NULL) + gnutls_free(state->gnutls_internals.ProtocolPriority.algorithm_priority); + + state->gnutls_internals.ProtocolPriority.algorithm_priority = gnutls_malloc(sizeof(int*)*num); + + if (state->gnutls_internals.ProtocolPriority.algorithm_priority == NULL) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + state->gnutls_internals.ProtocolPriority.algorithms = num; + for (i=0;ignutls_internals.ProtocolPriority.algorithm_priority[i] = va_arg( _ap, int); + } + va_end(ap); + + /* set the current version to the lowest + */ + _gnutls_set_current_version( state, state->gnutls_internals.ProtocolPriority.algorithm_priority[num-1]); + return 0; +} diff --git a/lib/gnutls_priority.h b/lib/gnutls_priority.h index fe01235ce8..8d8b952f5a 100644 --- a/lib/gnutls_priority.h +++ b/lib/gnutls_priority.h @@ -18,7 +18,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -void gnutls_set_cipher_priority( GNUTLS_STATE state, LIST); -void gnutls_set_kx_priority( GNUTLS_STATE state, LIST); -void gnutls_set_mac_priority( GNUTLS_STATE state, LIST); -void gnutls_set_compression_priority( GNUTLS_STATE state, LIST); +int gnutls_set_cipher_priority( GNUTLS_STATE state, LIST); +int gnutls_set_kx_priority( GNUTLS_STATE state, LIST); +int gnutls_set_mac_priority( GNUTLS_STATE state, LIST); +int gnutls_set_compression_priority( GNUTLS_STATE state, LIST); +int gnutls_set_protocol_priority( GNUTLS_STATE state, LIST); diff --git a/lib/gnutls_record.c b/lib/gnutls_record.c index 8f77328e35..56db2dec7f 100644 --- a/lib/gnutls_record.c +++ b/lib/gnutls_record.c @@ -49,7 +49,7 @@ GNUTLS_Version ver; return ver; } -void gnutls_set_current_version(GNUTLS_STATE state, GNUTLS_Version version) { +void _gnutls_set_current_version(GNUTLS_STATE state, GNUTLS_Version version) { state->connection_state.version = version; if (state->gnutls_key!=NULL) { state->gnutls_key->version.major = _gnutls_version_get_major(version); @@ -102,7 +102,7 @@ int gnutls_init(GNUTLS_STATE * state, ConnectionEnd con_end) (*state)->gnutls_internals.resumable = RESUME_TRUE; - gnutls_set_current_version ( (*state), GNUTLS_TLS1); /* default */ + gnutls_set_protocol_priority( *state, GNUTLS_TLS1, 0); /* default */ (*state)->gnutls_key = gnutls_calloc(1, sizeof(GNUTLS_KEY_A)); @@ -341,11 +341,11 @@ int _gnutls_send_alert(SOCKET cd, GNUTLS_STATE state, AlertLevel level, AlertDes memcpy(&data[0], &level, 1); memcpy(&data[1], &desc, 1); -#ifdef DEBUG +#ifdef RECORD_DEBUG fprintf(stderr, "Record: Sending Alert[%d|%d] - %s\n", data[0], data[1], _gnutls_alert2str((int)data[1])); #endif - return gnutls_send_int(cd, state, GNUTLS_ALERT, data, 2, 0); + return gnutls_send_int(cd, state, GNUTLS_ALERT, -1, data, 2, 0); } /** @@ -367,7 +367,7 @@ int gnutls_bye(SOCKET cd, GNUTLS_STATE state, int wait) ret = _gnutls_send_alert(cd, state, GNUTLS_WARNING, GNUTLS_CLOSE_NOTIFY); /* receive the closure alert */ - if (wait==0) gnutls_recv_int(cd, state, GNUTLS_ALERT, NULL, 0, 0); + if (wait==0) gnutls_recv_int(cd, state, GNUTLS_ALERT, -1, NULL, 0, 0); state->gnutls_internals.valid_connection = VALID_FALSE; @@ -379,7 +379,7 @@ int gnutls_bye(SOCKET cd, GNUTLS_STATE state, int wait) * send (if called by the user the Content is specific) * It is intended to transfer data, under the current state. */ -ssize_t gnutls_send_int(SOCKET cd, GNUTLS_STATE state, ContentType type, const void *_data, size_t sizeofdata, int flags) +ssize_t gnutls_send_int(SOCKET cd, GNUTLS_STATE state, ContentType type, HandshakeType htype, const void *_data, size_t sizeofdata, int flags) { uint8 *cipher; int i, cipher_size; @@ -388,6 +388,7 @@ ssize_t gnutls_send_int(SOCKET cd, GNUTLS_STATE state, ContentType type, const v int Size; uint8 headers[5]; const uint8 *data=_data; + GNUTLS_Version lver; if (sizeofdata == 0) return 0; @@ -405,9 +406,23 @@ ssize_t gnutls_send_int(SOCKET cd, GNUTLS_STATE state, ContentType type, const v } headers[0]=type; - headers[1]=_gnutls_version_get_major(state->connection_state.version); - headers[2]=_gnutls_version_get_minor(state->connection_state.version); + + if (htype==GNUTLS_CLIENT_HELLO) { /* then send the lowest + * protocol we support + */ + lver = _gnutls_version_lowest(state); + if (lver==GNUTLS_VERSION_UNKNOWN) { + gnutls_assert(); + return GNUTLS_E_UNSUPPORTED_VERSION_PACKET; + } + } else { /* send the current */ + lver = gnutls_get_current_version( state); + } + headers[1]=_gnutls_version_get_major( lver); + headers[2]=_gnutls_version_get_minor( lver); + + #ifdef RECORD_DEBUG fprintf(stderr, "Record: Sending Packet[%d] %s(%d) with length: %d\n", (int) uint64touint32(&state->connection_state.write_sequence_number), _gnutls_packet2str(type), type, sizeofdata); @@ -495,7 +510,7 @@ ssize_t _gnutls_send_change_cipher_spec(SOCKET cd, GNUTLS_STATE state) fprintf(stderr, "Record: Sending ChangeCipherSpec\n"); #endif - return gnutls_send_int( cd, state, GNUTLS_CHANGE_CIPHER_SPEC, data, 1, 0); + return gnutls_send_int( cd, state, GNUTLS_CHANGE_CIPHER_SPEC, -1, data, 1, 0); } @@ -510,6 +525,8 @@ char peekdata; return 0; } +#define CHECK_RECORD_VERSION + /* This function behave exactly like read(). The only difference is * that it accepts, the gnutls_state and the ContentType of data to * send (if called by the user the Content is Userdata only) @@ -517,7 +534,7 @@ char peekdata; * flags is the sockets flags to use. Currently only MSG_DONTWAIT is * supported. */ -ssize_t gnutls_recv_int(SOCKET cd, GNUTLS_STATE state, ContentType type, char *data, size_t sizeofdata, int flags) +ssize_t gnutls_recv_int(SOCKET cd, GNUTLS_STATE state, ContentType type, HandshakeType htype, char *data, size_t sizeofdata, int flags) { uint8 *tmpdata; int tmplen; @@ -564,7 +581,7 @@ ssize_t gnutls_recv_int(SOCKET cd, GNUTLS_STATE state, ContentType type, char *d /* Read the first two bytes to determine if this is a * version 2 message */ - if ( headers[0] > 127 && type==GNUTLS_HANDSHAKE) { + if ( headers[0] > 127 && type==GNUTLS_HANDSHAKE && htype == GNUTLS_CLIENT_HELLO) { /* if msb set and expecting handshake message * it should be SSL 2 hello @@ -576,7 +593,7 @@ ssize_t gnutls_recv_int(SOCKET cd, GNUTLS_STATE state, ContentType type, char *d recv_type = GNUTLS_HANDSHAKE; /* we accept only v2 client hello */ state->gnutls_internals.v2_hello = length; -#ifdef DEBUG +#ifdef RECORD_DEBUG fprintf(stderr, "Record: V2 packet received. Length: %d\n", length); #endif @@ -584,15 +601,18 @@ ssize_t gnutls_recv_int(SOCKET cd, GNUTLS_STATE state, ContentType type, char *d /* version 3.x */ recv_type = headers[0]; +#ifdef CHECK_RECORD_VERSION version = _gnutls_version_get( headers[1], headers[2]); +#endif length = READuint16( &headers[3]); } - - if ( gnutls_get_current_version(state) != version && recv_type != GNUTLS_HANDSHAKE) { -#ifdef DEBUG + +#ifdef CHECK_RECORD_VERSION + if ( htype!=GNUTLS_CLIENT_HELLO && gnutls_get_current_version(state) != version) { +# ifdef RECORD_DEBUG fprintf(stderr, "Record: INVALID VERSION PACKET: (%d) %d.%d\n", headers[0], headers[1], headers[2]); -#endif +# endif if (type!=GNUTLS_ALERT) { /* some browsers return garbage, when * we send them a close notify. @@ -604,7 +624,7 @@ ssize_t gnutls_recv_int(SOCKET cd, GNUTLS_STATE state, ContentType type, char *d gnutls_assert(); return GNUTLS_E_UNSUPPORTED_VERSION_PACKET; } - +#endif #ifdef RECORD_DEBUG fprintf(stderr, "Record: Expected Packet[%d] %s(%d) with length: %d\n", @@ -614,7 +634,7 @@ ssize_t gnutls_recv_int(SOCKET cd, GNUTLS_STATE state, ContentType type, char *d #endif if (length > MAX_RECV_SIZE) { -#ifdef DEBUG +#ifdef RECORD_DEBUG fprintf(stderr, "Record: FATAL ERROR: Received packet with length: %d\n", length); #endif _gnutls_send_alert(cd, state, GNUTLS_FATAL, GNUTLS_RECORD_OVERFLOW); @@ -668,7 +688,7 @@ ssize_t gnutls_recv_int(SOCKET cd, GNUTLS_STATE state, ContentType type, char *d * received that data. */ if (ret != length) { -#ifdef DEBUG +#ifdef RECORD_DEBUG fprintf(stderr, "Record: Received packet with length: %d\nExpected %d\n", ret, length); #endif gnutls_free(ciphertext); @@ -736,7 +756,7 @@ ssize_t gnutls_recv_int(SOCKET cd, GNUTLS_STATE state, ContentType type, char *d } else { switch (recv_type) { case GNUTLS_ALERT: -#ifdef DEBUG +#ifdef RECORD_DEBUG fprintf(stderr, "Record: Alert[%d|%d] - %s - was received\n", tmpdata[0], tmpdata[1], _gnutls_alert2str((int)tmpdata[1])); #endif state->gnutls_internals.last_alert = tmpdata[1]; @@ -793,7 +813,7 @@ ssize_t gnutls_recv_int(SOCKET cd, GNUTLS_STATE state, ContentType type, char *d break; default: -#ifdef DEBUG +#ifdef RECORD_DEBUG fprintf(stderr, "Record: Received Unknown packet %d expecting %d\n", recv_type, type); #endif gnutls_assert(); @@ -974,7 +994,7 @@ AlertDescription gnutls_get_last_alert( GNUTLS_STATE state) { * be anything except 0. **/ ssize_t gnutls_send(SOCKET cd, GNUTLS_STATE state, const void *data, size_t sizeofdata, int flags) { - return gnutls_send_int( cd, state, GNUTLS_APPLICATION_DATA, data, sizeofdata, flags); + return gnutls_send_int( cd, state, GNUTLS_APPLICATION_DATA, -1, data, sizeofdata, flags); } /** @@ -993,7 +1013,7 @@ ssize_t gnutls_send(SOCKET cd, GNUTLS_STATE state, const void *data, size_t size * if there are no data in the socket. **/ ssize_t gnutls_recv(SOCKET cd, GNUTLS_STATE state, void *data, size_t sizeofdata, int flags) { - return gnutls_recv_int( cd, state, GNUTLS_APPLICATION_DATA, data, sizeofdata, flags); + return gnutls_recv_int( cd, state, GNUTLS_APPLICATION_DATA, -1, data, sizeofdata, flags); } /** @@ -1007,7 +1027,7 @@ ssize_t gnutls_recv(SOCKET cd, GNUTLS_STATE state, void *data, size_t sizeofdata * difference is that is accepts a GNUTLS state. **/ ssize_t gnutls_write(SOCKET cd, GNUTLS_STATE state, const void *data, size_t sizeofdata) { - return gnutls_send_int( cd, state, GNUTLS_APPLICATION_DATA, data, sizeofdata, 0); + return gnutls_send_int( cd, state, GNUTLS_APPLICATION_DATA, -1, data, sizeofdata, 0); } /** @@ -1021,5 +1041,5 @@ ssize_t gnutls_write(SOCKET cd, GNUTLS_STATE state, const void *data, size_t siz * difference is that is accepts a GNUTLS state. **/ ssize_t gnutls_read(SOCKET cd, GNUTLS_STATE state, void *data, size_t sizeofdata) { - return gnutls_recv_int( cd, state, GNUTLS_APPLICATION_DATA, data, sizeofdata, 0); + return gnutls_recv_int( cd, state, GNUTLS_APPLICATION_DATA, -1, data, sizeofdata, 0); } diff --git a/lib/gnutls_v2_compat.c b/lib/gnutls_v2_compat.c index 7a6e21d6b4..97fc2dc09b 100644 --- a/lib/gnutls_v2_compat.c +++ b/lib/gnutls_v2_compat.c @@ -111,12 +111,13 @@ int _gnutls_read_client_hello_v2(GNUTLS_STATE state, opaque * data, int err; uint16 challenge; opaque session_id[TLS_MAX_SESSION_ID_SIZE]; + GNUTLS_Version ver; /* we only want to get here once - only in client hello */ state->gnutls_internals.v2_hello = 0; DECR_LEN(len, 2); -#ifdef DEBUG +#ifdef HANDSHAKE_DEBUG fprintf(stderr, "V2 Handshake: Client's version: %d.%d\n", data[pos], data[pos + 1]); #endif @@ -125,12 +126,18 @@ int _gnutls_read_client_hello_v2(GNUTLS_STATE state, opaque * data, /* if we do not support that version */ if (_gnutls_version_is_supported(state, version) == 0) { + ver = _gnutls_version_lowest( state); + } else { + ver = version; + } + + if (ver==GNUTLS_VERSION_UNKNOWN || ver > version) { gnutls_assert(); return GNUTLS_E_UNSUPPORTED_VERSION_PACKET; - } else { - gnutls_set_current_version(state, version); } + _gnutls_set_current_version(state, ver); + pos += 2; @@ -188,7 +195,7 @@ int _gnutls_read_client_hello_v2(GNUTLS_STATE state, opaque * data, (state->security_parameters. current_cipher_suite)); if (state->gnutls_internals.auth_struct == NULL) { -#ifdef DEBUG +#ifdef HANDSHAKE_DEBUG fprintf(stderr, "V2 Handshake: Cannot find the appropriate handler for the KX algorithm\n"); #endif diff --git a/src/serv.c b/src/serv.c index a97e657dda..b5e9769ab9 100644 --- a/src/serv.c +++ b/src/serv.c @@ -97,6 +97,8 @@ GNUTLS_STATE initialize_state() gnutls_set_compression_priority(state, GNUTLS_ZLIB, GNUTLS_NULL_COMPRESSION, 0); gnutls_set_kx_priority(state, GNUTLS_KX_DHE_RSA, GNUTLS_KX_RSA, GNUTLS_KX_SRP, GNUTLS_KX_DH_ANON, 0); + gnutls_set_protocol_priority( state, GNUTLS_TLS1, GNUTLS_SSL3, 0); + gnutls_set_cred(state, GNUTLS_ANON, dh_cred); gnutls_set_cred(state, GNUTLS_SRP, srp_cred); gnutls_set_cred(state, GNUTLS_X509PKI, x509_cred); @@ -315,7 +317,6 @@ int main(int argc, char **argv) - listen_sd = socket(AF_INET, SOCK_STREAM, 0); ERR(listen_sd, "socket"); -- cgit v1.2.1