summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2001-07-24 18:26:51 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2001-07-24 18:26:51 +0000
commitdc1122e7b6c6437a0e20d93679e0f8af5b3869c7 (patch)
tree7cef5217443bc85f1397a38c6d9b32a5a0439a68
parentc8a1ec8a502e38dcb68896544ec5adfcfebddacd (diff)
downloadgnutls-dc1122e7b6c6437a0e20d93679e0f8af5b3869c7.tar.gz
corrected bug in b64 decoding. Added support for multiple TLS protocol
versions.
-rw-r--r--NEWS1
-rw-r--r--lib/cert_b64.c52
-rw-r--r--lib/gnutls.h.in12
-rw-r--r--lib/gnutls_algorithms.c55
-rw-r--r--lib/gnutls_algorithms.h4
-rw-r--r--lib/gnutls_buffers.c8
-rw-r--r--lib/gnutls_buffers.h4
-rw-r--r--lib/gnutls_cert.c18
-rw-r--r--lib/gnutls_constate.c4
-rw-r--r--lib/gnutls_handshake.c45
-rw-r--r--lib/gnutls_int.h18
-rw-r--r--lib/gnutls_priority.c47
-rw-r--r--lib/gnutls_priority.h9
-rw-r--r--lib/gnutls_record.c70
-rw-r--r--lib/gnutls_v2_compat.c15
-rw-r--r--src/serv.c3
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;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;
+}
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");