]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
corrected bug in b64 decoding. Added support for multiple TLS protocol
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Tue, 24 Jul 2001 18:26:51 +0000 (18:26 +0000)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Tue, 24 Jul 2001 18:26:51 +0000 (18:26 +0000)
versions.

16 files changed:
NEWS
lib/cert_b64.c
lib/gnutls.h.in
lib/gnutls_algorithms.c
lib/gnutls_algorithms.h
lib/gnutls_buffers.c
lib/gnutls_buffers.h
lib/gnutls_cert.c
lib/gnutls_constate.c
lib/gnutls_handshake.c
lib/gnutls_int.h
lib/gnutls_priority.c
lib/gnutls_priority.h
lib/gnutls_record.c
lib/gnutls_v2_compat.c
src/serv.c

diff --git a/NEWS b/NEWS
index e85639673e9731b95f3f508401f332d78e3e14c8..8caee5fb430e078a66ed92460efff6f507096c10 100644 (file)
--- 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.
index 9613e455b4d139540821f67d2121eb16a132c5e1..d953c4dd2c02e523ed84467357ed4dcddc0a46f3 100644 (file)
@@ -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();
index 3ca2c23bdb0a2e3f324e2c033dde7c96980c328e..30c0e4562366acb14b1e7e9fab89b528f7e3508e 100644 (file)
@@ -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);
 
index 4aacabc7e8230e8377d61907680dd0b7eea8e6d6..f15504a3e31b1ee60f1cc7e2c96d02f1ed57fa86 100644 (file)
@@ -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 */
index 1b869606f709c5287efab60f1e9d7fac3062e321..e7c643b247a51d239c570400deb331a7a3aeeda9 100644 (file)
 #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);
index f31fc48ea2892e6ff509032370da43326f49d4b1..f368e88a0c6b8630d00f66a82990ae5b4d2a26c5 100644 (file)
@@ -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 {
index 6b23f60397f33ecd14d0cd7a72de587c8fe0713c..7ecbfe88f96d6b56ad9d183836c792357d3cd18a 100644 (file)
@@ -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);
index 7a62eddb58bd6a8e4881a90764ac7edfc65b1171..81f683fdc4befdd783e49741754b2a3442329277 100644 (file)
@@ -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;
 
index 61cf259b247facbb481a447b591270dd2f1999b3..7550a59f6171842977876e706d2e79888bc3b6e5 100644 (file)
@@ -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));
index 3a3ed0f7a0695d4b1e76e7e075bd6f549d49564a..e46b4958bc2b38d0eba8af1d57bcdad898069d16 100644 (file)
@@ -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);
index 5f0e8a8a14cddc214a21b041299e5715d6385ac8..7fa671946381f25139bf33d9f236698e4872aab9 100644 (file)
@@ -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)
index 4cf098c3b919643b4477cd2910a4e990030d6b54..94af37847becf10cebdf44788b53f5fa37223784 100644 (file)
@@ -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;i<num;i++) {
+               state->gnutls_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;
+}
index fe01235ce859c7237375f1057e3fc6d15888bc8f..8d8b952f5a035ed857cd9b4b665afa54372dc5ec 100644 (file)
@@ -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);
index 8f77328e357d7849df4a62ea7517fb187663c34c..56db2dec7f93b555e01d540f6f660172b2d958d2 100644 (file)
@@ -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);
 }
index 7a6e21d6b49ea0c9339ffddaebbc12e281dd2873..97fc2dc09b86199a8561d2b726e068db2b57dfb7 100644 (file)
@@ -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
index a97e657dda0ecdf0a24cd154bee3c64c60628a1e..b5e9769ab939d3e973271dc5f3a62604742665b6 100644 (file)
@@ -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");