summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/gnutls_buffers.c26
-rw-r--r--lib/gnutls_handshake.c444
-rw-r--r--lib/gnutls_handshake.h2
-rw-r--r--lib/gnutls_int.h7
-rw-r--r--lib/gnutls_kx.c143
-rw-r--r--lib/gnutls_kx.h16
-rw-r--r--lib/gnutls_record.c49
7 files changed, 441 insertions, 246 deletions
diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c
index 756c55e3b1..e6d78fc840 100644
--- a/lib/gnutls_buffers.c
+++ b/lib/gnutls_buffers.c
@@ -176,10 +176,13 @@ static ssize_t _gnutls_read(SOCKET fd, void *iptr, size_t sizeOfPtr, int flags)
#endif
goto finish;
}
+ gnutls_assert();
if (errno==EAGAIN) return GNUTLS_E_AGAIN;
else return GNUTLS_E_INTERRUPTED;
- } else
+ } else {
+ gnutls_assert();
return GNUTLS_E_PULL_ERROR;
+ }
} else {
#ifdef READ_DEBUG
_gnutls_log( "READ: Got %d bytes from %d\n", i, fd);
@@ -273,6 +276,7 @@ void _gnutls_read_clear_buffer( GNUTLS_STATE state) {
*
* This is not a general purpose function. It returns EXACTLY the data requested.
*
+ * FIXME: make the buffer, be dynamically allocated.
*/
ssize_t _gnutls_read_buffered( int fd, GNUTLS_STATE state, opaque **iptr, size_t sizeOfPtr, ContentType recv_type)
{
@@ -466,6 +470,7 @@ ssize_t _gnutls_write_buffered(int fd, GNUTLS_STATE state, const void *iptr, siz
#ifdef WRITE_DEBUG
_gnutls_log( "WRITE: Interrupted. wrote %d bytes to %d. Left %d\n", n-left, fd, left);
#endif
+ gnutls_assert();
if (errno==EAGAIN) return GNUTLS_E_AGAIN;
else return GNUTLS_E_INTERRUPTED;
@@ -508,10 +513,23 @@ ssize_t _gnutls_handshake_send_int(int fd, GNUTLS_STATE state, ContentType type,
ssize_t i = 0;
char *ptr = iptr;
+ if (iptr==NULL && n == 0) {
+ uint8 sdata = 0;
+ /* resuming interrupted write. Put some random data into
+ * the data field so send_int() will proceed normally.
+ */
+ return gnutls_send_int( fd, state, type, htype, &sdata, 1);
+ }
+
left = n;
while (left > 0) {
i = gnutls_send_int(fd, state, type, htype, &ptr[i], left);
if (i <= 0) {
+ gnutls_assert();
+ if (n-left > 0) {
+ gnutls_assert();
+ return n-left;
+ }
return i;
}
left -= i;
@@ -534,6 +552,11 @@ ssize_t _gnutls_handshake_recv_int(int fd, GNUTLS_STATE state, ContentType type,
while (left > 0) {
i = gnutls_recv_int(fd, state, type, htype, &ptr[i], left);
if (i < 0) {
+ if (sizeOfPtr - left > 0) {
+ gnutls_assert();
+ goto finish;
+ }
+ gnutls_assert();
return i;
} else {
if (i == 0)
@@ -544,6 +567,7 @@ ssize_t _gnutls_handshake_recv_int(int fd, GNUTLS_STATE state, ContentType type,
}
+ finish:
return (sizeOfPtr - left);
}
diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c
index eb54c2182c..0c2f249df0 100644
--- a/lib/gnutls_handshake.c
+++ b/lib/gnutls_handshake.c
@@ -116,9 +116,15 @@ void *_gnutls_ssl3_finished(GNUTLS_STATE state, int type, int skip)
GNUTLS_MAC_HANDLE td;
GNUTLS_MAC_HANDLE td2;
char tmp[MAX_HASH_SIZE];
- char *concat = gnutls_malloc(36);
+ char *concat;
char *mesg, *data;
+ concat = gnutls_malloc(36);
+ if (concat==NULL) {
+ gnutls_assert();
+ return NULL;
+ }
+
td = gnutls_mac_init_ssl3_handshake(GNUTLS_MAC_MD5,
state->security_parameters.
master_secret, 48);
@@ -129,6 +135,10 @@ void *_gnutls_ssl3_finished(GNUTLS_STATE state, int type, int skip)
siz = gnutls_getHashDataBufferSize(state) - skip;
data = gnutls_malloc(siz);
+ if (data==NULL) {
+ gnutls_assert();
+ return NULL;
+ }
gnutls_readHashDataFromBuffer(state, data, siz);
@@ -172,6 +182,10 @@ void *_gnutls_finished(GNUTLS_STATE state, int type, int skip)
siz = gnutls_getHashDataBufferSize(state) - skip;
data = gnutls_malloc(siz);
+ if (data==NULL) {
+ gnutls_assert();
+ return NULL;
+ }
gnutls_readHashDataFromBuffer(state, data, siz);
@@ -381,25 +395,26 @@ int _gnutls_read_client_hello(GNUTLS_STATE state, opaque * data,
* and initializing encryption. This is the first encrypted message
* we send.
*/
-int _gnutls_send_finished(SOCKET cd, GNUTLS_STATE state)
+int _gnutls_send_finished(SOCKET cd, GNUTLS_STATE state, int again)
{
- uint8 *data;
+ uint8 *data=NULL;
int ret;
- int data_size;
-
- if (state->connection_state.version == GNUTLS_SSL3) {
- 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;
+ int data_size=0;
+
+ if (again==0) {
+ if (state->connection_state.version == GNUTLS_SSL3) {
+ 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;
+ }
}
-
ret =
_gnutls_send_handshake(cd, state, data, data_size,
GNUTLS_FINISHED);
@@ -550,6 +565,15 @@ int _gnutls_server_SelectCompMethod(GNUTLS_STATE state,
return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM;
}
+int _gnutls_send_empty_handshake(SOCKET cd, GNUTLS_STATE state, HandshakeType type, int again) {
+opaque data=0;
+opaque * ptr;
+
+if (again==0) ptr = &data;
+else ptr = NULL;
+
+ return _gnutls_send_handshake( cd, state, ptr, 0, type);
+}
int _gnutls_send_handshake(SOCKET cd, GNUTLS_STATE state, void *i_data,
uint32 i_datasize, HandshakeType type)
@@ -559,38 +583,59 @@ int _gnutls_send_handshake(SOCKET cd, GNUTLS_STATE state, void *i_data,
uint32 datasize;
int pos = 0;
- datasize = i_datasize;
+ if (i_data==NULL && i_datasize == 0) {
+ /* we are resuming a previously interrupted
+ * send.
+ */
+ return
+ _gnutls_handshake_send_int(cd, state, GNUTLS_HANDSHAKE, type,
+ i_data, i_datasize);
+ }
- i_datasize += HANDSHAKE_HEADER_SIZE;
- data = gnutls_malloc(i_datasize);
+ if (i_data==NULL && i_datasize > 0) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_PARAMETERS;
+ }
+
+ /* first run */
+ datasize = i_datasize + HANDSHAKE_HEADER_SIZE;
+ data = gnutls_malloc(datasize);
+ if (data==NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
memcpy(&data[pos++], &type, 1);
- WRITEuint24(datasize, &data[pos]);
+ WRITEuint24(i_datasize, &data[pos]);
pos += 3;
- if (i_datasize > 4)
- memcpy(&data[pos], i_data, i_datasize - 4);
+ if (i_datasize > 0)
+ memcpy(&data[pos], i_data, i_datasize);
#ifdef HANDSHAKE_DEBUG
_gnutls_log("Handshake: %s was send [%ld bytes]\n",
- _gnutls_handshake2str(type), i_datasize);
+ _gnutls_handshake2str(type), datasize);
#endif
/* Here we keep the handshake messages in order to hash them later!
*/
if (type != GNUTLS_HELLO_REQUEST) {
+
if ((ret =
gnutls_insertHashDataBuffer(state, data,
- i_datasize)) < 0) {
+ datasize)) < 0) {
gnutls_assert();
+ gnutls_free(data);
return ret;
}
}
+
ret =
_gnutls_handshake_send_int(cd, state, GNUTLS_HANDSHAKE, type,
- data, i_datasize);
+ data, datasize);
gnutls_free(data);
+
return ret;
}
@@ -817,38 +862,6 @@ int _gnutls_recv_handshake(SOCKET cd, GNUTLS_STATE state, uint8 ** data,
return ret;
}
-/**
- * gnutls_rehandshake - This function will renegotiate security parameters
- * @cd: is a connection descriptor, as returned by socket().
- * @state: is a a &GNUTLS_STATE structure.
- *
- * This function will renegotiate security parameters with the
- * client. This should only be called in case of a server.
- * If the client does not wish to renegotiate parameters he
- * will reply with an alert message, thus the return code will be
- * GNUTLS_E_WARNING_ALERT_RECEIVED and the alert will be
- * GNUTLS_NO_RENEGOTIATION.
- **/
-int gnutls_rehandshake(SOCKET cd, GNUTLS_STATE state)
-{
- int ret;
-
- /* only server sends that handshake packet */
- if (state->security_parameters.entity == GNUTLS_CLIENT)
- return GNUTLS_E_UNIMPLEMENTED_FEATURE;
-
- ret = _gnutls_send_handshake(cd, state, NULL, 0,
- GNUTLS_HELLO_REQUEST);
-
- if (ret < 0) {
- gnutls_assert();
- return ret;
- }
- /* begin handshake procedure again */
- ret = gnutls_handshake(cd, state);
-
- return ret;
-}
static int _gnutls_read_server_hello(GNUTLS_STATE state, char *data,
int datalen)
@@ -1015,7 +1028,7 @@ static int _gnutls_read_server_hello(GNUTLS_STATE state, char *data,
}
-static int _gnutls_send_client_hello(SOCKET cd, GNUTLS_STATE state)
+static int _gnutls_send_client_hello(SOCKET cd, GNUTLS_STATE state, int again)
{
char *data = NULL;
opaque *extdata;
@@ -1038,68 +1051,105 @@ static int _gnutls_send_client_hello(SOCKET cd, GNUTLS_STATE state)
if (SessionID == NULL)
session_id_len = 0;
- datalen = 2 + 4 + (session_id_len + 1) + 28 + 3;
- /* 2 for version, 4 for unix time, 28 for random bytes 2 for cipher suite's
- * size and 1 for compression method's size
- */
- data = gnutls_malloc(datalen);
+ data = NULL;
+ datalen = 0;
+ if (again==0) {
+ datalen = 2 + 4 + (session_id_len + 1) + 28 + 3;
+ /* 2 for version, 4 for unix time, 28 for random bytes 2 for cipher suite's
+ * size and 1 for compression method's size
+ */
+ data = gnutls_malloc(datalen);
+ if (data==NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
- hver = _gnutls_version_max(state);
- data[pos++] = _gnutls_version_get_major(hver);
- data[pos++] = _gnutls_version_get_minor(hver);
+ hver = _gnutls_version_max(state);
+ data[pos++] = _gnutls_version_get_major(hver);
+ data[pos++] = _gnutls_version_get_minor(hver);
- _gnutls_create_random(random);
- _gnutls_set_client_random(state, random);
+ _gnutls_create_random(random);
+ _gnutls_set_client_random(state, random);
- state->security_parameters.timestamp = time(0);
+ state->security_parameters.timestamp = time(0);
- memcpy(&data[pos],
- state->security_parameters.client_random, TLS_RANDOM_SIZE);
- pos += TLS_RANDOM_SIZE;
+ memcpy(&data[pos],
+ state->security_parameters.client_random, TLS_RANDOM_SIZE);
+ pos += TLS_RANDOM_SIZE;
- memcpy(&data[pos++], &session_id_len, 1);
+ memcpy(&data[pos++], &session_id_len, 1);
- if (session_id_len > 0) {
- memcpy(&data[pos], SessionID, session_id_len);
- }
- pos += session_id_len;
+ if (session_id_len > 0) {
+ memcpy(&data[pos], SessionID, session_id_len);
+ }
+ pos += session_id_len;
- x = _gnutls_supported_ciphersuites_sorted(state, &cipher_suites);
- x *= sizeof(uint16); /* in order to get bytes */
+ ret = _gnutls_supported_ciphersuites_sorted(state, &cipher_suites);
+ if (ret<0) {
+ gnutls_free(data);
+ gnutls_assert();
+ return ret;
+ }
- WRITEuint16(x, &data[pos]);
- pos += sizeof(uint16);
+ x = ret;
+ x *= sizeof(uint16); /* in order to get bytes */
- datalen += x;
- data = gnutls_realloc(data, datalen);
+ WRITEuint16(x, &data[pos]);
+ pos += sizeof(uint16);
- for (i = 0; i < x / 2; i++) {
- memcpy(&data[pos], cipher_suites[i].CipherSuite, 2);
- pos += 2;
- }
- gnutls_free(cipher_suites);
+ datalen += x;
+ data = gnutls_realloc(data, datalen);
+ if (data==NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ for (i = 0; i < x / 2; i++) {
+ memcpy(&data[pos], cipher_suites[i].CipherSuite, 2);
+ pos += 2;
+ }
+ gnutls_free(cipher_suites);
- z = _gnutls_supported_compression_methods
- (state, &compression_methods);
+ ret = _gnutls_supported_compression_methods
+ (state, &compression_methods);
+ if (ret < 0) {
+ gnutls_free(data);
+ gnutls_assert();
+ return ret;
+ }
+
+ z = ret;
+ memcpy(&data[pos++], &z, 1); /* put the number of compression methods */
- memcpy(&data[pos++], &z, 1); /* put the number of compression methods */
+ datalen += z;
+ data = gnutls_realloc(data, datalen);
+ if (data==NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
- datalen += z;
- data = gnutls_realloc(data, datalen);
+ for (i = 0; i < z; i++) {
+ memcpy(&data[pos++], &compression_methods[i], 1);
+ }
- for (i = 0; i < z; i++) {
- memcpy(&data[pos++], &compression_methods[i], 1);
- }
+ gnutls_free(compression_methods);
- gnutls_free(compression_methods);
+ extdatalen = _gnutls_gen_extensions(state, &extdata);
+ if (extdatalen > 0) {
+ datalen += extdatalen;
+ data = gnutls_realloc(data, datalen);
+ if (data==NULL) {
+ gnutls_assert();
+ gnutls_free(extdata);
+ return GNUTLS_E_MEMORY_ERROR;
+ }
- extdatalen = _gnutls_gen_extensions(state, &extdata);
- if (extdatalen > 0) {
- datalen += extdatalen;
- data = gnutls_realloc(data, datalen);
- memcpy(&data[pos], extdata, extdatalen);
- gnutls_free(extdata);
+ memcpy(&data[pos], extdata, extdatalen);
+ gnutls_free(extdata);
+ }
+
}
+
ret =
_gnutls_send_handshake(cd, state, data, datalen,
GNUTLS_CLIENT_HELLO);
@@ -1110,7 +1160,7 @@ static int _gnutls_send_client_hello(SOCKET cd, GNUTLS_STATE state)
return ret;
}
-static int _gnutls_send_server_hello(SOCKET cd, GNUTLS_STATE state)
+static int _gnutls_send_server_hello(SOCKET cd, GNUTLS_STATE state, int again)
{
char *data = NULL;
opaque *extdata;
@@ -1124,60 +1174,76 @@ static int _gnutls_send_server_hello(SOCKET cd, GNUTLS_STATE state)
if (SessionID == NULL)
session_id_len = 0;
- datalen = 2 + session_id_len + 1 + TLS_RANDOM_SIZE;
- data = gnutls_malloc(datalen);
- if (data == NULL) {
- gnutls_assert();
- return GNUTLS_E_MEMORY_ERROR;
- }
+ data = NULL;
+ datalen = 0;
+
+ if (again==0) {
+ datalen = 2 + session_id_len + 1 + TLS_RANDOM_SIZE;
+ data = gnutls_malloc(datalen);
+ if (data == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
- 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);
- memcpy(&data[pos],
- state->security_parameters.server_random, TLS_RANDOM_SIZE);
- pos += TLS_RANDOM_SIZE;
+ memcpy(&data[pos],
+ state->security_parameters.server_random, TLS_RANDOM_SIZE);
+ pos += TLS_RANDOM_SIZE;
- data[pos++] = session_id_len;
- if (session_id_len > 0) {
- memcpy(&data[pos], SessionID, session_id_len);
- }
- pos += session_id_len;
+ data[pos++] = session_id_len;
+ if (session_id_len > 0) {
+ memcpy(&data[pos], SessionID, session_id_len);
+ }
+ pos += session_id_len;
#ifdef HANDSHAKE_DEBUG
- _gnutls_log("Handshake: SessionID: %s\n",
- _gnutls_bin2hex(SessionID, session_id_len));
+ _gnutls_log("Handshake: SessionID: %s\n",
+ _gnutls_bin2hex(SessionID, session_id_len));
#endif
- datalen += 2;
- data = gnutls_realloc(data, datalen);
-
- memcpy(&data[pos],
- state->security_parameters.
- current_cipher_suite.CipherSuite, 2);
- pos += 2;
-
- datalen += 1;
- data = gnutls_realloc(data, datalen);
- if (data == NULL) {
- gnutls_assert();
- return GNUTLS_E_MEMORY_ERROR;
- }
+ datalen += 2;
+ data = gnutls_realloc(data, datalen);
+ if (data == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
- comp =
- (uint8) _gnutls_compression_get_num(state->gnutls_internals.
- compression_method);
- memcpy(&data[pos++], &comp, 1);
+ memcpy(&data[pos],
+ state->security_parameters.
+ current_cipher_suite.CipherSuite, 2);
+ pos += 2;
- extdatalen = _gnutls_gen_extensions(state, &extdata);
- if (extdatalen > 0) {
- datalen += extdatalen;
+ datalen += 1;
data = gnutls_realloc(data, datalen);
- memcpy(&data[pos], extdata, extdatalen);
- gnutls_free(extdata);
+ if (data == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ comp =
+ (uint8) _gnutls_compression_get_num(state->gnutls_internals.
+ compression_method);
+ memcpy(&data[pos++], &comp, 1);
+
+ extdatalen = _gnutls_gen_extensions(state, &extdata);
+ if (extdatalen > 0) {
+ datalen += extdatalen;
+ data = gnutls_realloc(data, datalen);
+ if (data==NULL) {
+ gnutls_free(extdata);
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ memcpy(&data[pos], extdata, extdatalen);
+ gnutls_free(extdata);
+ }
}
+
ret =
_gnutls_send_handshake(cd, state, data, datalen,
GNUTLS_SERVER_HELLO);
@@ -1187,15 +1253,14 @@ static int _gnutls_send_server_hello(SOCKET cd, GNUTLS_STATE state)
return ret;
}
-int _gnutls_send_hello(SOCKET cd, GNUTLS_STATE state)
-{
- int ret;
+int _gnutls_send_hello(SOCKET cd, GNUTLS_STATE state, int again) {
+int ret;
if (state->security_parameters.entity == GNUTLS_CLIENT) {
- ret = _gnutls_send_client_hello(cd, state);
+ ret = _gnutls_send_client_hello(cd, state, again);
} else { /* SERVER */
- ret = _gnutls_send_server_hello(cd, state);
+ ret = _gnutls_send_server_hello(cd, state, again);
}
return ret;
@@ -1256,6 +1321,50 @@ int _gnutls_recv_hello(SOCKET cd, GNUTLS_STATE state, char *data,
#define STATE state->gnutls_internals.handshake_state
+/* This returns true if we have got there
+ * before (and not finished due to an interrupt).
+ */
+#define AGAIN(target) STATE==target?1:0
+
+/**
+ * gnutls_rehandshake - This function will renegotiate security parameters
+ * @cd: is a connection descriptor, as returned by socket().
+ * @state: is a a &GNUTLS_STATE structure.
+ *
+ * This function will renegotiate security parameters with the
+ * client. This should only be called in case of a server.
+ *
+ * This message informs the peer that we want to renegotiate
+ * parameters (perform a handshake).
+ *
+ * If this function succeeds (returns 0), you must call
+ * the gnutls_handshake() function in order to negotiate
+ * the new parameters.
+ *
+ * If the client does not wish to renegotiate parameters he
+ * will reply with an alert message, thus the return code will be
+ * GNUTLS_E_WARNING_ALERT_RECEIVED and the alert will be
+ * GNUTLS_NO_RENEGOTIATION.
+ **/
+int gnutls_rehandshake(SOCKET cd, GNUTLS_STATE state)
+{
+ int ret;
+
+ /* only server sends that handshake packet */
+ if (state->security_parameters.entity == GNUTLS_CLIENT)
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+
+ ret = _gnutls_send_empty_handshake(cd, state, GNUTLS_HELLO_REQUEST, AGAIN(STATE50));
+ STATE = STATE50;
+
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+ STATE = STATE0;
+
+ return 0;
+}
/**
* gnutls_handshake - This the main function in the handshake protocol.
@@ -1326,7 +1435,7 @@ int gnutls_handshake_client(SOCKET cd, GNUTLS_STATE state)
switch( STATE) {
case STATE1:
- ret = _gnutls_send_hello(cd, state);
+ ret = _gnutls_send_hello(cd, state, 0);
STATE = STATE1;
IMED_RET("send hello", ret);
@@ -1357,7 +1466,7 @@ int gnutls_handshake_client(SOCKET cd, GNUTLS_STATE state)
* 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);
+ ret = _gnutls_send_client_kx_message0(cd, state, AGAIN(STATE5));
STATE = STATE5;
IMED_RET("send client kx0", ret);
@@ -1393,20 +1502,20 @@ int gnutls_handshake_client(SOCKET cd, GNUTLS_STATE state)
/* send our certificate - if any and if requested
*/
if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_send_client_certificate(cd, state);
+ ret = _gnutls_send_client_certificate(cd, state, AGAIN(STATE9));
STATE = STATE9;
IMED_RET("send client certificate", ret);
case STATE10:
if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_send_client_kx_message(cd, state);
+ ret = _gnutls_send_client_kx_message(cd, state, AGAIN(STATE10));
STATE = STATE10;
IMED_RET("send client kx", ret);
case STATE11:
/* send client certificate verify */
if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */
- ret = _gnutls_send_client_certificate_verify(cd, state);
+ ret = _gnutls_send_client_certificate_verify(cd, state, AGAIN(STATE11));
STATE = STATE11;
IMED_RET("send client certificate verify", ret);
@@ -1456,7 +1565,7 @@ static int _gnutls_send_handshake_final(SOCKET cd, GNUTLS_STATE state,
case STATE21:
/* send the finished message */
- ret = _gnutls_send_finished(cd, state);
+ ret = _gnutls_send_finished(cd, state, AGAIN(STATE21));
STATE = STATE21;
if (ret < 0) {
ERR("send Finished", ret);
@@ -1546,7 +1655,7 @@ int gnutls_handshake_server(SOCKET cd, GNUTLS_STATE state)
IMED_RET("recv hello", ret);
case STATE2:
- ret = _gnutls_send_hello(cd, state);
+ ret = _gnutls_send_hello(cd, state, AGAIN(STATE2));
STATE = STATE2;
IMED_RET("send hello", ret);
@@ -1555,21 +1664,21 @@ int gnutls_handshake_server(SOCKET cd, GNUTLS_STATE state)
/* NOTE: these should not be send if we are resuming */
if (state->gnutls_internals.resumed == RESUME_FALSE)
- ret = _gnutls_send_server_certificate(cd, state);
+ ret = _gnutls_send_server_certificate(cd, state, AGAIN(STATE3));
STATE = STATE3;
IMED_RET("send server certificate", ret);
case STATE4:
/* send server key exchange (A) */
if (state->gnutls_internals.resumed == RESUME_FALSE)
- ret = _gnutls_send_server_kx_message(cd, state);
+ ret = _gnutls_send_server_kx_message(cd, state, AGAIN(STATE4));
STATE = STATE4;
IMED_RET("send server kx", ret);
case STATE5:
/* Send certificate request - if requested to */
if (state->gnutls_internals.resumed == RESUME_FALSE)
- ret = _gnutls_send_server_certificate_request(cd, state);
+ ret = _gnutls_send_server_certificate_request(cd, state, AGAIN(STATE5));
STATE = STATE5;
IMED_RET("send server cert request", ret);
@@ -1585,7 +1694,7 @@ int gnutls_handshake_server(SOCKET cd, GNUTLS_STATE state)
case STATE7:
/* send server key exchange (B) */
if (state->gnutls_internals.resumed == RESUME_FALSE)
- ret = _gnutls_send_server_kx_message2(cd, state);
+ ret = _gnutls_send_server_kx_message2(cd, state, AGAIN(STATE7));
STATE = STATE7;
IMED_RET("send server kx2", ret);
@@ -1593,8 +1702,7 @@ int gnutls_handshake_server(SOCKET cd, GNUTLS_STATE state)
/* 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);
+ _gnutls_send_empty_handshake(cd, state, GNUTLS_SERVER_HELLO_DONE, AGAIN(STATE8));
STATE = STATE8;
IMED_RET("send server hello done", ret);
@@ -1798,6 +1906,10 @@ int _gnutls_remove_unwanted_ciphersuites(GNUTLS_STATE state,
newSuite =
gnutls_malloc(numCipherSuites * sizeof(GNUTLS_CipherSuite));
+ if (newSuite==NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
for (i = 0; i < numCipherSuites; i++) {
kx = _gnutls_cipher_suite_get_kx_algo((*cipherSuites)[i]);
diff --git a/lib/gnutls_handshake.h b/lib/gnutls_handshake.h
index d59889495e..c1498de5cf 100644
--- a/lib/gnutls_handshake.h
+++ b/lib/gnutls_handshake.h
@@ -23,7 +23,7 @@ typedef enum Optional { OPTIONAL_PACKET, MANDATORY_PACKET } Optional;
int _gnutls_send_handshake(int cd, GNUTLS_STATE state, void* i_data, uint32 i_datasize, HandshakeType type);
int gnutls_send_hello_request(int cd, GNUTLS_STATE state);
int _gnutls_recv_hello_request(int cd, GNUTLS_STATE state, void* data, uint32 data_size);
-int _gnutls_send_hello(int cd, GNUTLS_STATE state);
+int _gnutls_send_hello(int cd, GNUTLS_STATE state, int again);
int _gnutls_recv_hello(int cd, GNUTLS_STATE state, char* data, int datalen);
int gnutls_handshake(int cd, GNUTLS_STATE state);
int _gnutls_recv_handshake( int cd, GNUTLS_STATE state, uint8**, int*, HandshakeType, Optional optional);
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index a8748d306e..10bf979da9 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -26,12 +26,13 @@
/*
#define BUFFERS_DEBUG
-#define WRITE_DEBUG
#define HARD_DEBUG
+#define READ_DEBUG
+#define WRITE_DEBUG
#define HANDSHAKE_DEBUG
#define RECORD_DEBUG
-#define READ_DEBUG*/
#define DEBUG
+*/
/* It might be a good idea to replace int with void*
* here.
@@ -104,7 +105,7 @@ typedef enum CloseRequest { GNUTLS_SHUT_RDWR=0, GNUTLS_SHUT_WR=1 } CloseRequest;
typedef enum HandshakeState { STATE0=0, STATE1, STATE2, STATE3, STATE4, STATE5,
STATE6, STATE7, STATE8, STATE9, STATE10, STATE11, STATE20=20, STATE21,
- STATE30=30, STATE31 } HandshakeState;
+ STATE30=30, STATE31, STATE50 } HandshakeState;
typedef enum HandshakeType { GNUTLS_HELLO_REQUEST, GNUTLS_CLIENT_HELLO, GNUTLS_SERVER_HELLO,
GNUTLS_CERTIFICATE=11, GNUTLS_SERVER_KEY_EXCHANGE,
diff --git a/lib/gnutls_kx.c b/lib/gnutls_kx.c
index cc41272698..f79cddb8f0 100644
--- a/lib/gnutls_kx.c
+++ b/lib/gnutls_kx.c
@@ -89,7 +89,7 @@ char random[2*TLS_RANDOM_SIZE];
* server. It does nothing if this type of message is not required
* by the selected ciphersuite.
*/
-int _gnutls_send_server_kx_message(SOCKET cd, GNUTLS_STATE state)
+int _gnutls_send_server_kx_message(SOCKET cd, GNUTLS_STATE state, int again)
{
uint8 *data = NULL;
int data_size = 0;
@@ -98,13 +98,18 @@ int _gnutls_send_server_kx_message(SOCKET cd, GNUTLS_STATE state)
if (state->gnutls_internals.auth_struct->gnutls_generate_server_kx==NULL)
return 0;
- data_size = state->gnutls_internals.auth_struct->gnutls_generate_server_kx( state, &data);
+ data = NULL;
+ data_size = 0;
- if (data_size < 0) {
- gnutls_assert();
- return data_size;
- }
+ if (again == 0) {
+ data_size = state->gnutls_internals.auth_struct->gnutls_generate_server_kx( state, &data);
+ if (data_size < 0) {
+ gnutls_assert();
+ return data_size;
+ }
+ }
+
ret = _gnutls_send_handshake(cd, state, data, data_size, GNUTLS_SERVER_KEY_EXCHANGE);
gnutls_free(data);
@@ -118,7 +123,7 @@ int _gnutls_send_server_kx_message(SOCKET cd, GNUTLS_STATE state)
/* This function sends a certificate request message to the
* client.
*/
-int _gnutls_send_server_certificate_request(SOCKET cd, GNUTLS_STATE state)
+int _gnutls_send_server_certificate_request(SOCKET cd, GNUTLS_STATE state, int again)
{
uint8 *data = NULL;
int data_size = 0;
@@ -130,13 +135,17 @@ int _gnutls_send_server_certificate_request(SOCKET cd, GNUTLS_STATE state)
if (state->gnutls_internals.send_cert_req <= 0)
return 0;
- data_size = state->gnutls_internals.auth_struct->gnutls_generate_server_certificate_request( state, &data);
+ data = NULL;
+ data_size = 0;
- if (data_size < 0) {
- gnutls_assert();
- return data_size;
- }
+ if (again == 0) {
+ data_size = state->gnutls_internals.auth_struct->gnutls_generate_server_certificate_request( state, &data);
+ if (data_size < 0) {
+ gnutls_assert();
+ return data_size;
+ }
+ }
ret = _gnutls_send_handshake(cd, state, data, data_size, GNUTLS_CERTIFICATE_REQUEST);
gnutls_free(data);
@@ -148,35 +157,42 @@ int _gnutls_send_server_certificate_request(SOCKET cd, GNUTLS_STATE state)
}
/* Currently only used in SRP */
-int _gnutls_send_server_kx_message2(SOCKET cd, GNUTLS_STATE state)
+int _gnutls_send_server_kx_message2(SOCKET cd, GNUTLS_STATE state, int again)
{
uint8 *data = NULL;
int data_size = 0;
int ret = 0;
- if (state->gnutls_internals.auth_struct->gnutls_generate_server_kx2 != NULL) {
+ if (state->gnutls_internals.auth_struct->gnutls_generate_server_kx2 == NULL)
+ return 0;
+
+ data = NULL;
+ data_size = 0;
+
+ if (again == 0) {
data_size = state->gnutls_internals.auth_struct->gnutls_generate_server_kx2( state, &data);
if (data_size<0) {
gnutls_assert();
return data_size;
}
+ }
- ret = _gnutls_send_handshake(cd, state, data, data_size, GNUTLS_SERVER_KEY_EXCHANGE);
- gnutls_free(data);
- if (ret<0) {
- gnutls_assert();
- return ret;
- }
+ ret = _gnutls_send_handshake(cd, state, data, data_size, GNUTLS_SERVER_KEY_EXCHANGE);
+ gnutls_free(data);
+ if (ret<0) {
+ gnutls_assert();
+ return ret;
}
+
return data_size;
}
/* This is the function for the client to send the key
* exchange message
*/
-int _gnutls_send_client_kx_message(SOCKET cd, GNUTLS_STATE state)
+int _gnutls_send_client_kx_message(SOCKET cd, GNUTLS_STATE state, int again)
{
uint8 *data;
int data_size;
@@ -185,12 +201,17 @@ int _gnutls_send_client_kx_message(SOCKET cd, GNUTLS_STATE state)
if (state->gnutls_internals.auth_struct->gnutls_generate_client_kx==NULL)
return 0;
- data_size = state->gnutls_internals.auth_struct->gnutls_generate_client_kx( state, &data);
- if (data_size < 0) {
- gnutls_assert();
- return data_size;
- }
+ data = NULL;
+ data_size = 0;
+
+ if (again == 0) {
+ data_size = state->gnutls_internals.auth_struct->gnutls_generate_client_kx( state, &data);
+ if (data_size < 0) {
+ gnutls_assert();
+ return data_size;
+ }
+ }
ret = _gnutls_send_handshake(cd, state, data, data_size, GNUTLS_CLIENT_KEY_EXCHANGE);
gnutls_free(data);
@@ -204,7 +225,7 @@ int _gnutls_send_client_kx_message(SOCKET cd, GNUTLS_STATE state)
/* Only used in SRP currently
*/
-int _gnutls_send_client_kx_message0(SOCKET cd, GNUTLS_STATE state)
+int _gnutls_send_client_kx_message0(SOCKET cd, GNUTLS_STATE state, int again)
{
uint8 *data;
int data_size;
@@ -213,12 +234,18 @@ int _gnutls_send_client_kx_message0(SOCKET cd, GNUTLS_STATE state)
if ( state->gnutls_internals.auth_struct->gnutls_generate_client_kx0 == NULL)
return 0;
- data_size = state->gnutls_internals.auth_struct->gnutls_generate_client_kx0( state, &data);
- if (data_size < 0) {
- gnutls_assert();
- return data_size;
- }
+ data = NULL;
+ data_size = 0;
+
+ if (again == 0) {
+ data_size = state->gnutls_internals.auth_struct->gnutls_generate_client_kx0( state, &data);
+
+ if (data_size < 0) {
+ gnutls_assert();
+ return data_size;
+ }
+ }
ret = _gnutls_send_handshake(cd, state, data, data_size, GNUTLS_CLIENT_KEY_EXCHANGE);
gnutls_free(data);
@@ -229,7 +256,7 @@ int _gnutls_send_client_kx_message0(SOCKET cd, GNUTLS_STATE state)
/* This is the function for the client to send the certificate
* verify message
*/
-int _gnutls_send_client_certificate_verify(SOCKET cd, GNUTLS_STATE state)
+int _gnutls_send_client_certificate_verify(SOCKET cd, GNUTLS_STATE state, int again)
{
uint8 *data;
int ret = 0;
@@ -251,14 +278,19 @@ int _gnutls_send_client_certificate_verify(SOCKET cd, GNUTLS_STATE state)
*/
}
- data_size = state->gnutls_internals.auth_struct->gnutls_generate_client_cert_vrfy( state, &data);
- if (data_size < 0) {
- gnutls_assert();
- return data_size;
- }
- if (data_size == 0)
- return 0;
+ data = NULL;
+ data_size = 0;
+ if (again == 0) {
+ data_size = state->gnutls_internals.auth_struct->gnutls_generate_client_cert_vrfy( state, &data);
+ if (data_size < 0) {
+ gnutls_assert();
+ return data_size;
+ }
+ if (data_size == 0)
+ return 0;
+
+ }
ret =
_gnutls_send_handshake(cd, state, data,
data_size,
@@ -402,7 +434,7 @@ int _gnutls_recv_client_kx_message0(SOCKET cd, GNUTLS_STATE state)
/* This is called when we want send our certificate
*/
-int _gnutls_send_client_certificate(SOCKET cd, GNUTLS_STATE state)
+int _gnutls_send_client_certificate(SOCKET cd, GNUTLS_STATE state, int again)
{
uint8 *data = NULL;
int data_size = 0;
@@ -415,14 +447,17 @@ int _gnutls_send_client_certificate(SOCKET cd, GNUTLS_STATE state)
if (state->gnutls_internals.auth_struct->gnutls_generate_client_certificate==NULL)
return 0;
+ data = NULL;
+ data_size = 0;
- data_size = state->gnutls_internals.auth_struct->gnutls_generate_client_certificate( state, &data);
+ if (again == 0) {
+ data_size = state->gnutls_internals.auth_struct->gnutls_generate_client_certificate( state, &data);
- if (data_size < 0) {
- gnutls_assert();
- return data_size;
+ if (data_size < 0) {
+ gnutls_assert();
+ return data_size;
+ }
}
-
ret = _gnutls_send_handshake(cd, state, data, data_size, GNUTLS_CERTIFICATE);
gnutls_free(data);
@@ -437,7 +472,7 @@ int _gnutls_send_client_certificate(SOCKET cd, GNUTLS_STATE state)
/* This is called when we want send our certificate
*/
-int _gnutls_send_server_certificate(SOCKET cd, GNUTLS_STATE state)
+int _gnutls_send_server_certificate(SOCKET cd, GNUTLS_STATE state, int again)
{
uint8 *data = NULL;
int data_size = 0;
@@ -447,13 +482,17 @@ int _gnutls_send_server_certificate(SOCKET cd, GNUTLS_STATE state)
if (state->gnutls_internals.auth_struct->gnutls_generate_server_certificate==NULL)
return 0;
- data_size = state->gnutls_internals.auth_struct->gnutls_generate_server_certificate( state, &data);
+ data = NULL;
+ data_size = 0;
- if (data_size < 0) {
- gnutls_assert();
- return data_size;
- }
+ if (again == 0) {
+ data_size = state->gnutls_internals.auth_struct->gnutls_generate_server_certificate( state, &data);
+ if (data_size < 0) {
+ gnutls_assert();
+ return data_size;
+ }
+ }
ret = _gnutls_send_handshake(cd, state, data, data_size, GNUTLS_CERTIFICATE);
gnutls_free(data);
diff --git a/lib/gnutls_kx.h b/lib/gnutls_kx.h
index a84ff0b4be..0bf69a7188 100644
--- a/lib/gnutls_kx.h
+++ b/lib/gnutls_kx.h
@@ -18,21 +18,21 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
-int _gnutls_send_server_kx_message(int cd, GNUTLS_STATE state);
-int _gnutls_send_server_kx_message2(int cd, GNUTLS_STATE state);
-int _gnutls_send_client_kx_message(int cd, GNUTLS_STATE state);
-int _gnutls_send_client_kx_message0(int cd, GNUTLS_STATE state);
+int _gnutls_send_server_kx_message(int cd, GNUTLS_STATE state, int again);
+int _gnutls_send_server_kx_message2(int cd, GNUTLS_STATE state, int again);
+int _gnutls_send_client_kx_message(int cd, GNUTLS_STATE state, int again);
+int _gnutls_send_client_kx_message0(int cd, GNUTLS_STATE state, int again);
int _gnutls_recv_server_kx_message(int cd, GNUTLS_STATE state);
int _gnutls_recv_server_kx_message2(int cd, GNUTLS_STATE state);
int _gnutls_recv_client_kx_message(int cd, GNUTLS_STATE state);
int _gnutls_recv_client_kx_message0(int cd, GNUTLS_STATE state);
-int _gnutls_send_client_certificate_verify(int cd, GNUTLS_STATE state);
-int _gnutls_send_server_certificate(int cd, GNUTLS_STATE state);
+int _gnutls_send_client_certificate_verify(int cd, GNUTLS_STATE state, int again);
+int _gnutls_send_server_certificate(int cd, GNUTLS_STATE state, int again);
int _gnutls_generate_master( GNUTLS_STATE state);
int _gnutls_recv_client_certificate(SOCKET cd, GNUTLS_STATE state);
int _gnutls_recv_server_certificate(SOCKET cd, GNUTLS_STATE state);
-int _gnutls_send_client_certificate(SOCKET cd, GNUTLS_STATE state);
+int _gnutls_send_client_certificate(SOCKET cd, GNUTLS_STATE state, int again);
int _gnutls_recv_server_certificate_request(SOCKET cd, GNUTLS_STATE state);
-int _gnutls_send_server_certificate_request(SOCKET cd, GNUTLS_STATE state);
+int _gnutls_send_server_certificate_request(SOCKET cd, GNUTLS_STATE state, int again);
int _gnutls_recv_client_certificate_verify_message(SOCKET cd, GNUTLS_STATE state);
diff --git a/lib/gnutls_record.c b/lib/gnutls_record.c
index d741d21f96..2dbc34a88e 100644
--- a/lib/gnutls_record.c
+++ b/lib/gnutls_record.c
@@ -81,6 +81,7 @@ int gnutls_init(GNUTLS_STATE * state, ConnectionEnd con_end)
{
*state = gnutls_calloc(1, sizeof(struct GNUTLS_STATE_INT));
+ if (*state==NULL) return GNUTLS_E_MEMORY_ERROR;
(*state)->security_parameters.entity = con_end;
@@ -99,6 +100,10 @@ int gnutls_init(GNUTLS_STATE * state, ConnectionEnd con_end)
gnutls_set_protocol_priority( *state, GNUTLS_TLS1, 0); /* default */
(*state)->gnutls_key = gnutls_calloc(1, sizeof(struct GNUTLS_KEY_INT));
+ if ( (*state)->gnutls_key == NULL) {
+ gnutls_free( *state);
+ return GNUTLS_E_MEMORY_ERROR;
+ }
(*state)->gnutls_internals.resumed = RESUME_FALSE;
@@ -225,6 +230,10 @@ static svoid *gnutls_P_hash( MACAlgorithm algorithm, opaque * secret, int secret
}
ret = secure_calloc(1, total_bytes);
+ if (ret==NULL) {
+ gnutls_assert();
+ return ret;
+ }
blocksize = gnutls_hmac_get_algo_len(algorithm);
do {
@@ -436,14 +445,16 @@ ssize_t gnutls_send_int(SOCKET cd, GNUTLS_STATE state, ContentType type, Handsha
const uint8 *data=_data;
GNUTLS_Version lver;
- if (sizeofdata == 0)
- return 0;
-
+ if (sizeofdata == 0 || _data==NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_PARAMETERS;
+ }
+
if (state->gnutls_internals.valid_connection == VALID_FALSE || state->gnutls_internals.may_write != 0) {
gnutls_assert();
return GNUTLS_E_INVALID_SESSION;
}
-
+
headers[0]=type;
if (htype==GNUTLS_CLIENT_HELLO) { /* then send the lowest
@@ -467,14 +478,11 @@ ssize_t gnutls_send_int(SOCKET cd, GNUTLS_STATE state, ContentType type, Handsha
(int) uint64touint32(&state->connection_state.write_sequence_number), _gnutls_packet2str(type), type, sizeofdata);
#endif
- /* in this loop we encrypt all data that are a multiple
- * of the MAC_ENC_LEN;
- */
data2send = sizeofdata;
ptr = data;
retval = 0;
- while( data2send != 0) {
+ while( data2send > 0) {
if (data2send - MAX_ENC_LEN >= 0) {
data2send -= MAX_ENC_LEN;
@@ -512,7 +520,10 @@ ssize_t gnutls_send_int(SOCKET cd, GNUTLS_STATE state, ContentType type, Handsha
* that value.
*/
gnutls_assert();
- if (retval > 0) return retval;
+ if (retval > 0) {
+ gnutls_assert();
+ return retval;
+ }
return ret;
}
state->gnutls_internals.valid_connection = VALID_FALSE;
@@ -588,7 +599,7 @@ ssize_t gnutls_recv_int(SOCKET cd, GNUTLS_STATE state, ContentType type, Handsha
uint16 length;
uint8 *ciphertext;
uint8 *recv_data;
- int ret;
+ int ret, ret2;
int header_size;
begin:
@@ -596,8 +607,10 @@ ssize_t gnutls_recv_int(SOCKET cd, GNUTLS_STATE state, ContentType type, Handsha
header_size = RECORD_HEADER_SIZE;
ret = 0;
- if (sizeofdata == 0)
- return 0;
+ if (sizeofdata == 0 || data == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_PARAMETERS;
+ }
if (state->gnutls_internals.valid_connection == VALID_FALSE || state->gnutls_internals.may_read!=0) {
gnutls_assert();
@@ -612,7 +625,10 @@ ssize_t gnutls_recv_int(SOCKET cd, GNUTLS_STATE state, ContentType type, Handsha
/* if the buffer just got empty */
if (gnutls_getDataBufferSize(type, state)==0) {
- _gnutls_clear_peeked_data( cd, state);
+ if ( (ret2=_gnutls_clear_peeked_data( cd, state)) < 0) {
+ gnutls_assert();
+ return ret2;
+ }
}
return ret;
@@ -622,7 +638,7 @@ ssize_t gnutls_recv_int(SOCKET cd, GNUTLS_STATE state, ContentType type, Handsha
* must be set to non blocking mode
*/
if ( (ret = _gnutls_read_buffered(cd, state, &headers, header_size, -1)) != header_size) {
- if (ret<0 && gnutls_is_fatal_error(ret)==0) return ret;
+ if (ret < 0 && gnutls_is_fatal_error(ret)==0) return ret;
state->gnutls_internals.valid_connection = VALID_FALSE;
if (type==GNUTLS_ALERT) {
@@ -859,7 +875,10 @@ ssize_t gnutls_recv_int(SOCKET cd, GNUTLS_STATE state, ContentType type, Handsha
/* if the buffer just got empty */
if (gnutls_getDataBufferSize(type, state)==0) {
- _gnutls_clear_peeked_data( cd, state);
+ if ( (ret2 = _gnutls_clear_peeked_data( cd, state)) < 0) {
+ gnutls_assert();
+ return ret2;
+ }
}
gnutls_free(tmpdata);