From: Nikos Mavrogiannopoulos Date: Sat, 12 Mar 2011 21:52:07 +0000 (+0100) Subject: Corrected SSL2 client hello handling. X-Git-Tag: gnutls_2_99_0~133 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3387c6872c26a1e8fbb8cfd12d6a3372795befd4;p=thirdparty%2Fgnutls.git Corrected SSL2 client hello handling. --- diff --git a/lib/debug.c b/lib/debug.c index f5eb466d53..14ec82f1f8 100644 --- a/lib/debug.c +++ b/lib/debug.c @@ -75,6 +75,9 @@ _gnutls_handshake2str (gnutls_handshake_description_t handshake) case GNUTLS_HANDSHAKE_CLIENT_HELLO: return "CLIENT HELLO"; break; + case GNUTLS_HANDSHAKE_CLIENT_HELLO_V2: + return "SSL2 CLIENT HELLO"; + break; case GNUTLS_HANDSHAKE_SERVER_HELLO: return "SERVER HELLO"; break; diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c index c66f1124ad..645d78de55 100644 --- a/lib/gnutls_buffers.c +++ b/lib/gnutls_buffers.c @@ -745,15 +745,14 @@ parse_handshake_header (gnutls_session_t session, mbuffer_st* bufel, gnutls_hand return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); dataptr = _mbuffer_get_udata_ptr(bufel); - /* if reading a client hello of SSLv2 */ if (!IS_DTLS(session) && htype == GNUTLS_HANDSHAKE_CLIENT_HELLO && bufel->htype == GNUTLS_HANDSHAKE_CLIENT_HELLO_V2) { - hsk->length = _mbuffer_get_udata_size(bufel) - SSL2_HEADERS; /* we've read the first byte */ - handshake_header_size = SSL2_HEADERS; /* we've already read one byte */ + hsk->length = _mbuffer_get_udata_size(bufel) - handshake_header_size; /* we've read the first byte */ + if (dataptr[0] != GNUTLS_HANDSHAKE_CLIENT_HELLO) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET); @@ -892,6 +891,17 @@ int ret; return 0; } +/* returns non-zero on match and zero on mismatch + */ +inline static int cmp_hsk_types(gnutls_handshake_description_t expected, gnutls_handshake_description_t recvd) +{ + if ((expected != GNUTLS_HANDSHAKE_CLIENT_HELLO || recvd != GNUTLS_HANDSHAKE_CLIENT_HELLO_V2) && + (expected != recvd)) + return 0; + + return 1; +} + #define LAST_ELEMENT (session->internals.handshake_recv_buffer_size-1) /* returns the last stored handshake packet. @@ -929,7 +939,7 @@ handshake_buffer_st* recv_buf = session->internals.handshake_recv_buffer; { if (session->internals.handshake_recv_buffer_size > 0 && recv_buf[0].length == recv_buf[0].data.length) { - if (recv_buf[0].htype != htype) + if (cmp_hsk_types(htype, recv_buf[0].htype) == 0) { hsk->htype = recv_buf[LAST_ELEMENT].htype; return gnutls_assert_val(GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET); @@ -940,15 +950,15 @@ handshake_buffer_st* recv_buf = session->internals.handshake_recv_buffer; return 0; } else - return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } } /* This is a receive function for the gnutls handshake * protocol. Makes sure that we have received all data. */ -ssize_t -_gnutls_handshake_io_recv_int (gnutls_session_t session, +static int +parse_record_buffered_msgs (gnutls_session_t session, gnutls_handshake_description_t htype, handshake_buffer_st * hsk) { @@ -958,19 +968,9 @@ _gnutls_handshake_io_recv_int (gnutls_session_t session, size_t data_size; handshake_buffer_st* recv_buf = session->internals.handshake_recv_buffer; - ret = get_last_packet(session, htype, hsk); - if (ret >= 0) - return ret; - - /* if we don't have a complete message waiting for us, try - * receiving more */ - ret = _gnutls_recv_in_buffers(session, GNUTLS_HANDSHAKE, htype); - if (ret < 0) - return gnutls_assert_val(ret); - bufel = _mbuffer_head_get_first(&session->internals.record_buffer, &msg); if (bufel == NULL) - return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; if (!IS_DTLS(session)) { @@ -1018,7 +1018,8 @@ _gnutls_handshake_io_recv_int (gnutls_session_t session, _mbuffer_head_remove_bytes(&session->internals.record_buffer, data_size+header_size); - if (htype != recv_buf[0].htype) + + if (cmp_hsk_types(htype, recv_buf[0].htype) == 0) { /* an unexpected packet */ hsk->htype = recv_buf[0].htype; return gnutls_assert_val(GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET); @@ -1117,6 +1118,40 @@ next: } } +/* This is a receive function for the gnutls handshake + * protocol. Makes sure that we have received all data. + */ +ssize_t +_gnutls_handshake_io_recv_int (gnutls_session_t session, + gnutls_handshake_description_t htype, + handshake_buffer_st * hsk) +{ + gnutls_datum_t msg; + mbuffer_st* bufel = NULL, *prev = NULL; + int ret; + size_t data_size; + handshake_buffer_st* recv_buf = session->internals.handshake_recv_buffer; + + ret = get_last_packet(session, htype, hsk); + if (ret >= 0) + return ret; + + /* try using the already existing records before + * trying to receive. + */ + ret = parse_record_buffered_msgs(session, htype, hsk); + if (ret >= 0) + return ret; + + /* if we don't have a complete message waiting for us, try + * receiving more */ + ret = _gnutls_recv_in_buffers(session, GNUTLS_HANDSHAKE, htype); + if (ret < 0) + return gnutls_assert_val(ret); + + return parse_record_buffered_msgs(session, htype, hsk); +} + /* Buffer for handshake packets. Keeps the packets in order * for finished messages to use them. Used in HMAC calculation * and finished messages. diff --git a/lib/gnutls_constate.c b/lib/gnutls_constate.c index 33548e0008..90372d9b75 100644 --- a/lib/gnutls_constate.c +++ b/lib/gnutls_constate.c @@ -675,7 +675,7 @@ epoch_get_slot (gnutls_session_t session, uint16_t epoch) if (epoch_index >= MAX_EPOCH_INDEX) { - _gnutls_dtls_log("Epoch %d out of range (idx: %d, max: %d)\n", (int)epoch, (int)epoch_index, MAX_EPOCH_INDEX); + _gnutls_handshake_log("Epoch %d out of range (idx: %d, max: %d)\n", (int)epoch, (int)epoch_index, MAX_EPOCH_INDEX); gnutls_assert (); return NULL; } diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c index a95b2076b7..ba592719ee 100644 --- a/lib/gnutls_handshake.c +++ b/lib/gnutls_handshake.c @@ -1045,8 +1045,7 @@ _gnutls_server_select_comp_method (gnutls_session_t session, return x; } - memset (&session->internals.compression_method, 0, - sizeof (gnutls_compression_method_t)); + session->internals.compression_method = 0; for (j = 0; j < datalen; j++) { @@ -1284,7 +1283,7 @@ _gnutls_handshake_hash_add_recvd (gnutls_session_t session, if ((session->security_parameters.entity == GNUTLS_SERVER || recv_type != GNUTLS_HANDSHAKE_SERVER_HELLO) && (session->security_parameters.entity == GNUTLS_CLIENT - || recv_type != GNUTLS_HANDSHAKE_CLIENT_HELLO)) + || (recv_type != GNUTLS_HANDSHAKE_CLIENT_HELLO && recv_type != GNUTLS_HANDSHAKE_CLIENT_HELLO_V2))) { if ((ret = _gnutls_handshake_hash_pending (session)) < 0) { @@ -2571,10 +2570,7 @@ gnutls_handshake (gnutls_session_t session) _gnutls_epoch_alloc (session, session->security_parameters.epoch_next, NULL); if (ret < 0) - { - gnutls_assert (); - return ret; - } + return gnutls_assert_val(ret); } if (session->security_parameters.entity == GNUTLS_CLIENT) diff --git a/lib/gnutls_record.c b/lib/gnutls_record.c index e7a70362b9..fa47d12fb0 100644 --- a/lib/gnutls_record.c +++ b/lib/gnutls_record.c @@ -349,17 +349,11 @@ _gnutls_send_int (gnutls_session_t session, content_type_t type, ret = _gnutls_epoch_get (session, epoch_rel, &record_params); if (ret < 0) - { - gnutls_assert (); - return ret; - } + return gnutls_assert_val(ret); /* Safeguard against processing data with an incomplete cipher state. */ if (!record_params->initialized) - { - gnutls_assert (); - return GNUTLS_E_INVALID_REQUEST; - } + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); record_state = &record_params->write; @@ -782,7 +776,7 @@ record_read_headers (gnutls_session_t session, record->length = (((headers[0] & 0x7f) << 8)) | headers[1]; /* SSL 2.0 headers */ - record->header_size = 2; + record->header_size = record->packet_size = 2; record->type = GNUTLS_HANDSHAKE; /* we accept only v2 client hello */ diff --git a/lib/gnutls_v2_compat.c b/lib/gnutls_v2_compat.c index abc17b7e4b..9d78287efe 100644 --- a/lib/gnutls_v2_compat.c +++ b/lib/gnutls_v2_compat.c @@ -42,6 +42,7 @@ #include "gnutls_extensions.h" #include "gnutls_auth.h" #include "gnutls_v2_compat.h" +#include "gnutls_constate.h" /* This selects the best supported ciphersuite from the ones provided */ static int @@ -250,6 +251,7 @@ _gnutls_read_client_hello_v2 (gnutls_session_t session, opaque * data, } session->internals.compression_method = GNUTLS_COMP_NULL; + _gnutls_epoch_set_compression (session, EPOCH_NEXT, session->internals.compression_method); return 0; }