diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/gnutls_buffers.c | 26 | ||||
-rw-r--r-- | lib/gnutls_handshake.c | 444 | ||||
-rw-r--r-- | lib/gnutls_handshake.h | 2 | ||||
-rw-r--r-- | lib/gnutls_int.h | 7 | ||||
-rw-r--r-- | lib/gnutls_kx.c | 143 | ||||
-rw-r--r-- | lib/gnutls_kx.h | 16 | ||||
-rw-r--r-- | lib/gnutls_record.c | 49 |
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); |