summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2001-05-07 19:09:43 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2001-05-07 19:09:43 +0000
commit0cc853fbe29baff7862a95d8bfcc9524eaa90df1 (patch)
tree8bc8c48f4e37f663a55ae042bb7ab5dba2e92707
parent4a25412e8773031b9ec541b1d6c5f0944d88f909 (diff)
downloadgnutls-0cc853fbe29baff7862a95d8bfcc9524eaa90df1.tar.gz
added support for SSL 2.0 client hello
-rw-r--r--NEWS7
-rw-r--r--doc/TODO1
-rw-r--r--lib/Makefile.am4
-rw-r--r--lib/gnutls.c61
-rw-r--r--lib/gnutls_handshake.c1253
-rw-r--r--lib/gnutls_int.h7
-rw-r--r--lib/gnutls_v2_compat.c260
-rw-r--r--lib/gnutls_v2_compat.h1
-rw-r--r--src/cli.c3
9 files changed, 1050 insertions, 547 deletions
diff --git a/NEWS b/NEWS
index 47e0c5e94a..7614ababd2 100644
--- a/NEWS
+++ b/NEWS
@@ -1,7 +1,8 @@
-Version 0.0.8 (28/01/2001)
+Version 0.1.0 (?)
+- Added SSL 2.0 client hello support
- GNUTLS is a gnu library
-- Added some support for TLS extensions.
-- Added some support for SRP
+- Added support for TLS extensions.
+- Added support for SRP
Version 0.0.7 (11/01/2001)
- Added server side session resuming (using gdbm)
diff --git a/doc/TODO b/doc/TODO
index fca1f145f6..f0d55e9ab5 100644
--- a/doc/TODO
+++ b/doc/TODO
@@ -2,4 +2,3 @@
* x509 Certificate API (we need an ASN.1 parser or something)
* Add Kerberos support
* OpenPGP certificate support (through libgcrypt)
-* Add support for v2.0 init packet (why do that anyway ???)
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 269b3f1d6a..5e6f6ed319 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -6,7 +6,7 @@ EXTRA_DIST = debug.h gnutls_compress.h defines.h gnutls_plaintext.h \
gnutls_compress_int.h gnutls_session.h gnutls_priority.h gnutls_auth.h \
auth_anon.h auth_dhe_dss.h gnutls_extensions.h ext_srp.h \
gnutls_auth_int.h crypt_bcrypt.h gnutls_random.h crypt_srpsha1.h \
- cert_b64.h gnutls_srp.h auth_srp.h auth_srp_passwd.h
+ cert_b64.h gnutls_srp.h auth_srp.h auth_srp_passwd.h gnutls_v2_compat.h
lib_LTLIBRARIES = libgnutls.la
libgnutls_la_SOURCES = gnutls.c gnutls_compress.c debug.c gnutls_plaintext.c \
gnutls_cipher.c gnutls_buffers.c gnutls_handshake.c gnutls_num.c \
@@ -15,5 +15,5 @@ libgnutls_la_SOURCES = gnutls.c gnutls_compress.c debug.c gnutls_plaintext.c \
gnutls_compress_int.c gnutls_session.c gnutls_db.c cert_b64.c \
auth_anon.c auth_dhe_dss.c gnutls_extensions.c ext_srp.c gnutls_auth.c \
crypt_bcrypt.c crypt.c gnutls_random.c crypt_srpsha1.c gnutls_srp.c \
- auth_srp.c auth_srp_passwd.c
+ auth_srp.c auth_srp_passwd.c gnutls_v2_compat.c
libgnutls_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
diff --git a/lib/gnutls.c b/lib/gnutls.c
index 641037b5f7..4e873f8c8b 100644
--- a/lib/gnutls.c
+++ b/lib/gnutls.c
@@ -92,6 +92,8 @@ int gnutls_init(GNUTLS_STATE * state, ConnectionEnd con_end)
(*state)->cipher_specs.server_write_key = NULL;
(*state)->cipher_specs.client_write_key = NULL;
+ (*state)->gnutls_internals.v2_hello = 0;
+
(*state)->gnutls_internals.buffer = NULL;
/* SSL3 stuff */
(*state)->gnutls_internals.hash_buffer = NULL;
@@ -579,6 +581,7 @@ char peekdata;
* flags is the sockets flags to use. Currently only MSG_DONTWAIT is
* supported.
*/
+#define SSL2_HSIZE
ssize_t gnutls_recv_int(int cd, GNUTLS_STATE state, ContentType type, char *data, size_t sizeofdata, int flags)
{
uint8 *tmpdata;
@@ -589,7 +592,7 @@ ssize_t gnutls_recv_int(int cd, GNUTLS_STATE state, ContentType type, char *data
uint16 length;
uint8 *ciphertext;
int ret = 0;
-
+ int header_size = HEADER_SIZE;
/* If we have enough data in the cache do not bother receiving
* a new packet. (in order to flush the cache)
*/
@@ -621,37 +624,57 @@ ssize_t gnutls_recv_int(int cd, GNUTLS_STATE state, ContentType type, char *data
return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
}
- memcpy( &recv_type, &headers[0], 1);
- version = _gnutls_version_get( headers[1], headers[2]);
+ /* Read the first two bytes to determine if this is a
+ * version 2 message
+ */
+ if ( headers[0] > 127 && type==GNUTLS_HANDSHAKE) {
+
+ /* if msb set and expecting handshake message
+ * it should be SSL 2 hello
+ */
+ version = GNUTLS_SSL3; /* assume ssl 3.0 */
+ length = (((headers[0] & 0x7f) << 8)) | headers[1];
+ header_size = 2;
+ recv_type = GNUTLS_HANDSHAKE; /* only v2 client hello we accept */
+ state->gnutls_internals.v2_hello = length;
+#ifdef DEBUG
+ fprintf(stderr, "Record: V2 packet received. Length: %d\n", length);
+#endif
- memcpy( &length, &headers[3], 2);
+ } else {
+ /* version 3.x
+ */
+ memcpy( &recv_type, &headers[0], 1);
+ version = _gnutls_version_get( headers[1], headers[2]);
+
+ memcpy( &length, &headers[3], 2);
#ifndef WORDS_BIGENDIAN
- length = byteswap16(length);
+ length = byteswap16(length);
#endif
+ }
+
- if (_gnutls_version_is_supported(state, version) == 0) {
+ if (type != GNUTLS_HANDSHAKE && gnutls_get_current_version(state) != version) {
#ifdef DEBUG
- fprintf(stderr, "INVALID VERSION PACKET: %d.%d\n", headers[1], headers[2]);
+ fprintf(stderr, "Record: INVALID VERSION PACKET: (%d) %d.%d\n", headers[0], headers[1], headers[2]);
#endif
_gnutls_send_alert(cd, state, GNUTLS_FATAL, GNUTLS_PROTOCOL_VERSION);
state->gnutls_internals.resumable = RESUME_FALSE;
gnutls_assert();
return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
- } else {
- gnutls_set_current_version(state, version);
}
#ifdef HARD_DEBUG
- fprintf(stderr, "Expected Packet[%d] %s(%d) with length: %d\n",
+ fprintf(stderr, "Record: Expected Packet[%d] %s(%d) with length: %d\n",
(int) state->connection_state.read_sequence_number, _gnutls_packet2str(type), type, sizeofdata);
- fprintf(stderr, "Received Packet[%d] %s(%d) with length: %d\n",
+ fprintf(stderr, "Record: Received Packet[%d] %s(%d) with length: %d\n",
(int) state->connection_state.read_sequence_number, _gnutls_packet2str(recv_type), recv_type, length);
#endif
if (length > MAX_RECV_SIZE) {
#ifdef DEBUG
- fprintf(stderr, "FATAL ERROR: Received packet with length: %d\n", length);
+ fprintf(stderr, "Record: FATAL ERROR: Received packet with length: %d\n", length);
#endif
_gnutls_send_alert(cd, state, GNUTLS_FATAL, GNUTLS_RECORD_OVERFLOW);
state->gnutls_internals.valid_connection = VALID_FALSE;
@@ -660,12 +683,12 @@ ssize_t gnutls_recv_int(int cd, GNUTLS_STATE state, ContentType type, char *data
return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
}
- ciphertext = gnutls_malloc(length+HEADER_SIZE);
+ ciphertext = gnutls_malloc(length+header_size);
/* check if we have that data into buffer. This seems to be
* expensive - but this is the only way to handle Non Blocking IO.
*/
- if ( _gnutls_Read(cd, ciphertext, HEADER_SIZE+length, MSG_PEEK|flags) != length+HEADER_SIZE) {
+ if ( _gnutls_Read(cd, ciphertext, header_size+length, MSG_PEEK|flags) != length+header_size) {
gnutls_free(ciphertext);
if (errno==EAGAIN) return GNUTLS_E_AGAIN;
@@ -677,7 +700,7 @@ ssize_t gnutls_recv_int(int cd, GNUTLS_STATE state, ContentType type, char *data
/* ok now we are sure that we can read all the data - so
* move on !
*/
- if (_gnutls_Read(cd, headers, HEADER_SIZE, 0)!=HEADER_SIZE) { /* read and clear the headers - again! */
+ if (_gnutls_Read(cd, headers, header_size, 0)!=header_size) { /* read and clear the headers - again! */
state->gnutls_internals.valid_connection = VALID_FALSE;
state->gnutls_internals.resumable = RESUME_FALSE;
gnutls_assert();
@@ -699,7 +722,7 @@ ssize_t gnutls_recv_int(int cd, GNUTLS_STATE state, ContentType type, char *data
*/
if (ret != length) {
#ifdef DEBUG
- fprintf(stderr, "Received packet with length: %d\nExpected %d\n", ret, length);
+ fprintf(stderr, "Record: Received packet with length: %d\nExpected %d\n", ret, length);
#endif
gnutls_free(ciphertext);
state->gnutls_internals.valid_connection = VALID_FALSE;
@@ -710,7 +733,7 @@ ssize_t gnutls_recv_int(int cd, GNUTLS_STATE state, ContentType type, char *data
if (type == GNUTLS_CHANGE_CIPHER_SPEC && recv_type == GNUTLS_CHANGE_CIPHER_SPEC) {
#ifdef HARD_DEBUG
- fprintf(stderr, "ChangeCipherSpec Packet was received\n");
+ fprintf(stderr, "Record: ChangeCipherSpec Packet was received\n");
#endif
if (length!=1) {
gnutls_assert();
@@ -748,7 +771,7 @@ ssize_t gnutls_recv_int(int cd, GNUTLS_STATE state, ContentType type, char *data
switch (recv_type) {
case GNUTLS_ALERT:
#ifdef DEBUG
- fprintf(stderr, "Alert[%d|%d] - %s - was received\n", tmpdata[0], tmpdata[1], _gnutls_alert2str((int)tmpdata[1]));
+ 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];
@@ -782,7 +805,7 @@ ssize_t gnutls_recv_int(int cd, GNUTLS_STATE state, ContentType type, char *data
break;
default:
#ifdef DEBUG
- fprintf(stderr, "Received Unknown packet %d expecting %d\n", recv_type, type);
+ fprintf(stderr, "Record: Received Unknown packet %d expecting %d\n", recv_type, type);
#endif
gnutls_assert();
return GNUTLS_E_UNKNOWN_ERROR;
diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c
index af3867a8f2..6661172398 100644
--- a/lib/gnutls_handshake.c
+++ b/lib/gnutls_handshake.c
@@ -36,6 +36,7 @@
#include "gnutls_extensions.h"
#include "gnutls_random.h"
#include "gnutls_auth_int.h"
+#include "gnutls_v2_compat.h"
#ifdef DEBUG
#define ERR(x, y) fprintf(stderr, "GNUTLS Error: %s (%d)\n", x,y)
@@ -46,30 +47,39 @@
#define TRUE 1
#define FALSE 0
+static int SelectSuite(GNUTLS_STATE state, opaque ret[2], char *data, int datalen);
+static int SelectCompMethod(GNUTLS_STATE state, CompressionMethod * ret, opaque * data, int datalen);
+
/* Calculate The SSL3 Finished message */
#define SSL3_CLIENT_MSG "CLNT"
#define SSL3_SERVER_MSG "SRVR"
-void* _gnutls_ssl3_finished( GNUTLS_STATE state, int type, int skip) {
+void *_gnutls_ssl3_finished(GNUTLS_STATE state, int type, int skip)
+{
int siz;
GNUTLS_MAC_HANDLE td;
GNUTLS_MAC_HANDLE td2;
- char* data;
- char* concat=gnutls_malloc(36);
+ char *data;
+ char *concat = gnutls_malloc(36);
char *mesg;
-
- td = gnutls_mac_init_ssl3_handshake( GNUTLS_MAC_MD5, state->security_parameters.master_secret, 48);
- td2 = gnutls_mac_init_ssl3_handshake( GNUTLS_MAC_SHA, state->security_parameters.master_secret, 48);
-
- siz = gnutls_getHashDataBufferSize( state) - skip;
- data = gnutls_malloc( siz);
- gnutls_readHashDataFromBuffer( state, data, siz);
+ td = gnutls_mac_init_ssl3_handshake(GNUTLS_MAC_MD5,
+ state->security_parameters.
+ master_secret, 48);
+ td2 =
+ gnutls_mac_init_ssl3_handshake(GNUTLS_MAC_SHA,
+ state->security_parameters.
+ master_secret, 48);
+
+ siz = gnutls_getHashDataBufferSize(state) - skip;
+ data = gnutls_malloc(siz);
+
+ gnutls_readHashDataFromBuffer(state, data, siz);
gnutls_mac_ssl3(td, data, siz);
gnutls_mac_ssl3(td2, data, siz);
gnutls_free(data);
-
- if (type==GNUTLS_SERVER) {
+
+ if (type == GNUTLS_SERVER) {
mesg = SSL3_SERVER_MSG;
} else {
mesg = SSL3_CLIENT_MSG;
@@ -79,12 +89,12 @@ void* _gnutls_ssl3_finished( GNUTLS_STATE state, int type, int skip) {
gnutls_mac_ssl3(td2, mesg, siz);
data = gnutls_mac_deinit_ssl3_handshake(td);
- memcpy( concat, data, 16);
+ memcpy(concat, data, 16);
gnutls_free(data);
-
+
data = gnutls_mac_deinit_ssl3_handshake(td2);
- memcpy( &concat[16], data, 20);
+ memcpy(&concat[16], data, 20);
gnutls_free(data);
return concat;
}
@@ -92,49 +102,212 @@ void* _gnutls_ssl3_finished( GNUTLS_STATE state, int type, int skip) {
/* Hash the handshake messages as required by TLS 1.0 */
#define SERVER_MSG "server finished"
#define CLIENT_MSG "client finished"
-void* _gnutls_finished( GNUTLS_STATE state, int type, int skip) {
+void *_gnutls_finished(GNUTLS_STATE state, int type, int skip)
+{
int siz;
GNUTLS_MAC_HANDLE td;
GNUTLS_MAC_HANDLE td2;
- char* data;
+ char *data;
char concat[36];
char *mesg;
-
- td = gnutls_hash_init( GNUTLS_MAC_MD5);
- td2 = gnutls_hash_init( GNUTLS_MAC_SHA);
-
- siz = gnutls_getHashDataBufferSize( state) - skip;
- data = gnutls_malloc( siz);
- gnutls_readHashDataFromBuffer( state, data, siz);
+ td = gnutls_hash_init(GNUTLS_MAC_MD5);
+ td2 = gnutls_hash_init(GNUTLS_MAC_SHA);
+
+ siz = gnutls_getHashDataBufferSize(state) - skip;
+ data = gnutls_malloc(siz);
+
+ gnutls_readHashDataFromBuffer(state, data, siz);
gnutls_hash(td, data, siz);
gnutls_hash(td2, data, siz);
-
+
gnutls_free(data);
-
+
data = gnutls_hash_deinit(td);
- memcpy( concat, data, 16);
+ memcpy(concat, data, 16);
gnutls_free(data);
-
+
data = gnutls_hash_deinit(td2);
- memcpy( &concat[16], data, 20);
+ memcpy(&concat[16], data, 20);
gnutls_free(data);
- if (type==GNUTLS_SERVER) {
- mesg=SERVER_MSG;
+ if (type == GNUTLS_SERVER) {
+ mesg = SERVER_MSG;
} else {
- mesg=CLIENT_MSG;
+ mesg = CLIENT_MSG;
}
data =
- gnutls_PRF( state->security_parameters.master_secret,
- 48, mesg, strlen(mesg), concat,
- 36, 12);
+ gnutls_PRF(state->security_parameters.master_secret,
+ 48, mesg, strlen(mesg), concat, 36, 12);
return data;
}
+/* Read a client hello
+ * client hello must be a known version client hello
+ * or version 2.0 client hello (only for compatibility)
+ * version 2.0 is not supported.
+ */
+
+#define DECR_LEN(len, x) len-=x; if (len<0) {gnutls_assert(); return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;}
+
+int _gnutls_read_client_hello(GNUTLS_STATE state, opaque * data,
+ int datalen)
+{
+ uint8 session_id_len = 0, z;
+ int pos = 0;
+ int ret = 0;
+ uint16 sizeOfSuites;
+ GNUTLS_Version version;
+ time_t cur_time;
+ char *rand;
+ int len = datalen;
+ int err;
+
+ if (state->gnutls_internals.v2_hello!=0) { /* version 2.0 */
+ return _gnutls_read_client_hello_v2(state, data, datalen);
+ }
+
+ DECR_LEN(len, 2);
+
+#ifdef DEBUG
+ fprintf(stderr, "Client's version: %d.%d\n", data[pos],
+ data[pos + 1]);
+#endif
+
+ version = _gnutls_version_get(data[pos], data[pos + 1]);
+
+ /* if we do not support that version */
+ if (_gnutls_version_is_supported(state, version) == 0) {
+ gnutls_assert();
+ return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
+ } else {
+ gnutls_set_current_version(state, version);
+ }
+
+ pos += 2;
+
+ DECR_LEN(len, 32);
+ memmove(state->security_parameters.client_random, &data[pos], 32);
+ pos += 32;
+
+ /* generate server random value */
+#ifdef WORDS_BIGENDIAN
+ cur_time = time(NULL);
+#else
+ cur_time = byteswap32(time(NULL));
+#endif
+ memmove(state->security_parameters.server_random, &cur_time, 4);
+ rand = _gnutls_get_random(28, GNUTLS_STRONG_RANDOM);
+ memmove(&state->security_parameters.server_random[4], rand, 28);
+ _gnutls_free_rand(rand);
+ state->security_parameters.timestamp = time(NULL);
+
+ DECR_LEN(len, 1);
+ memmove(&session_id_len, &data[pos++], 1);
+
+ /* RESUME SESSION */
+ if (session_id_len > 32)
+ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+
+ DECR_LEN(len, session_id_len);
+ ret =
+ _gnutls_server_restore_session(state, &data[pos],
+ session_id_len);
+ pos += session_id_len;
+
+ if (ret == 0) { /* resumed! */
+ /* get the new random values */
+ memcpy(state->gnutls_internals.resumed_security_parameters.
+ server_random,
+ state->security_parameters.server_random, 32);
+ memcpy(state->gnutls_internals.resumed_security_parameters.
+ client_random,
+ state->security_parameters.client_random, 32);
+
+ state->gnutls_internals.resumed = RESUME_TRUE;
+ return 0;
+ } else {
+ _gnutls_generate_session_id(state->security_parameters.
+ session_id,
+ &state->security_parameters.
+ session_id_size);
+ state->gnutls_internals.resumed = RESUME_FALSE;
+ }
+
+ /* Select a ciphersuite */
+ DECR_LEN(len, 2);
+ memmove(&sizeOfSuites, &data[pos], 2);
+ pos += 2;
+
+#ifndef WORDS_BIGENDIAN
+ sizeOfSuites = byteswap16(sizeOfSuites);
+#endif
+
+ DECR_LEN(len, sizeOfSuites);
+ ret = SelectSuite(state, state->gnutls_internals.
+ current_cipher_suite.CipherSuite, &data[pos],
+ sizeOfSuites);
+
+ pos += sizeOfSuites;
+ if (ret < 0)
+ return ret;
+
+
+ /* check if the credentials (username, public key etc. are ok)
+ */
+ if (_gnutls_get_kx_cred
+ (state->gnutls_key,
+ _gnutls_cipher_suite_get_kx_algo(state->gnutls_internals.
+ current_cipher_suite),
+ &err) == NULL && err != 0) {
+ gnutls_assert();
+ return GNUTLS_E_INSUFICIENT_CRED;
+ }
+
+ /* set the MOD_AUTH_STRUCT to the appropriate struct
+ * according to the KX algorithm. This is needed since all the
+ * handshake functions are read from there;
+ */
+ state->gnutls_internals.auth_struct =
+ _gnutls_kx_auth_struct(_gnutls_cipher_suite_get_kx_algo
+ (state->gnutls_internals.
+ current_cipher_suite));
+ if (state->gnutls_internals.auth_struct == NULL) {
+#ifdef DEBUG
+ fprintf(stderr,
+ "Cannot find the appropriate handler for the KX algorithm\n");
+#endif
+ gnutls_assert();
+ return GNUTLS_E_UNKNOWN_CIPHER_TYPE;
+ }
+
+ DECR_LEN(len, 1);
+ memmove(&z, &data[pos++], 1); /* z is the number of compression methods */
+
+ DECR_LEN(len, z);
+ ret = SelectCompMethod(state, &state->
+ gnutls_internals.compression_method,
+ &data[pos], z);
+ pos += z;
+
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ ret = _gnutls_parse_extensions(state, &data[pos], len); /* len is the rest of the parsed length */
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ return ret;
+}
+
+
/* This is to be called after sending CHANGE CIPHER SPEC packet
* and initializing encryption. This is the first encrypted message
* we send.
@@ -146,14 +319,21 @@ int _gnutls_send_finished(int cd, GNUTLS_STATE state)
int data_size;
if (_gnutls_version_ssl3(state->connection_state.version) == 0) {
- data = _gnutls_ssl3_finished( state, state->security_parameters.entity, 0);
+ data =
+ _gnutls_ssl3_finished(state,
+ state->security_parameters.
+ entity, 0);
data_size = 36;
- } else { /* TLS 1.0 */
- data = _gnutls_finished( state, state->security_parameters.entity, 0);
- data_size=12;
+ } else { /* TLS 1.0 */
+ data =
+ _gnutls_finished(state,
+ state->security_parameters.entity, 0);
+ data_size = 12;
}
- ret = _gnutls_send_handshake(cd, state, data, data_size, GNUTLS_FINISHED);
+ ret =
+ _gnutls_send_handshake(cd, state, data, data_size,
+ GNUTLS_FINISHED);
gnutls_free(data);
return ret;
@@ -172,18 +352,20 @@ int _gnutls_recv_finished(int cd, GNUTLS_STATE state)
ret = 0;
- ret = _gnutls_recv_handshake(cd, state, &vrfy, &vrfysize, GNUTLS_FINISHED);
+ ret =
+ _gnutls_recv_handshake(cd, state, &vrfy, &vrfysize,
+ GNUTLS_FINISHED);
if (ret < 0) {
ERR("recv finished int", ret);
return ret;
}
if (_gnutls_version_ssl3(state->connection_state.version) == 0) {
- data_size=36;
+ data_size = 36;
} else {
- data_size=12;
+ data_size = 12;
}
-
+
if (vrfysize != data_size) {
gnutls_assert();
return GNUTLS_E_ERROR_IN_FINISHED_PACKET;
@@ -191,9 +373,18 @@ int _gnutls_recv_finished(int cd, GNUTLS_STATE state)
if (_gnutls_version_ssl3(state->connection_state.version) == 0) {
/* skip the bytes from the last message */
- data = _gnutls_ssl3_finished( state, (state->security_parameters.entity+1)%2, vrfysize + HANDSHAKE_HEADERS_SIZE);
- } else { /* TLS 1.0 */
- data = _gnutls_finished( state, (state->security_parameters.entity+1)%2, vrfysize + HANDSHAKE_HEADERS_SIZE);
+ data =
+ _gnutls_ssl3_finished(state,
+ (state->security_parameters.
+ entity + 1) % 2,
+ vrfysize +
+ HANDSHAKE_HEADERS_SIZE);
+ } else { /* TLS 1.0 */
+ data =
+ _gnutls_finished(state,
+ (state->security_parameters.entity +
+ 1) % 2,
+ vrfysize + HANDSHAKE_HEADERS_SIZE);
}
if (memcmp(vrfy, data, data_size) != 0) {
@@ -203,13 +394,15 @@ int _gnutls_recv_finished(int cd, GNUTLS_STATE state)
gnutls_free(data);
gnutls_free(vrfy);
-
+
return ret;
}
+
/* This selects the best supported ciphersuite from the ones provided */
-static int SelectSuite(GNUTLS_STATE state, opaque ret[2], char *data, int datalen)
+static int SelectSuite(GNUTLS_STATE state, opaque ret[2], char *data,
+ int datalen)
{
int x, i, j;
GNUTLS_CipherSuite *ciphers;
@@ -217,22 +410,31 @@ static int SelectSuite(GNUTLS_STATE state, opaque ret[2], char *data, int datale
x = _gnutls_supported_ciphersuites(state, &ciphers);
#ifdef HARD_DEBUG
fprintf(stderr, "Requested cipher suites: \n");
- for (j=0;j<datalen;j+=2) fprintf(stderr, "\t%s\n", _gnutls_cipher_suite_get_name( *((GNUTLS_CipherSuite*)&data[j]) ));
+ for (j = 0; j < datalen; j += 2)
+ fprintf(stderr, "\t%s\n",
+ _gnutls_cipher_suite_get_name(*
+ ((GNUTLS_CipherSuite
+ *) & data[j])));
fprintf(stderr, "Supported cipher suites: \n");
- for (j=0;j<x;j++) fprintf(stderr, "\t%s\n", _gnutls_cipher_suite_get_name(ciphers[j]));
+ for (j = 0; j < x; j++)
+ fprintf(stderr, "\t%s\n",
+ _gnutls_cipher_suite_get_name(ciphers[j]));
#endif
memset(ret, '\0', sizeof(GNUTLS_CipherSuite));
for (j = 0; j < datalen; j += 2) {
for (i = 0; i < x; i++) {
- if (memcmp(&ciphers[i].CipherSuite, &data[j], 2) == 0) {
+ if (memcmp(&ciphers[i].CipherSuite, &data[j], 2) ==
+ 0) {
#ifdef HARD_DEBUG
fprintf(stderr, "Selected cipher suite: ");
- fprintf(stderr, "%s\n", _gnutls_cipher_suite_get_name( *((GNUTLS_CipherSuite*)&data[j]) ));
+ fprintf(stderr, "%s\n",
+ _gnutls_cipher_suite_get_name(*
+ ((GNUTLS_CipherSuite *) & data[j])));
#endif
memmove(ret, &ciphers[i].CipherSuite, 2);
gnutls_free(ciphers);
-
+
return 0;
}
}
@@ -245,8 +447,10 @@ static int SelectSuite(GNUTLS_STATE state, opaque ret[2], char *data, int datale
}
+
/* This selects the best supported compression method from the ones provided */
-static int SelectCompMethod(GNUTLS_STATE state, CompressionMethod * ret, opaque *data, int datalen)
+static int SelectCompMethod(GNUTLS_STATE state, CompressionMethod * ret,
+ opaque * data, int datalen)
{
int x, i, j;
uint8 *ciphers;
@@ -256,7 +460,7 @@ static int SelectCompMethod(GNUTLS_STATE state, CompressionMethod * ret, opaque
for (j = 0; j < datalen; j++) {
for (i = 0; i < x; i++) {
- if ( ciphers[i] == data[j]) {
+ if (ciphers[i] == data[j]) {
*ret = ciphers[i];
gnutls_free(ciphers);
return 0;
@@ -302,16 +506,18 @@ int _gnutls_send_handshake(int cd, GNUTLS_STATE state, void *i_data,
memmove(&data[pos], i_data, i_datasize - 4);
#ifdef HANDSHAKE_DEBUG
- fprintf(stderr, "Handshake: %s was send [%ld bytes]\n", _gnutls_handshake2str(type), i_datasize);
+ fprintf(stderr, "Handshake: %s was send [%ld bytes]\n",
+ _gnutls_handshake2str(type), i_datasize);
#endif
/* Here we keep the handshake messages in order to hash them later!
*/
- if (type!=GNUTLS_HELLO_REQUEST)
- gnutls_insertHashDataBuffer( state, data, i_datasize);
+ if (type != GNUTLS_HELLO_REQUEST)
+ gnutls_insertHashDataBuffer(state, data, i_datasize);
ret =
- _gnutls_Send_int(cd, state, GNUTLS_HANDSHAKE, data, i_datasize);
+ _gnutls_Send_int(cd, state, GNUTLS_HANDSHAKE, data,
+ i_datasize);
gnutls_free(data);
return ret;
@@ -323,70 +529,111 @@ int _gnutls_send_handshake(int cd, GNUTLS_STATE state, void *i_data,
* Eg. for the SERVER_HELLO message (if it is expected), it will be
* send to _gnutls_recv_hello().
*/
-int _gnutls_recv_handshake(int cd, GNUTLS_STATE state, uint8 **data,
- int* datalen, HandshakeType type)
+#define SSL2_HEADERS 1
+int _gnutls_recv_handshake(int cd, GNUTLS_STATE state, uint8 ** data,
+ int *datalen, HandshakeType type)
{
int ret;
- uint32 length32 = 0, sum=0;
- uint8 *dataptr;
+ uint32 length32 = 0, sum = 0;
+ uint8 *dataptr=NULL; /* for realloc */
uint24 num;
+ int handshake_headers = HANDSHAKE_HEADERS_SIZE;
+ int recv_type;
-
- if (type==GNUTLS_CERTIFICATE) {
- /* If the ciphersuite does not support certificate just quit */
+ if (type == GNUTLS_CERTIFICATE) {
+ /* If the ciphersuite does not support certificate just quit */
if (state->security_parameters.entity == GNUTLS_CLIENT) {
- if ( _gnutls_kx_server_certificate(
- _gnutls_cipher_suite_get_kx_algo(state->gnutls_internals.current_cipher_suite)) ==0 )
- return 0;
- } else { /* server */
- if (_gnutls_kx_client_certificate( _gnutls_cipher_suite_get_kx_algo(state->gnutls_internals.current_cipher_suite)==0))
- return 0;
+ if (_gnutls_kx_server_certificate( _gnutls_cipher_suite_get_kx_algo( state->gnutls_internals.current_cipher_suite) ) == 0)
+ return 0;
+ } else { /* server */
+ if (_gnutls_kx_client_certificate( _gnutls_cipher_suite_get_kx_algo( state->gnutls_internals.current_cipher_suite) ) == 0)
+ return 0;
}
}
dataptr = gnutls_malloc(HANDSHAKE_HEADERS_SIZE);
- ret = _gnutls_Recv_int(cd, state, GNUTLS_HANDSHAKE, dataptr, HANDSHAKE_HEADERS_SIZE);
+ ret =
+ _gnutls_Recv_int(cd, state, GNUTLS_HANDSHAKE, dataptr, SSL2_HEADERS);
if (ret < 0) {
gnutls_free(dataptr);
return ret;
}
- if (ret!=HANDSHAKE_HEADERS_SIZE) {
+ if (ret!=SSL2_HEADERS) {
gnutls_assert();
gnutls_free(dataptr);
return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
}
- if (dataptr[0]!=type) {
- gnutls_assert();
- gnutls_free(dataptr);
- return GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET;
- }
+ if ( state->gnutls_internals.v2_hello == 0 || type != GNUTLS_CLIENT_HELLO) {
+
+ ret =
+ _gnutls_Recv_int(cd, state, GNUTLS_HANDSHAKE, &dataptr[SSL2_HEADERS],
+ HANDSHAKE_HEADERS_SIZE-SSL2_HEADERS);
+ if (ret < 0) {
+ gnutls_free(dataptr);
+ return ret;
+ }
+ if (ret != HANDSHAKE_HEADERS_SIZE - SSL2_HEADERS) {
+ gnutls_assert();
+ gnutls_free(dataptr);
+ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ }
+
+ recv_type = dataptr[0];
+
+ if (recv_type != type) {
+ gnutls_assert();
+ gnutls_free(dataptr);
+ return GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET;
+ }
- num.pint[0] = dataptr[1];
- num.pint[1] = dataptr[2];
- num.pint[2] = dataptr[3];
- length32 = uint24touint32(num);
+ num.pint[0] = dataptr[1];
+ num.pint[1] = dataptr[2];
+ num.pint[2] = dataptr[3];
+ length32 = uint24touint32(num);
#ifndef WORDS_BIGENDIAN
- length32 = byteswap32(length32);
+ length32 = byteswap32(length32);
#endif
#ifdef HANDSHAKE_DEBUG
- fprintf(stderr, "Handshake: %s was received [%ld bytes]\n", _gnutls_handshake2str(dataptr[0]), length32+HANDSHAKE_HEADERS_SIZE);
+ fprintf(stderr, "Handshake: %s was received [%ld bytes]\n",
+ _gnutls_handshake2str(dataptr[0]),
+ length32 + HANDSHAKE_HEADERS_SIZE);
#endif
- dataptr = gnutls_realloc( dataptr, length32+HANDSHAKE_HEADERS_SIZE);
- if (length32>0 && data!=NULL)
- *data = gnutls_malloc( length32);
- if (datalen!=NULL) *datalen = length32;
+ } else { /* v2 hello */
+ length32 = state->gnutls_internals.v2_hello - 1; /* we've read the first byte */
+
+ handshake_headers = 0; /* no headers in v2 */
- sum=HANDSHAKE_HEADERS_SIZE;
+#ifdef HANDSHAKE_DEBUG
+ fprintf(stderr, "Handshake: %s(v2) was received [%ld bytes]\n",
+ _gnutls_handshake2str(dataptr[0]),
+ length32 + handshake_headers);
+#endif
+ recv_type = dataptr[0];
+ if (dataptr[0] != GNUTLS_CLIENT_HELLO) /* it should be one or nothing */
+ return GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET;
+ }
+
+ dataptr =
+ gnutls_realloc(dataptr, length32 + handshake_headers);
+ if (length32 > 0 && data != NULL)
+ *data = gnutls_malloc(length32);
+
+ if (datalen != NULL)
+ *datalen = length32;
+
+ sum = handshake_headers;
do {
- ret = _gnutls_Recv_int(cd, state, GNUTLS_HANDSHAKE, &dataptr[sum], length32);
+ ret =
+ _gnutls_Recv_int(cd, state, GNUTLS_HANDSHAKE,
+ &dataptr[sum], length32);
sum += ret;
- } while( ( (sum-HANDSHAKE_HEADERS_SIZE) < length32) && (ret > 0) );
-
+ } while (((sum - handshake_headers) < length32) && (ret > 0));
+
if (ret < 0) {
gnutls_assert();
gnutls_free(dataptr);
@@ -394,21 +641,26 @@ int _gnutls_recv_handshake(int cd, GNUTLS_STATE state, uint8 **data,
}
ret = GNUTLS_E_UNKNOWN_ERROR;
- if (length32 > 0 && data!=NULL)
- memmove( *data, &dataptr[HANDSHAKE_HEADERS_SIZE], length32);
+ if (length32 > 0 && data != NULL)
+ memmove(*data, &dataptr[handshake_headers], length32);
/* here we buffer the handshake messages - needed at Finished message */
- gnutls_insertHashDataBuffer( state, dataptr, length32+HANDSHAKE_HEADERS_SIZE);
+ gnutls_insertHashDataBuffer(state, dataptr, length32 + handshake_headers);
- switch (dataptr[0]) {
+ switch (recv_type) {
case GNUTLS_CLIENT_HELLO:
case GNUTLS_SERVER_HELLO:
- ret = _gnutls_recv_hello(cd, state, &dataptr[HANDSHAKE_HEADERS_SIZE],
- length32);
+ ret =
+ _gnutls_recv_hello(cd, state,
+ &dataptr[handshake_headers],
+ length32);
break;
case GNUTLS_CERTIFICATE:
- ret = _gnutls_recv_certificate(cd, state, &dataptr[HANDSHAKE_HEADERS_SIZE],
- length32);
+ ret =
+ _gnutls_recv_certificate(cd, state,
+ &dataptr
+ [HANDSHAKE_HEADERS_SIZE],
+ length32);
break;
case GNUTLS_SERVER_HELLO_DONE:
ret = 0;
@@ -426,9 +678,9 @@ int _gnutls_recv_handshake(int cd, GNUTLS_STATE state, uint8 **data,
#ifdef HARD_DEBUG
fprintf(stderr, "Requested Client Certificate!\n");
#endif
- /* FIXME: just ignore that message for the time being
- * we have to parse it and the store the needed information
- */
+ /* FIXME: just ignore that message for the time being
+ * we have to parse it and the store the needed information
+ */
state->gnutls_internals.certificate_requested = 1;
ret = length32;
break;
@@ -450,8 +702,9 @@ int _gnutls_send_client_certificate(int cd, GNUTLS_STATE state)
{
char data[1];
int ret;
-
- if (state->gnutls_internals.certificate_requested==0) return 0;
+
+ if (state->gnutls_internals.certificate_requested == 0)
+ return 0;
/* we do not have that functionality yet */
state->gnutls_internals.certificate_verify_needed = 0;
@@ -464,11 +717,177 @@ int _gnutls_send_client_certificate(int cd, GNUTLS_STATE state)
*/
data[0] = 0;
ret = _gnutls_send_handshake(cd, state, &data, 1,
- GNUTLS_CERTIFICATE);
-
+ GNUTLS_CERTIFICATE);
+
return ret;
}
+static int _gnutls_read_server_hello( GNUTLS_STATE state, char *data, int datalen)
+{
+ uint8 session_id_len = 0, z;
+ int pos = 0;
+ GNUTLS_CipherSuite cipher_suite, *cipher_suites;
+ uint8 compression_method, *compression_methods;
+ int i, ret = 0;
+ uint16 x;
+ GNUTLS_Version version;
+ int len = datalen;
+ int err;
+
+ if (datalen < 38) {
+ gnutls_assert();
+ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ }
+#ifdef DEBUG
+ fprintf(stderr, "Server's version: %d.%d\n", data[pos],
+ data[pos + 1]);
+#endif
+ DECR_LEN(len, 2);
+ version = _gnutls_version_get(data[pos], data[pos + 1]);
+ if (_gnutls_version_is_supported(state, version) == 0) {
+ gnutls_assert();
+ return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
+ } else {
+ gnutls_set_current_version(state, version);
+ }
+ pos += 2;
+
+ DECR_LEN(len, 32);
+ memmove(state->security_parameters.server_random,
+ &data[pos], 32);
+ pos += 32;
+
+ DECR_LEN(len, 1);
+ memmove(&session_id_len, &data[pos++], 1);
+
+ if (len < session_id_len) {
+ gnutls_assert();
+ return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
+ }
+
+ DECR_LEN(len, session_id_len);
+
+#ifdef HARD_DEBUG
+ fprintf(stderr, "SessionID length: %d\n", session_id_len);
+ fprintf(stderr, "SessionID: %s\n",
+ _gnutls_bin2hex(&data[pos], session_id_len));
+#endif
+ if ((state->gnutls_internals.resumed_security_parameters.
+ session_id_size > 0)
+ && memcmp(&data[pos],
+ state->gnutls_internals.
+ resumed_security_parameters.session_id,
+ session_id_len) == 0) {
+ /* resume session */
+ memcpy(state->gnutls_internals.
+ resumed_security_parameters.server_random,
+ state->security_parameters.server_random,
+ 32);
+ memcpy(state->gnutls_internals.
+ resumed_security_parameters.client_random,
+ state->security_parameters.client_random,
+ 32);
+ state->gnutls_internals.resumed = RESUME_TRUE; /* we are resuming */
+ return 0;
+ } else {
+ /* keep the session id */
+ state->gnutls_internals.resumed = RESUME_FALSE; /* we are not resuming */
+ state->security_parameters.session_id_size =
+ session_id_len;
+ memcpy(state->security_parameters.session_id,
+ &data[pos], session_id_len);
+ }
+ pos += session_id_len;
+ DECR_LEN(len, 2);
+ memmove(&cipher_suite.CipherSuite, &data[pos], 2);
+ pos += 2;
+
+ z = 1;
+ x = _gnutls_supported_ciphersuites(state, &cipher_suites);
+ for (i = 0; i < x; i++) {
+ if (memcmp
+ (&cipher_suites[i], cipher_suite.CipherSuite,
+ 2) == 0) {
+ z = 0;
+ }
+ }
+ if (z != 0) {
+ gnutls_assert();
+ return GNUTLS_E_UNKNOWN_CIPHER_TYPE;
+ }
+
+ memmove(state->gnutls_internals.
+ current_cipher_suite.CipherSuite,
+ cipher_suite.CipherSuite, 2);
+
+#ifdef HARD_DEBUG
+ fprintf(stderr, "Selected cipher suite: ");
+ fprintf(stderr, "%s\n",
+ _gnutls_cipher_suite_get_name(state->
+ gnutls_internals.
+ current_cipher_suite));
+#endif
+
+ /* check if the credentials (username, public key etc. are ok - actually check if they exist)
+ */
+ if (_gnutls_get_kx_cred
+ (state->gnutls_key,
+ _gnutls_cipher_suite_get_kx_algo(state->
+ gnutls_internals.
+ current_cipher_suite),
+ &err) == NULL && err != 0) {
+ gnutls_assert();
+ return GNUTLS_E_INSUFICIENT_CRED;
+ }
+
+ /* set the MOD_AUTH_STRUCT to the appropriate struct
+ * according to the KX algorithm. This is needed since all the
+ * handshake functions are read from there;
+ */
+ state->gnutls_internals.auth_struct =
+ _gnutls_kx_auth_struct(_gnutls_cipher_suite_get_kx_algo
+ (cipher_suite));
+ if (state->gnutls_internals.auth_struct == NULL) {
+#ifdef DEBUG
+ fprintf(stderr,
+ "Cannot find the appropriate handler for the KX algorithm\n");
+#endif
+ gnutls_assert();
+ return GNUTLS_E_UNKNOWN_CIPHER_TYPE;
+ }
+
+
+ /* move to compression */
+ z = 1;
+ DECR_LEN(len, 1);
+ memmove(&compression_method, &data[pos++], 1);
+
+ z = _gnutls_supported_compression_methods
+ (state, &compression_methods);
+ for (i = 0; i < z; i++) {
+ if (memcmp
+ (&compression_methods[i], &compression_method,
+ 1) == 0) {
+ z = 0;
+ }
+ }
+
+ if (z != 0)
+ return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM;
+ memmove(&state->gnutls_internals.compression_method,
+ &compression_method, 1);
+
+ gnutls_free(cipher_suites);
+ gnutls_free(compression_methods);
+
+ ret = _gnutls_parse_extensions(state, &data[pos], len); /* len is the rest of the parsed length */
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ return ret;
+}
int _gnutls_send_hello(int cd, GNUTLS_STATE state, opaque * SessionID,
uint8 SessionIDLen)
@@ -498,8 +917,12 @@ int _gnutls_send_hello(int cd, GNUTLS_STATE state, opaque * SessionID,
*/
data = gnutls_malloc(datalen);
- data[pos++] = _gnutls_version_get_major(state->connection_state.version);
- data[pos++] = _gnutls_version_get_minor(state->connection_state.version);
+ data[pos++] =
+ _gnutls_version_get_major(state->connection_state.
+ version);
+ data[pos++] =
+ _gnutls_version_get_minor(state->connection_state.
+ version);
#ifdef WORDS_BIGENDIAN
cur_time = time(NULL);
#else
@@ -512,10 +935,11 @@ int _gnutls_send_hello(int cd, GNUTLS_STATE state, opaque * SessionID,
memmove(&state->security_parameters.client_random[4], rand,
28);
_gnutls_free_rand(rand);
-
+
state->security_parameters.timestamp = time(0);
- memmove(&data[pos], state->security_parameters.client_random, 32);
+ memmove(&data[pos],
+ state->security_parameters.client_random, 32);
pos += 32;
memmove(&data[pos++], &session_id_len, 1);
@@ -525,8 +949,9 @@ int _gnutls_send_hello(int cd, GNUTLS_STATE state, opaque * SessionID,
}
pos += session_id_len;
- x = _gnutls_supported_ciphersuites_sorted(state, &cipher_suites);
- x *= sizeof(uint16); /* in order to get bytes */
+ x = _gnutls_supported_ciphersuites_sorted(state,
+ &cipher_suites);
+ x *= sizeof(uint16); /* in order to get bytes */
#ifdef WORDS_BIGENDIAN
memmove(&data[pos], &x, sizeof(uint16));
#else
@@ -539,7 +964,7 @@ int _gnutls_send_hello(int cd, GNUTLS_STATE state, opaque * SessionID,
datalen += x;
data = gnutls_realloc(data, datalen);
- for (i = 0; i < x/2; i++) {
+ for (i = 0; i < x / 2; i++) {
memmove(&data[pos], &cipher_suites[i].CipherSuite,
2);
pos += 2;
@@ -549,22 +974,22 @@ int _gnutls_send_hello(int cd, GNUTLS_STATE state, opaque * SessionID,
z = _gnutls_supported_compression_methods
(state, &compression_methods);
- memmove(&data[pos++], &z, 1); /* put the number of compression methods */
+ memmove(&data[pos++], &z, 1); /* put the number of compression methods */
- datalen += z;
+ datalen += z;
data = gnutls_realloc(data, datalen);
-
+
for (i = 0; i < z; i++) {
memmove(&data[pos++], &compression_methods[i], 1);
}
gnutls_free(compression_methods);
- extdatalen = _gnutls_gen_extensions( state, &extdata);
+ extdatalen = _gnutls_gen_extensions(state, &extdata);
if (extdatalen > 0) {
- datalen+=extdatalen;
+ datalen += extdatalen;
data = gnutls_realloc(data, datalen);
- memcpy( &data[pos], extdata, extdatalen);
+ memcpy(&data[pos], extdata, extdatalen);
gnutls_free(extdata);
}
@@ -578,10 +1003,15 @@ int _gnutls_send_hello(int cd, GNUTLS_STATE state, opaque * SessionID,
datalen = 2 + session_id_len + 1 + 32;
data = gnutls_malloc(datalen);
- data[pos++] = _gnutls_version_get_major(state->connection_state.version);
- data[pos++] = _gnutls_version_get_minor(state->connection_state.version);
+ data[pos++] =
+ _gnutls_version_get_major(state->connection_state.
+ version);
+ data[pos++] =
+ _gnutls_version_get_minor(state->connection_state.
+ version);
- memmove( &data[pos], state->security_parameters.server_random, 32);
+ memmove(&data[pos],
+ state->security_parameters.server_random, 32);
pos += 32;
memmove(&data[pos++], &session_id_len, sizeof(uint8));
@@ -601,12 +1031,12 @@ int _gnutls_send_hello(int cd, GNUTLS_STATE state, opaque * SessionID,
data = gnutls_realloc(data, datalen);
memmove(&data[pos++],
&state->gnutls_internals.compression_method, 1);
-
- extdatalen = _gnutls_gen_extensions( state, &extdata);
+
+ extdatalen = _gnutls_gen_extensions(state, &extdata);
if (extdatalen > 0) {
- datalen+=extdatalen;
+ datalen += extdatalen;
data = gnutls_realloc(data, datalen);
- memcpy( &data[pos], extdata, extdatalen);
+ memcpy(&data[pos], extdata, extdatalen);
gnutls_free(extdata);
}
@@ -620,310 +1050,69 @@ int _gnutls_send_hello(int cd, GNUTLS_STATE state, opaque * SessionID,
return ret;
}
-#define DECR_LEN(len, x) len-=x; if (len<0) {gnutls_assert(); return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;}
-
/* RECEIVE A HELLO MESSAGE. This should be called from gnutls_recv_handshake_int only if a
* hello message is expected. It uses the gnutls_internals.current_cipher_suite
* and gnutls_internals.compression_method.
*/
int _gnutls_recv_hello(int cd, GNUTLS_STATE state, char *data, int datalen)
{
- uint8 session_id_len = 0, z;
- int pos = 0;
- GNUTLS_CipherSuite cipher_suite, *cipher_suites;
- uint8 compression_method, *compression_methods;
- int i, ret=0;
- uint16 x, sizeOfSuites;
- GNUTLS_Version version;
- time_t cur_time;
- char* rand;
- int len = datalen;
- int err;
-
- if (state->security_parameters.entity == GNUTLS_CLIENT) {
- if (datalen < 38) {
- gnutls_assert();
- return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
- }
-
-#ifdef DEBUG
- fprintf(stderr, "Server's version: %d.%d\n", data[pos], data[pos+1]);
-#endif
- version = _gnutls_version_get( data[pos], data[pos+1]);
- if ( _gnutls_version_is_supported( state, version) == 0) {
- gnutls_assert();
- return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
- } else {
- gnutls_set_current_version(state, version);
- }
- pos+=2;
- DECR_LEN(len, 2);
-
- memmove(state->security_parameters.server_random,
- &data[pos], 32);
- pos += 32;
- DECR_LEN(len, 32);
-
- memmove(&session_id_len, &data[pos++], 1);
- DECR_LEN(len, 1);
-
- if (len < session_id_len) {
- gnutls_assert();
- return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
- }
-#ifdef HARD_DEBUG
- fprintf(stderr, "SessionID length: %d\n", session_id_len);
- fprintf(stderr, "SessionID: %s\n",
- _gnutls_bin2hex(&data[pos], session_id_len));
-#endif
- if ( (state->gnutls_internals.resumed_security_parameters.session_id_size > 0)
- && memcmp(&data[pos], state->gnutls_internals.resumed_security_parameters.session_id, session_id_len)==0) {
- /* resume session */
- memcpy( state->gnutls_internals.resumed_security_parameters.server_random, state->security_parameters.server_random, 32);
- memcpy( state->gnutls_internals.resumed_security_parameters.client_random, state->security_parameters.client_random, 32);
-
- state->gnutls_internals.resumed=RESUME_TRUE; /* we are resuming */
- return 0;
- } else {
- /* keep the session id */
- state->gnutls_internals.resumed=RESUME_FALSE; /* we are not resuming */
- state->security_parameters.session_id_size = session_id_len;
- memcpy( state->security_parameters.session_id, &data[pos], session_id_len);
-
- }
-
- pos += session_id_len;
- DECR_LEN(len, session_id_len);
-
- memmove(&cipher_suite.CipherSuite, &data[pos], 2);
- pos += 2;
- DECR_LEN(len, 2);
-
- z = 1;
- x = _gnutls_supported_ciphersuites(state, &cipher_suites);
- for (i = 0; i < x; i++) {
- if (memcmp (&cipher_suites[i], cipher_suite.CipherSuite, 2) == 0) {
- z = 0;
- }
- }
- if (z != 0) {
- gnutls_assert();
- return GNUTLS_E_UNKNOWN_CIPHER_TYPE;
- }
-
- memmove(state->gnutls_internals.
- current_cipher_suite.CipherSuite,
- cipher_suite.CipherSuite, 2);
-#ifdef HARD_DEBUG
- fprintf(stderr, "Selected cipher suite: ");
- fprintf(stderr, "%s\n", _gnutls_cipher_suite_get_name(state->gnutls_internals.current_cipher_suite ) );
-#endif
-
- /* check if the credentials (username, public key etc. are ok - actually check if they exist)
- */
- if ( _gnutls_get_kx_cred( state->gnutls_key, _gnutls_cipher_suite_get_kx_algo( state->gnutls_internals.current_cipher_suite), &err) == NULL && err!=0) {
- gnutls_assert();
- return GNUTLS_E_INSUFICIENT_CRED;
- }
+int ret;
- /* set the MOD_AUTH_STRUCT to the appropriate struct
- * according to the KX algorithm. This is needed since all the
- * handshake functions are read from there;
- */
- state->gnutls_internals.auth_struct = _gnutls_kx_auth_struct( _gnutls_cipher_suite_get_kx_algo( cipher_suite));
- if (state->gnutls_internals.auth_struct==NULL) {
-#ifdef DEBUG
- fprintf(stderr, "Cannot find the appropriate handler for the KX algorithm\n");
-#endif
- gnutls_assert();
- return GNUTLS_E_UNKNOWN_CIPHER_TYPE;
- }
-
-
- /* move to compression */
- z = 1;
- memmove(&compression_method, &data[pos++], 1);
- DECR_LEN(len, 1);
-
- z =
- _gnutls_supported_compression_methods
- (state, &compression_methods);
- for (i = 0; i < z; i++) {
- if (memcmp
- (&compression_methods[i], &compression_method,
- 1) == 0) {
- z = 0;
-
- }
- }
- if (z != 0)
- return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM;
- memmove(&state->gnutls_internals.compression_method,
- &compression_method, 1);
-
- gnutls_free(cipher_suites);
- gnutls_free(compression_methods);
-
- ret = _gnutls_parse_extensions( state, &data[pos], len); /* len is the rest of the parsed length */
+ if (state->security_parameters.entity == GNUTLS_CLIENT) {
+ ret = _gnutls_read_server_hello(state, data, datalen);
if (ret < 0) {
+ _gnutls_send_alert( cd, state, GNUTLS_FATAL, GNUTLS_HANDSHAKE_FAILURE); /* send handshake failure */
gnutls_assert();
return ret;
}
-
} else { /* Server side reading a client hello */
- if (datalen < 35) {
- gnutls_assert();
- return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
- }
-
-#ifdef DEBUG
- fprintf(stderr, "Client's version: %d.%d\n", data[pos], data[pos+1]);
-#endif
- version = _gnutls_version_get( data[pos], data[pos+1]);
- if ( _gnutls_version_is_supported( state, version) == 0) {
- gnutls_assert();
- return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
- } else {
- gnutls_set_current_version(state, version);
- }
- pos+=2;
- DECR_LEN(len, 2);
-
- memmove(state->security_parameters.client_random,
- &data[pos], 32);
- pos+=32;
- DECR_LEN(len, 32);
-
- /* generate server random value */
-#ifdef WORDS_BIGENDIAN
- cur_time = time(NULL);
-#else
- cur_time = byteswap32(time(NULL));
-#endif
- memmove(state->security_parameters.server_random,
- &cur_time, 4);
- rand = _gnutls_get_random(28, GNUTLS_STRONG_RANDOM);
- memmove(&state->security_parameters.server_random[4], rand,
- 28);
- _gnutls_free_rand(rand);
- state->security_parameters.timestamp = time(NULL);
- memmove(&session_id_len, &data[pos++], 1);
- DECR_LEN(len, 1);
-
- /* RESUME SESSION */
- if (session_id_len > 32) return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
-
- ret = _gnutls_server_restore_session( state, &data[pos], session_id_len);
- pos += session_id_len;
- DECR_LEN(len, session_id_len);
-
- if (ret==0) { /* resumed! */
- /* get the new random values */
- memcpy( state->gnutls_internals.resumed_security_parameters.server_random, state->security_parameters.server_random, 32);
- memcpy( state->gnutls_internals.resumed_security_parameters.client_random, state->security_parameters.client_random, 32);
-
- state->gnutls_internals.resumed = RESUME_TRUE;
- return 0;
- } else {
- _gnutls_generate_session_id(state->security_parameters.session_id, &state->security_parameters.session_id_size);
- state->gnutls_internals.resumed = RESUME_FALSE;
- }
-
- /* Select a ciphersuite */
- memmove(&sizeOfSuites, &data[pos], 2);
- pos += 2;
- DECR_LEN(len, 2);
-#ifndef WORDS_BIGENDIAN
- sizeOfSuites = byteswap16(sizeOfSuites);
-#endif
- ret = SelectSuite(state, state->gnutls_internals.
- current_cipher_suite.CipherSuite, &data[pos],
- sizeOfSuites);
-
- if (ret<0) return ret;
-
-
- /* check if the credentials (username, public key etc. are ok)
- */
- if ( _gnutls_get_kx_cred( state->gnutls_key, _gnutls_cipher_suite_get_kx_algo( state->gnutls_internals.current_cipher_suite), &err) == NULL && err!=0) {
- gnutls_assert();
- return GNUTLS_E_INSUFICIENT_CRED;
- }
-
- /* set the MOD_AUTH_STRUCT to the appropriate struct
- * according to the KX algorithm. This is needed since all the
- * handshake functions are read from there;
- */
- state->gnutls_internals.auth_struct = _gnutls_kx_auth_struct( _gnutls_cipher_suite_get_kx_algo( state->gnutls_internals.current_cipher_suite));
- if (state->gnutls_internals.auth_struct==NULL) {
-#ifdef DEBUG
- fprintf(stderr, "Cannot find the appropriate handler for the KX algorithm\n");
-#endif
- gnutls_assert();
- return GNUTLS_E_UNKNOWN_CIPHER_TYPE;
- }
-
- pos += sizeOfSuites;
- DECR_LEN(len, sizeOfSuites);
- memmove(&z, &data[pos++], 1); /* z is the number of compression methods */
- DECR_LEN(len, 1);
- ret = SelectCompMethod(state, &state->
- gnutls_internals.compression_method,
- &data[pos], z);
- pos+=z;
- DECR_LEN(len, z);
-
- if (ret < 0) {
- gnutls_assert();
- return ret;
- }
-
- ret = _gnutls_parse_extensions( state, &data[pos], len); /* len is the rest of the parsed length */
+ ret = _gnutls_read_client_hello(state, data, datalen);
if (ret < 0) {
+ _gnutls_send_alert( cd, state, GNUTLS_FATAL, GNUTLS_HANDSHAKE_FAILURE); /* send handshake failure */
gnutls_assert();
return ret;
}
-
}
return ret;
}
-int _gnutls_recv_certificate(int cd, GNUTLS_STATE state, char *data, int datalen)
+int _gnutls_recv_certificate(int cd, GNUTLS_STATE state, char *data,
+ int datalen)
{
int pos = 0;
- char* certificate_list;
- int ret=0;
+ char *certificate_list;
+ int ret = 0;
uint32 sizeOfCert;
uint24 num;
-
+
if (state->security_parameters.entity == GNUTLS_CLIENT) {
if (datalen < 2) {
gnutls_assert();
return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
}
- num.pint[0] = data[pos];
- num.pint[1] = data[pos+1];
- num.pint[2] = data[pos+2];
+ num.pint[0] = data[pos];
+ num.pint[1] = data[pos + 1];
+ num.pint[2] = data[pos + 2];
sizeOfCert = uint24touint32(num);
-
- pos+=3;
+
+ pos += 3;
#ifndef WORDS_BIGENDIAN
- sizeOfCert=byteswap32(sizeOfCert);
+ sizeOfCert = byteswap32(sizeOfCert);
#endif
if (sizeOfCert > MAX24) {
gnutls_assert();
return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
}
certificate_list = gnutls_malloc(sizeOfCert);
-
- memmove( certificate_list, &data[pos], sizeOfCert);
-
+
+ memmove(certificate_list, &data[pos], sizeOfCert);
+
/* Verify certificates !!! */
-
- gnutls_free(certificate_list); /* oooops! */
+
+ gnutls_free(certificate_list); /* oooops! */
} else { /* Server side reading a client certificate */
/* actually this is not complete */
@@ -942,13 +1131,15 @@ int _gnutls_recv_certificate(int cd, GNUTLS_STATE state, char *data, int datalen
/* This is the main function in the handshake protocol. This does actually
* everything. (exchange hello messages etc).
*/
-int gnutls_handshake(int cd, GNUTLS_STATE state) {
+int gnutls_handshake(int cd, GNUTLS_STATE state)
+{
int ret;
-
- ret = gnutls_handshake_begin( cd, state);
+
+ ret = gnutls_handshake_begin(cd, state);
/* FIXME: check certificate */
- if (ret==0) ret = gnutls_handshake_finish( cd, state);
-
+ if (ret == 0)
+ ret = gnutls_handshake_finish(cd, state);
+
return ret;
}
@@ -962,32 +1153,48 @@ int gnutls_handshake_begin(int cd, GNUTLS_STATE state)
if (state->security_parameters.entity == GNUTLS_CLIENT) {
#ifdef HARD_DEBUG
- if (state->gnutls_internals.resumed_security_parameters.session_id_size>0)
- fprintf(stderr, "Ask to resume: %s\n", _gnutls_bin2hex(state->gnutls_internals.resumed_security_parameters.session_id, state->gnutls_internals.resumed_security_parameters.session_id_size));
+ if (state->gnutls_internals.resumed_security_parameters.
+ session_id_size > 0)
+ fprintf(stderr, "Ask to resume: %s\n",
+ _gnutls_bin2hex(state->gnutls_internals.
+ resumed_security_parameters.
+ session_id,
+ state->gnutls_internals.
+ resumed_security_parameters.
+ session_id_size));
#endif
- ret = _gnutls_send_hello(cd, state, state->gnutls_internals.resumed_security_parameters.session_id, state->gnutls_internals.resumed_security_parameters.session_id_size);
+ ret =
+ _gnutls_send_hello(cd, state,
+ state->gnutls_internals.
+ resumed_security_parameters.
+ session_id,
+ state->gnutls_internals.
+ resumed_security_parameters.
+ session_id_size);
if (ret < 0) {
ERR("send hello", ret);
- gnutls_clearHashDataBuffer( state);
+ gnutls_clearHashDataBuffer(state);
return ret;
}
/* receive the server hello */
ret =
- _gnutls_recv_handshake(cd, state, NULL, NULL, GNUTLS_SERVER_HELLO);
+ _gnutls_recv_handshake(cd, state, NULL, NULL,
+ GNUTLS_SERVER_HELLO);
if (ret < 0) {
ERR("recv hello", ret);
- gnutls_clearHashDataBuffer( state);
+ gnutls_clearHashDataBuffer(state);
return ret;
}
/* RECV CERTIFICATE */
- if (state->gnutls_internals.resumed==RESUME_FALSE) /* if we are not resuming */
- ret =
- _gnutls_recv_handshake(cd, state, NULL, NULL, GNUTLS_CERTIFICATE);
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret =
+ _gnutls_recv_handshake(cd, state, NULL, NULL,
+ GNUTLS_CERTIFICATE);
if (ret < 0) {
ERR("recv server certificate", ret);
- gnutls_clearHashDataBuffer( state);
+ gnutls_clearHashDataBuffer(state);
return ret;
}
return 0;
@@ -998,49 +1205,52 @@ int gnutls_handshake_begin(int cd, GNUTLS_STATE state)
GNUTLS_CLIENT_HELLO);
if (ret < 0) {
ERR("recv hello", ret);
- gnutls_clearHashDataBuffer( state);
+ gnutls_clearHashDataBuffer(state);
return ret;
}
ret =
- _gnutls_send_hello(cd, state, state->security_parameters.session_id,
- state->security_parameters.session_id_size);
+ _gnutls_send_hello(cd, state,
+ state->security_parameters.
+ session_id,
+ state->security_parameters.
+ session_id_size);
if (ret < 0) {
ERR("send hello", ret);
- gnutls_clearHashDataBuffer( state);
+ gnutls_clearHashDataBuffer(state);
return ret;
}
/* FIXME: send our certificate - if required */
/* NOTE: these should not be send if we are resuming */
-
+
/* SEND CERTIFICATE + KEYEXCHANGE + CERTIFICATE_REQUEST */
/* send server key exchange (A) */
- if (state->gnutls_internals.resumed==RESUME_FALSE)
- ret = _gnutls_send_server_kx_message(cd, state);
+ if (state->gnutls_internals.resumed == RESUME_FALSE)
+ ret = _gnutls_send_server_kx_message(cd, state);
if (ret < 0) {
ERR("send server kx", ret);
- gnutls_clearHashDataBuffer( state);
+ gnutls_clearHashDataBuffer(state);
return ret;
}
/* Added for SRP which uses a different handshake */
/* receive the client key exchange message */
- if (state->gnutls_internals.resumed==RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_recv_client_kx_message0(cd, state);
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret = _gnutls_recv_client_kx_message0(cd, state);
if (ret < 0) {
ERR("recv client kx0", ret);
- gnutls_clearHashDataBuffer( state);
+ gnutls_clearHashDataBuffer(state);
return ret;
}
/* send server key exchange (B) */
- if (state->gnutls_internals.resumed==RESUME_FALSE)
- ret = _gnutls_send_server_kx_message2(cd, state);
+ if (state->gnutls_internals.resumed == RESUME_FALSE)
+ ret = _gnutls_send_server_kx_message2(cd, state);
if (ret < 0) {
ERR("send server kx2", ret);
- gnutls_clearHashDataBuffer( state);
+ gnutls_clearHashDataBuffer(state);
return ret;
}
@@ -1050,67 +1260,71 @@ int gnutls_handshake_begin(int cd, GNUTLS_STATE state)
}
/* This function sends the final handshake packets and initializes connection */
-static int _gnutls_send_handshake_final( int cd, GNUTLS_STATE state, int init) {
-int ret=0;
-
- /* Send the CHANGE CIPHER SPEC PACKET */
- ret = _gnutls_send_change_cipher_spec(cd, state);
- if (ret < 0) {
- ERR("send ChangeCipherSpec", ret);
- gnutls_clearHashDataBuffer( state);
- return ret;
- }
+static int _gnutls_send_handshake_final(int cd, GNUTLS_STATE state,
+ int init)
+{
+ int ret = 0;
- /* Initialize the connection state (start encryption) - in case of client */
- if (init == TRUE) {
- ret = _gnutls_connection_state_init(state);
- if (ret<0) {
- gnutls_assert();
- gnutls_clearHashDataBuffer( state);
- return ret;
- }
- }
- /* send the finished message */
+ /* Send the CHANGE CIPHER SPEC PACKET */
+ ret = _gnutls_send_change_cipher_spec(cd, state);
+ if (ret < 0) {
+ ERR("send ChangeCipherSpec", ret);
+ gnutls_clearHashDataBuffer(state);
+ return ret;
+ }
- ret = _gnutls_send_finished(cd, state);
+ /* Initialize the connection state (start encryption) - in case of client */
+ if (init == TRUE) {
+ ret = _gnutls_connection_state_init(state);
if (ret < 0) {
- ERR("send Finished", ret);
- gnutls_clearHashDataBuffer( state);
+ gnutls_assert();
+ gnutls_clearHashDataBuffer(state);
return ret;
}
+ }
+ /* send the finished message */
+
+ ret = _gnutls_send_finished(cd, state);
+ if (ret < 0) {
+ ERR("send Finished", ret);
+ gnutls_clearHashDataBuffer(state);
return ret;
+ }
+ return ret;
}
/* This function receives the final handshake packets */
-static int _gnutls_recv_handshake_final( int cd, GNUTLS_STATE state, int init) {
-int ret=0;
-
- ret =
- gnutls_recv_int(cd, state, GNUTLS_CHANGE_CIPHER_SPEC,
- NULL, 0, 0);
- if (ret < 0) {
- ERR("recv ChangeCipherSpec", ret);
- gnutls_clearHashDataBuffer( state);
- return ret;
- }
+static int _gnutls_recv_handshake_final(int cd, GNUTLS_STATE state,
+ int init)
+{
+ int ret = 0;
- /* Initialize the connection state (start encryption) - in case of server */
- if (init == TRUE) {
- ret = _gnutls_connection_state_init(state);
- if (ret<0) {
- gnutls_assert();
- gnutls_clearHashDataBuffer( state);
- return ret;
- }
- }
+ ret =
+ gnutls_recv_int(cd, state, GNUTLS_CHANGE_CIPHER_SPEC,
+ NULL, 0, 0);
+ if (ret < 0) {
+ ERR("recv ChangeCipherSpec", ret);
+ gnutls_clearHashDataBuffer(state);
+ return ret;
+ }
- ret = _gnutls_recv_finished(cd, state);
+ /* Initialize the connection state (start encryption) - in case of server */
+ if (init == TRUE) {
+ ret = _gnutls_connection_state_init(state);
if (ret < 0) {
- ERR("recv finished", ret);
- gnutls_clearHashDataBuffer( state);
+ gnutls_assert();
+ gnutls_clearHashDataBuffer(state);
return ret;
}
+ }
+
+ ret = _gnutls_recv_finished(cd, state);
+ if (ret < 0) {
+ ERR("recv finished", ret);
+ gnutls_clearHashDataBuffer(state);
return ret;
+ }
+ return ret;
}
/* in this function we finish the handshake procedure
@@ -1118,37 +1332,37 @@ int ret=0;
*/
int gnutls_handshake_finish(int cd, GNUTLS_STATE state)
{
- int ret=0;
+ int ret = 0;
if (state->security_parameters.entity == GNUTLS_CLIENT) {
/* receive the server key exchange */
- if (state->gnutls_internals.resumed==RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_recv_server_kx_message(cd, state);
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret = _gnutls_recv_server_kx_message(cd, state);
if (ret < 0) {
ERR("recv server kx message", ret);
- gnutls_clearHashDataBuffer( state);
+ gnutls_clearHashDataBuffer(state);
return ret;
}
/* Added for SRP */
-
+
/* send the client key exchange for SRP */
- if (state->gnutls_internals.resumed==RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_send_client_kx_message0(cd, state);
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret = _gnutls_send_client_kx_message0(cd, state);
if (ret < 0) {
ERR("send client kx0", ret);
- gnutls_clearHashDataBuffer( state);
+ gnutls_clearHashDataBuffer(state);
return ret;
}
-
+
/* receive the server key exchange (B) (SRP only) */
- if (state->gnutls_internals.resumed==RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_recv_server_kx_message2(cd, state);
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret = _gnutls_recv_server_kx_message2(cd, state);
if (ret < 0) {
ERR("recv server kx message2", ret);
- gnutls_clearHashDataBuffer( state);
+ gnutls_clearHashDataBuffer(state);
return ret;
}
@@ -1156,63 +1370,65 @@ int gnutls_handshake_finish(int cd, GNUTLS_STATE state)
/* FIXME: receive certificate request */
/* receive the server hello done */
- if (state->gnutls_internals.resumed==RESUME_FALSE) /* if we are not resuming */
- ret =
- _gnutls_recv_handshake(cd, state, NULL, NULL,
- GNUTLS_SERVER_HELLO_DONE);
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret =
+ _gnutls_recv_handshake(cd, state, NULL, NULL,
+ GNUTLS_SERVER_HELLO_DONE);
if (ret < 0) {
ERR("recv server hello done", ret);
- gnutls_clearHashDataBuffer( state);
+ gnutls_clearHashDataBuffer(state);
return ret;
}
/* send our certificate - if any */
- if (state->gnutls_internals.resumed==RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_send_client_certificate(cd, state);
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret = _gnutls_send_client_certificate(cd, state);
if (ret < 0) {
ERR("send client certificate", ret);
- gnutls_clearHashDataBuffer( state);
+ gnutls_clearHashDataBuffer(state);
return ret;
}
- if (state->gnutls_internals.resumed==RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_send_client_kx_message(cd, state);
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret = _gnutls_send_client_kx_message(cd, state);
if (ret < 0) {
ERR("send client kx", ret);
- gnutls_clearHashDataBuffer( state);
+ gnutls_clearHashDataBuffer(state);
return ret;
}
/* send client certificate verify */
- if (state->gnutls_internals.resumed==RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_send_client_certificate_verify( cd, state);
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret =
+ _gnutls_send_client_certificate_verify(cd,
+ state);
if (ret < 0) {
ERR("send client certificate verify", ret);
- gnutls_clearHashDataBuffer( state);
+ gnutls_clearHashDataBuffer(state);
return ret;
}
- } else { /* SERVER SIDE */
+ } else { /* SERVER SIDE */
/* send the server hello done */
- if (state->gnutls_internals.resumed==RESUME_FALSE) /* if we are not resuming */
- ret =
- _gnutls_send_handshake(cd, state, NULL, 0,
- GNUTLS_SERVER_HELLO_DONE);
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret =
+ _gnutls_send_handshake(cd, state, NULL, 0,
+ GNUTLS_SERVER_HELLO_DONE);
if (ret < 0) {
ERR("send server hello done", ret);
- gnutls_clearHashDataBuffer( state);
+ gnutls_clearHashDataBuffer(state);
return ret;
}
/* RECV CERTIFICATE + KEYEXCHANGE + CERTIFICATE_VERIFY */
- /* receive the client key exchange message */
- if (state->gnutls_internals.resumed==RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_recv_client_kx_message(cd, state);
+ /* receive the client key exchange message */
+ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
+ ret = _gnutls_recv_client_kx_message(cd, state);
if (ret < 0) {
ERR("recv client kx", ret);
- gnutls_clearHashDataBuffer( state);
+ gnutls_clearHashDataBuffer(state);
return ret;
}
@@ -1220,47 +1436,49 @@ int gnutls_handshake_finish(int cd, GNUTLS_STATE state)
}
/* send and recv the change cipher spec and finished messages */
- if ((state->gnutls_internals.resumed==RESUME_TRUE && state->security_parameters.entity == GNUTLS_CLIENT)
- || (state->gnutls_internals.resumed==RESUME_FALSE && state->security_parameters.entity == GNUTLS_SERVER)) {
+ if ((state->gnutls_internals.resumed == RESUME_TRUE
+ && state->security_parameters.entity == GNUTLS_CLIENT)
+ || (state->gnutls_internals.resumed == RESUME_FALSE
+ && state->security_parameters.entity == GNUTLS_SERVER)) {
/* if we are a client resuming - or we are a server not resuming */
- ret = _gnutls_recv_handshake_final( cd, state, TRUE);
+ ret = _gnutls_recv_handshake_final(cd, state, TRUE);
if (ret < 0) {
gnutls_assert();
- gnutls_clearHashDataBuffer( state);
+ gnutls_clearHashDataBuffer(state);
return ret;
}
- ret = _gnutls_send_handshake_final( cd, state, FALSE);
+ ret = _gnutls_send_handshake_final(cd, state, FALSE);
if (ret < 0) {
gnutls_assert();
- gnutls_clearHashDataBuffer( state);
+ gnutls_clearHashDataBuffer(state);
return ret;
}
- } else { /* if we are a client not resuming - or we are a server resuming */
+ } else { /* if we are a client not resuming - or we are a server resuming */
- ret = _gnutls_send_handshake_final( cd, state, TRUE);
+ ret = _gnutls_send_handshake_final(cd, state, TRUE);
if (ret < 0) {
gnutls_assert();
- gnutls_clearHashDataBuffer( state);
+ gnutls_clearHashDataBuffer(state);
return ret;
}
- ret = _gnutls_recv_handshake_final( cd, state, FALSE);
+ ret = _gnutls_recv_handshake_final(cd, state, FALSE);
if (ret < 0) {
gnutls_assert();
- gnutls_clearHashDataBuffer( state);
+ gnutls_clearHashDataBuffer(state);
return ret;
}
}
if (state->security_parameters.entity == GNUTLS_SERVER) {
/* in order to support session resuming */
- _gnutls_server_register_current_session( state);
+ _gnutls_server_register_current_session(state);
}
/* clear handshake buffer */
- gnutls_clearHashDataBuffer( state);
+ gnutls_clearHashDataBuffer(state);
return ret;
}
@@ -1275,7 +1493,8 @@ int _gnutls_generate_session_id(char *session_id, uint8 * len)
*len = 32;
#ifdef HARD_DEBUG
- fprintf(stderr, "SessionID: %s\n", _gnutls_bin2hex(session_id, 32));
+ fprintf(stderr, "SessionID: %s\n",
+ _gnutls_bin2hex(session_id, 32));
#endif
return 0;
}
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index fbac103cb6..1b79c838e2 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -23,14 +23,13 @@
#define GNUTLS_INT_H
/*
-#define HANDSHAKE_DEBUG
#define READ_DEBUG
#define WRITE_DEBUG
#define BUFFERS_DEBUG
#define HARD_DEBUG
-*/
+#define HANDSHAKE_DEBUG
#define DEBUG
-
+*/
#define MAX32 4294967295
#define MAX24 16777215
@@ -266,7 +265,7 @@ typedef struct {
char* db_name;
int expire_time;
MOD_AUTH_STRUCT* auth_struct; /* used in handshake packets and KX algorithms */
-
+ int v2_hello; /* set 0 normally - 1 if v2 hello was received - server side only */
} GNUTLS_INTERNALS;
typedef struct {
diff --git a/lib/gnutls_v2_compat.c b/lib/gnutls_v2_compat.c
new file mode 100644
index 0000000000..bc4190ac7a
--- /dev/null
+++ b/lib/gnutls_v2_compat.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2001 Nikos Mavroyanopoulos
+ *
+ * This file is part of GNUTLS.
+ *
+ * GNUTLS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GNUTLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <defines.h>
+#include "gnutls_int.h"
+#include "gnutls_errors.h"
+#include "gnutls_dh.h"
+#include "debug.h"
+#include "gnutls_algorithms.h"
+#include "gnutls_compress.h"
+#include "gnutls_plaintext.h"
+#include "gnutls_cipher.h"
+#include "gnutls_buffers.h"
+#include "gnutls_kx.h"
+#include "gnutls_handshake.h"
+#include "gnutls_num.h"
+#include "gnutls_hash_int.h"
+#include "gnutls_db.h"
+#include "gnutls_extensions.h"
+#include "gnutls_random.h"
+#include "gnutls_auth_int.h"
+
+
+/* This selects the best supported ciphersuite from the ones provided */
+static int SelectSuite_v2(GNUTLS_STATE state, opaque ret[2], char *data,
+ int datalen)
+{
+ int x, i, j;
+ GNUTLS_CipherSuite *ciphers;
+
+ x = _gnutls_supported_ciphersuites(state, &ciphers);
+#ifdef HARD_DEBUG
+ fprintf(stderr, "Requested cipher suites: \n");
+ for (j = 0; j < datalen; j += 2) {
+ if (data[j] == 0) { /* only print if in v2 compat mode */
+ j++;
+ fprintf(stderr, "\t%s\n",
+ _gnutls_cipher_suite_get_name(*
+ ((GNUTLS_CipherSuite *) & data[j])));
+ }
+ }
+ fprintf(stderr, "Supported cipher suites: \n");
+ for (j = 0; j < x; j++)
+ fprintf(stderr, "\t%s\n",
+ _gnutls_cipher_suite_get_name(ciphers[j]));
+#endif
+ memset(ret, '\0', sizeof(GNUTLS_CipherSuite));
+
+ for (j = 0; j < datalen; j += 2) {
+ for (i = 0; i < x; i++) {
+ if (data[j++] == 0)
+ if (memcmp
+ (&ciphers[i].CipherSuite, &data[j],
+ 2) == 0) {
+#ifdef HARD_DEBUG
+ fprintf(stderr,
+ "Selected cipher suite: ");
+ fprintf(stderr, "%s\n",
+ _gnutls_cipher_suite_get_name
+ (*
+ ((GNUTLS_CipherSuite *) &
+ data[j])));
+#endif
+ memmove(ret,
+ &ciphers[i].CipherSuite,
+ 2);
+ gnutls_free(ciphers);
+
+ return 0;
+ }
+ }
+ }
+
+
+ gnutls_free(ciphers);
+ gnutls_assert();
+ return GNUTLS_E_UNKNOWN_CIPHER_SUITE;
+
+}
+
+
+#define DECR_LEN(len, x) len-=x; if (len<0) {gnutls_assert(); return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;}
+
+/* Read a v2 client hello
+ */
+int _gnutls_read_client_hello_v2(GNUTLS_STATE state, opaque * data,
+ int datalen)
+{
+ uint16 session_id_len = 0;
+ int pos = 0;
+ int ret = 0;
+ uint16 sizeOfSuites;
+ GNUTLS_Version version;
+ time_t cur_time;
+ char *rand;
+ int len = datalen;
+ int err;
+ uint16 challenge;
+
+
+ /* we only want to get here once - only in client hello */
+ state->gnutls_internals.v2_hello = 0;
+
+
+ DECR_LEN(len, 2);
+#ifdef DEBUG
+ fprintf(stderr, "Client's version: %d.%d\n", data[pos],
+ data[pos + 1]);
+#endif
+
+ version = _gnutls_version_get(data[pos], data[pos + 1]);
+ /* fallback to SSL 3.0 */
+ gnutls_set_current_version(state, GNUTLS_SSL3);
+
+ pos += 2;
+
+
+ /* Read uint16 cipher_spec_length */
+ DECR_LEN(len, 2);
+ memmove(&sizeOfSuites, &data[pos], 2);
+ pos += 2;
+
+#ifndef WORDS_BIGENDIAN
+ sizeOfSuites = byteswap16(sizeOfSuites);
+#endif
+
+ /* read session id length */
+ DECR_LEN(len, 2);
+ memmove(&session_id_len, &data[pos], 2);
+#ifndef WORDS_BIGENDIAN
+ session_id_len = byteswap16(session_id_len);
+#endif
+ pos += 2;
+
+ if (session_id_len > 32)
+ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+
+
+ /* read challenge length */
+ DECR_LEN(len, 2);
+ memmove(&challenge, &data[pos], 2);
+#ifndef WORDS_BIGENDIAN
+ challenge = byteswap16(challenge);
+#endif
+ pos += 2;
+
+ if (challenge < 10) { /* wow that's not random */
+ gnutls_assert();
+ return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
+ }
+
+
+ /* find an appropriate cipher suite */
+
+ DECR_LEN(len, sizeOfSuites);
+ ret = SelectSuite_v2(state, state->gnutls_internals.
+ current_cipher_suite.CipherSuite,
+ &data[pos], sizeOfSuites);
+
+ pos += sizeOfSuites;
+ if (ret < 0)
+ return ret;
+
+
+ /* check if the credentials (username, public key etc. are ok)
+ */
+ if (_gnutls_get_kx_cred( state->gnutls_key, _gnutls_cipher_suite_get_kx_algo(state->gnutls_internals.current_cipher_suite), &err) == NULL && err != 0) {
+ gnutls_assert();
+ return GNUTLS_E_INSUFICIENT_CRED;
+ }
+
+ /* set the MOD_AUTH_STRUCT to the appropriate struct
+ * according to the KX algorithm. This is needed since all the
+ * handshake functions are read from there;
+ */
+ state->gnutls_internals.auth_struct =
+ _gnutls_kx_auth_struct(_gnutls_cipher_suite_get_kx_algo
+ (state->gnutls_internals.
+ current_cipher_suite));
+ if (state->gnutls_internals.auth_struct == NULL) {
+#ifdef DEBUG
+ fprintf(stderr,
+ "Cannot find the appropriate handler for the KX algorithm\n");
+#endif
+ gnutls_assert();
+ return GNUTLS_E_UNKNOWN_CIPHER_TYPE;
+ }
+
+
+
+ /* read random new values -skip session id for now */
+ DECR_LEN(len, session_id_len); /* skip session id for now */
+ pos+=session_id_len;
+
+ DECR_LEN(len, challenge);
+ memset( state->security_parameters.client_random, 0, 32);
+
+ /* read the last 32 bytes */
+ memcpy( state->security_parameters.client_random, &data[challenge > 32 ? (pos+challenge-32) : pos], challenge < 32 ? challenge : 32);
+
+ /* generate server random value */
+#ifdef WORDS_BIGENDIAN
+ cur_time = time(NULL);
+#else
+ cur_time = byteswap32(time(NULL));
+#endif
+ memmove(state->security_parameters.server_random, &cur_time, 4);
+ rand = _gnutls_get_random(28, GNUTLS_STRONG_RANDOM);
+ memmove(&state->security_parameters.server_random[4], rand, 28);
+ _gnutls_free_rand(rand);
+ state->security_parameters.timestamp = time(NULL);
+
+
+ /* RESUME SESSION */
+
+ len += session_id_len; /* back to session_id */
+ pos -= session_id_len;
+
+
+ DECR_LEN(len, session_id_len);
+ ret = _gnutls_server_restore_session(state, &data[pos], session_id_len);
+
+ pos += session_id_len;
+
+ if (ret == 0) { /* resumed! */
+ /* get the new random values */
+ memcpy(state->gnutls_internals.resumed_security_parameters.server_random,
+ state->security_parameters.server_random, 32);
+ memcpy(state->gnutls_internals.resumed_security_parameters.client_random,
+ state->security_parameters.client_random, 32);
+
+ state->gnutls_internals.resumed = RESUME_TRUE;
+ return 0;
+ } else {
+ _gnutls_generate_session_id(state->security_parameters.
+ session_id,
+ &state->security_parameters.
+ session_id_size);
+ state->gnutls_internals.resumed = RESUME_FALSE;
+ }
+
+ return ret;
+}
diff --git a/lib/gnutls_v2_compat.h b/lib/gnutls_v2_compat.h
new file mode 100644
index 0000000000..595d04d60b
--- /dev/null
+++ b/lib/gnutls_v2_compat.h
@@ -0,0 +1 @@
+int _gnutls_read_client_hello_v2(GNUTLS_STATE state, opaque * data, int datalen);
diff --git a/src/cli.c b/src/cli.c
index 5c66953b3c..bcfdaa8909 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -82,7 +82,8 @@ int main()
gnutls_set_cipher_priority( state, 3, GNUTLS_3DES, GNUTLS_ARCFOUR, GNUTLS_RIJNDAEL);
gnutls_set_compression_priority( state, 2, GNUTLS_ZLIB, GNUTLS_NULL_COMPRESSION);
- gnutls_set_kx_priority( state, 2, GNUTLS_KX_SRP, GNUTLS_KX_ANON_DH);
+// gnutls_set_kx_priority( state, 2, GNUTLS_KX_SRP, GNUTLS_KX_ANON_DH);
+ gnutls_set_kx_priority( state, 1, GNUTLS_KX_ANON_DH);
gnutls_set_kx_cred( state, GNUTLS_KX_ANON_DH, NULL, 0);
gnutls_set_kx_cred( state, GNUTLS_KX_SRP, &cred, sizeof(cred));