summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2012-08-06 17:54:50 +0200
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2012-08-06 18:04:16 +0200
commit5cd6ecd192636509a4dd66bdd295ebe19fc67b6c (patch)
tree4c4ed190be38827028e41a2f6668932437382d51
parentafab4ff9bdf459f02d73ec6ffabb1b15a633c84b (diff)
downloadgnutls-5cd6ecd192636509a4dd66bdd295ebe19fc67b6c.tar.gz
Added gnutls_handshake_timeout().
-rw-r--r--NEWS3
-rw-r--r--doc/Makefile.am2
-rw-r--r--doc/cha-gtls-app.texi2
-rw-r--r--doc/examples/ex-client-anon.c2
-rw-r--r--doc/examples/ex-client-dtls.c2
-rw-r--r--doc/examples/ex-client-psk.c2
-rw-r--r--doc/examples/ex-client-resume.c2
-rw-r--r--doc/examples/ex-client-srp.c2
-rw-r--r--doc/examples/ex-client-x509.c2
-rw-r--r--lib/gnutls_buffers.c59
-rw-r--r--lib/gnutls_buffers.h4
-rw-r--r--lib/gnutls_handshake.c22
-rw-r--r--lib/gnutls_int.h2
-rw-r--r--lib/gnutls_record.c32
-rw-r--r--lib/includes/gnutls/gnutls.h.in3
-rw-r--r--lib/libgnutls.map1
-rw-r--r--src/cli.c2
17 files changed, 117 insertions, 27 deletions
diff --git a/NEWS b/NEWS
index aedb25af0f..2abf67e9f8 100644
--- a/NEWS
+++ b/NEWS
@@ -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 {
diff --git a/src/cli.c b/src/cli.c
index 106c6173d3..755ca1fde6 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -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)
{