diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2012-08-06 17:54:50 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2012-08-06 18:04:16 +0200 |
commit | 5cd6ecd192636509a4dd66bdd295ebe19fc67b6c (patch) | |
tree | 4c4ed190be38827028e41a2f6668932437382d51 | |
parent | afab4ff9bdf459f02d73ec6ffabb1b15a633c84b (diff) | |
download | gnutls-5cd6ecd192636509a4dd66bdd295ebe19fc67b6c.tar.gz |
Added gnutls_handshake_timeout().
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | doc/Makefile.am | 2 | ||||
-rw-r--r-- | doc/cha-gtls-app.texi | 2 | ||||
-rw-r--r-- | doc/examples/ex-client-anon.c | 2 | ||||
-rw-r--r-- | doc/examples/ex-client-dtls.c | 2 | ||||
-rw-r--r-- | doc/examples/ex-client-psk.c | 2 | ||||
-rw-r--r-- | doc/examples/ex-client-resume.c | 2 | ||||
-rw-r--r-- | doc/examples/ex-client-srp.c | 2 | ||||
-rw-r--r-- | doc/examples/ex-client-x509.c | 2 | ||||
-rw-r--r-- | lib/gnutls_buffers.c | 59 | ||||
-rw-r--r-- | lib/gnutls_buffers.h | 4 | ||||
-rw-r--r-- | lib/gnutls_handshake.c | 22 | ||||
-rw-r--r-- | lib/gnutls_int.h | 2 | ||||
-rw-r--r-- | lib/gnutls_record.c | 32 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 3 | ||||
-rw-r--r-- | lib/libgnutls.map | 1 | ||||
-rw-r--r-- | src/cli.c | 2 |
17 files changed, 117 insertions, 27 deletions
@@ -2,7 +2,7 @@ GnuTLS NEWS -- History of user-visible changes. -*- outline -*- Copyright (C) 2000-2012 Free Software Foundation, Inc. See the end for copying conditions. -* Version 3.1.0pre0 (released 2012-08-05) +* Version 3.1.0 (unreleased) ** libgnutls: Added direct support for TPM as a cryptographic module in gnutls/tpm.h. @@ -84,6 +84,7 @@ gnutls_x509_trust_list_add_system_trust: Added gnutls_x509_trust_list_add_trust_file: Added gnutls_x509_trust_list_add_trust_mem: Added gnutls_pk_to_sign: Added +gnutls_handshake_timeout: Added gnutls_pubkey_verify_hash: Deprecated (use gnutls_pubkey_verify_hash2) gnutls_pubkey_verify_data: Deprecated (use gnutls_pubkey_verify_data2) diff --git a/doc/Makefile.am b/doc/Makefile.am index ff5edf2e59..a8dfa6e9f9 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -766,6 +766,8 @@ FUNCS += functions/gnutls_bye FUNCS += functions/gnutls_bye.short FUNCS += functions/gnutls_handshake FUNCS += functions/gnutls_handshake.short +FUNCS += functions/gnutls_handshake_timeout +FUNCS += functions/gnutls_handshake_timeout.short FUNCS += functions/gnutls_rehandshake FUNCS += functions/gnutls_rehandshake.short FUNCS += functions/gnutls_alert_get diff --git a/doc/cha-gtls-app.texi b/doc/cha-gtls-app.texi index ea2dfb8e61..45d4ef02d8 100644 --- a/doc/cha-gtls-app.texi +++ b/doc/cha-gtls-app.texi @@ -733,6 +733,8 @@ exchange. @showfuncdesc{gnutls_handshake} +@showfuncdesc{gnutls_handshake_timeout} + The handshake process doesn't ensure the verification of the peer's identity. When certificates are in use, this can be done, either after the handshake is complete, or during diff --git a/doc/examples/ex-client-anon.c b/doc/examples/ex-client-anon.c index ba56934461..b4befa88e0 100644 --- a/doc/examples/ex-client-anon.c +++ b/doc/examples/ex-client-anon.c @@ -57,7 +57,7 @@ main (void) */ do { - ret = gnutls_handshake (session); + ret = gnutls_handshake_timeout (session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); } while (ret < 0 && gnutls_error_is_fatal (ret) == 0); diff --git a/doc/examples/ex-client-dtls.c b/doc/examples/ex-client-dtls.c index 21e7244a56..6b97ba619b 100644 --- a/doc/examples/ex-client-dtls.c +++ b/doc/examples/ex-client-dtls.c @@ -73,7 +73,7 @@ main (void) /* Perform the TLS handshake */ do { - ret = gnutls_handshake (session); + ret = gnutls_handshake_timeout (session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); } while (ret < 0 && gnutls_error_is_fatal (ret) == 0); diff --git a/doc/examples/ex-client-psk.c b/doc/examples/ex-client-psk.c index 63366c2f35..f77e3a3cfa 100644 --- a/doc/examples/ex-client-psk.c +++ b/doc/examples/ex-client-psk.c @@ -67,7 +67,7 @@ main (void) */ do { - ret = gnutls_handshake (session); + ret = gnutls_handshake_timeout (session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); } while (ret < 0 && gnutls_error_is_fatal (ret) == 0); diff --git a/doc/examples/ex-client-resume.c b/doc/examples/ex-client-resume.c index c09495007c..13b42e488f 100644 --- a/doc/examples/ex-client-resume.c +++ b/doc/examples/ex-client-resume.c @@ -65,7 +65,7 @@ main (void) */ do { - ret = gnutls_handshake (session); + ret = gnutls_handshake_timeout (session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); } while (ret < 0 && gnutls_error_is_fatal (ret) == 0); diff --git a/doc/examples/ex-client-srp.c b/doc/examples/ex-client-srp.c index 77840758e9..afc6c09432 100644 --- a/doc/examples/ex-client-srp.c +++ b/doc/examples/ex-client-srp.c @@ -64,7 +64,7 @@ main (void) */ do { - ret = gnutls_handshake (session); + ret = gnutls_handshake_timeout (session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); } while (ret < 0 && gnutls_error_is_fatal (ret) == 0); diff --git a/doc/examples/ex-client-x509.c b/doc/examples/ex-client-x509.c index 2a78e2da17..2535230472 100644 --- a/doc/examples/ex-client-x509.c +++ b/doc/examples/ex-client-x509.c @@ -82,7 +82,7 @@ int main (void) */ do { - ret = gnutls_handshake (session); + ret = gnutls_handshake_timeout (session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); } while (ret < 0 && gnutls_error_is_fatal (ret) == 0); diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c index 5d1f3f50b3..4c4f9e32de 100644 --- a/lib/gnutls_buffers.c +++ b/lib/gnutls_buffers.c @@ -174,7 +174,7 @@ int errno_to_gerr(int err) static ssize_t _gnutls_dgram_read (gnutls_session_t session, mbuffer_st **bufel, - gnutls_pull_func pull_func) + gnutls_pull_func pull_func, unsigned int ms) { ssize_t i, ret; uint8_t *ptr; @@ -185,14 +185,21 @@ _gnutls_dgram_read (gnutls_session_t session, mbuffer_st **bufel, if (recv_size > max_size) recv_size = max_size; + session->internals.direction = 0; + + if (ms) + { + ret = _gnutls_io_check_recv(session, ms); + if (ret < 0) + return gnutls_assert_val(ret); + } + *bufel = _mbuffer_alloc (0, max_size); if (*bufel == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); ptr = (*bufel)->msg.data; - - session->internals.direction = 0; - + reset_errno (session); i = pull_func (fd, ptr, recv_size); @@ -232,13 +239,18 @@ cleanup: static ssize_t _gnutls_stream_read (gnutls_session_t session, mbuffer_st **bufel, - size_t size, gnutls_pull_func pull_func) + size_t size, gnutls_pull_func pull_func, unsigned int ms) { size_t left; ssize_t i = 0; size_t max_size = _gnutls_get_max_decrypted_data(session); uint8_t *ptr; gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr; + int ret; + struct timespec t1, t2; + unsigned int diff; + + session->internals.direction = 0; *bufel = _mbuffer_alloc (0, MAX(max_size, size)); if (!*bufel) @@ -248,11 +260,18 @@ _gnutls_stream_read (gnutls_session_t session, mbuffer_st **bufel, } ptr = (*bufel)->msg.data; - session->internals.direction = 0; - left = size; while (left > 0) { + if (ms) + { + ret = _gnutls_io_check_recv(session, ms); + if (ret < 0) + return gnutls_assert_val(ret); + + gettime(&t1); + } + reset_errno (session); i = pull_func (fd, &ptr[size - left], left); @@ -291,9 +310,19 @@ _gnutls_stream_read (gnutls_session_t session, mbuffer_st **bufel, if (i == 0) break; /* EOF */ } - + left -= i; (*bufel)->msg.size += i; + + if (ms && left) + { + gettime(&t2); + diff = _dtls_timespec_sub_ms(&t2, &t1); + if (diff < ms) + ms -= diff; + else + return gnutls_assert_val(GNUTLS_E_TIMEDOUT); + } } finish: @@ -312,13 +341,13 @@ finish: */ static ssize_t _gnutls_read (gnutls_session_t session, mbuffer_st **bufel, - size_t size, gnutls_pull_func pull_func) + size_t size, gnutls_pull_func pull_func, unsigned int ms) { if (IS_DTLS (session)) /* Size is not passed, since a whole datagram will be read. */ - return _gnutls_dgram_read (session, bufel, pull_func); + return _gnutls_dgram_read (session, bufel, pull_func, ms); else - return _gnutls_stream_read (session, bufel, size, pull_func); + return _gnutls_stream_read (session, bufel, size, pull_func, ms); } static ssize_t @@ -381,10 +410,13 @@ _gnutls_writev (gnutls_session_t session, const giovec_t * giovec, * This is not a general purpose function. It returns EXACTLY the data requested, * which are stored in a local (in the session) buffer. * + * If the @ms parameter is non zero then this function will return before + * the given amount of milliseconds or return GNUTLS_E_TIMEDOUT. + * */ ssize_t _gnutls_io_read_buffered (gnutls_session_t session, size_t total, - content_type_t recv_type) + content_type_t recv_type, unsigned int ms) { ssize_t ret = 0; size_t min; @@ -440,7 +472,7 @@ _gnutls_io_read_buffered (gnutls_session_t session, size_t total, { ret = _gnutls_read (session, &bufel, readsize, - session->internals.pull_func); + session->internals.pull_func, ms); /* return immediately if we got an interrupt or eagain * error. @@ -1145,6 +1177,7 @@ _gnutls_handshake_io_recv_int (gnutls_session_t session, handshake_buffer_st * hsk, unsigned int optional) { int ret; + time_t tleft = 0; ret = get_last_packet(session, htype, hsk, optional); if (ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) diff --git a/lib/gnutls_buffers.h b/lib/gnutls_buffers.h index 04a89eb219..52106acf41 100644 --- a/lib/gnutls_buffers.h +++ b/lib/gnutls_buffers.h @@ -53,7 +53,7 @@ record_check_unprocessed (gnutls_session_t session) int _gnutls_record_buffer_get (content_type_t type, gnutls_session_t session, uint8_t * data, size_t length, uint8_t seq[8]); -ssize_t _gnutls_io_read_buffered (gnutls_session_t, size_t n, content_type_t); +ssize_t _gnutls_io_read_buffered (gnutls_session_t, size_t n, content_type_t, unsigned int ms); int _gnutls_io_clear_peeked_data (gnutls_session_t session); ssize_t _gnutls_io_write_buffered (gnutls_session_t session, @@ -109,7 +109,7 @@ _gnutls_parse_record_buffered_msgs (gnutls_session_t session); ssize_t _gnutls_recv_in_buffers (gnutls_session_t session, content_type_t type, - gnutls_handshake_description_t htype); + gnutls_handshake_description_t htype); #define _gnutls_handshake_io_buffer_clear( session) \ _mbuffer_head_clear( &session->internals.handshake_send_buffer); \ diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c index dc2da48e93..3f30e52d39 100644 --- a/lib/gnutls_handshake.c +++ b/lib/gnutls_handshake.c @@ -2364,9 +2364,31 @@ cleanup: int gnutls_handshake (gnutls_session_t session) { + return gnutls_handshake_timeout( session, 0); +} + +/** + * gnutls_handshake_timeout: + * @session: is a #gnutls_session_t structure. + * @sec: is a timeout value in seconds + * + * This function is identical to the gnutls_handshake() but + * it also ensures that the handshake is completed within + * the provided timeout value. + * + * Returns: %GNUTLS_E_SUCCESS on success, %GNUTLS_E_TIMED_OUT on timeout, otherwise a negative error code. + **/ +int +gnutls_handshake_timeout (gnutls_session_t session, unsigned int sec) +{ int ret; record_parameters_st *params; + if (sec > 0) + session->internals.handshake_endtime = gnutls_time(0) + sec; + else + session->internals.handshake_endtime = 0; + /* sanity check. Verify that there are priorities setup. */ if (session->internals.priorities.protocol.algorithms == 0) diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 0f8f8c1b44..e0b324bfdc 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -876,6 +876,8 @@ typedef struct unsigned int cb_tls_unique_len; unsigned char cb_tls_unique[MAX_VERIFY_DATA_SIZE]; + + unsigned int handshake_endtime; /* end time in seconds */ /* If you add anything here, check _gnutls_handshake_internal_state_clear(). */ diff --git a/lib/gnutls_record.c b/lib/gnutls_record.c index fbb84a1447..4eaa79f96a 100644 --- a/lib/gnutls_record.c +++ b/lib/gnutls_record.c @@ -861,7 +861,9 @@ record_read_headers (gnutls_session_t session, static int recv_headers( gnutls_session_t session, content_type_t type, - gnutls_handshake_description_t htype, struct tls_record_st* record) + gnutls_handshake_description_t htype, + struct tls_record_st* record, + unsigned int ms) { int ret; gnutls_datum_t raw; /* raw headers */ @@ -870,7 +872,7 @@ gnutls_datum_t raw; /* raw headers */ record->header_size = record->packet_size = RECORD_HEADER_SIZE(session); if ((ret = - _gnutls_io_read_buffered (session, record->header_size, -1)) != record->header_size) + _gnutls_io_read_buffered (session, record->header_size, -1, ms)) != record->header_size) { if (ret < 0 && gnutls_error_is_fatal (ret) == 0) return ret; @@ -941,6 +943,9 @@ gnutls_datum_t raw; /* raw headers */ /* This will receive record layer packets and add them to * application_data_buffer and handshake_data_buffer. + * + * If the htype is not -1 then handshake timeouts + * will be enforced. */ ssize_t _gnutls_recv_in_buffers (gnutls_session_t session, content_type_t type, @@ -954,6 +959,7 @@ _gnutls_recv_in_buffers (gnutls_session_t session, content_type_t type, record_parameters_st *record_params; record_state_st *record_state; struct tls_record_st record; + time_t now, tleft = 0; begin: @@ -986,8 +992,17 @@ begin: record_state = &record_params->read; + if (htype != -1 && session->internals.handshake_endtime > 0) + { + now = gnutls_time(0); + if (now < session->internals.handshake_endtime) + tleft = (session->internals.handshake_endtime - now) * 1000; + else + return gnutls_assert_val(GNUTLS_E_TIMEDOUT); + } + /* receive headers */ - ret = recv_headers(session, type, htype, &record); + ret = recv_headers(session, type, htype, &record, tleft); if (ret < 0) { ret = gnutls_assert_val_fatal(ret); @@ -999,11 +1014,20 @@ begin: else packet_sequence = &record_state->sequence_number; + if (htype != -1 && session->internals.handshake_endtime > 0) + { + now = gnutls_time(0); + if (now < session->internals.handshake_endtime) + tleft = (session->internals.handshake_endtime - now) * 1000; + else + return gnutls_assert_val(GNUTLS_E_TIMEDOUT); + } + /* Read the packet data and insert it to record_recv_buffer. */ ret = _gnutls_io_read_buffered (session, record.packet_size, - record.type); + record.type, tleft); if (ret != record.packet_size) { gnutls_assert(); diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index 25cb1ea100..823f1d7bde 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -751,6 +751,9 @@ typedef enum int gnutls_bye (gnutls_session_t session, gnutls_close_request_t how); int gnutls_handshake (gnutls_session_t session); + +#define GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT 60 + int gnutls_handshake_timeout (gnutls_session_t session, unsigned int sec); int gnutls_rehandshake (gnutls_session_t session); gnutls_alert_description_t gnutls_alert_get (gnutls_session_t session); diff --git a/lib/libgnutls.map b/lib/libgnutls.map index 19f63c3ce8..801c6357ac 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -825,6 +825,7 @@ GNUTLS_3_1_0 { gnutls_pkcs11_privkey_set_pin_function; gnutls_certificate_set_pin_function; gnutls_x509_crt_set_pin_function; + gnutls_handshake_timeout; } GNUTLS_3_0_0; GNUTLS_PRIVATE { @@ -1183,7 +1183,7 @@ do_handshake (socket_st * socket) gl_fd_to_handle (socket->fd)); do { - ret = gnutls_handshake (socket->session); + ret = gnutls_handshake_timeout (socket->session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); if (ret < 0) { |