]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added gnutls_handshake_timeout().
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Mon, 6 Aug 2012 15:54:50 +0000 (17:54 +0200)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Mon, 6 Aug 2012 16:04:16 +0000 (18:04 +0200)
17 files changed:
NEWS
doc/Makefile.am
doc/cha-gtls-app.texi
doc/examples/ex-client-anon.c
doc/examples/ex-client-dtls.c
doc/examples/ex-client-psk.c
doc/examples/ex-client-resume.c
doc/examples/ex-client-srp.c
doc/examples/ex-client-x509.c
lib/gnutls_buffers.c
lib/gnutls_buffers.h
lib/gnutls_handshake.c
lib/gnutls_int.h
lib/gnutls_record.c
lib/includes/gnutls/gnutls.h.in
lib/libgnutls.map
src/cli.c

diff --git a/NEWS b/NEWS
index aedb25af0fe2b82455a04f9e8b72cba3acad40fe..2abf67e9f8090664da70281d473c1a61f93f4a68 100644 (file)
--- 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)
 
index ff5edf2e598d0627ae29e02a161c157cdddb8842..a8dfa6e9f92e9d33f9a98113a82006cbb78275b9 100644 (file)
@@ -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
index ea2dfb8e61c1db8831ebcd649a7932f56463874b..45d4ef02d8fc940117ee0ac5217f0a99cf07df80 100644 (file)
@@ -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 
index ba56934461a440f1fa460b5c1e2a38e2ca491a80..b4befa88e041a3858eb9c54076fd952599c2124e 100644 (file)
@@ -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);
 
index 21e7244a56654ab43b3b15e465f1f0cecb595c84..6b97ba619b295b8f90805656ac080a93b1b062e1 100644 (file)
@@ -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);
 
index 63366c2f35b1363ccd9d6345873320aaa21e4b0e..f77e3a3cfab65f9687e7589047d86a128c9896e9 100644 (file)
@@ -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);
 
index c09495007c25b592b7198c4010b0b5f44d13ad7e..13b42e488f51c4ece0836f48fd56484a950b959c 100644 (file)
@@ -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);
 
index 77840758e9adea35ce6c02ed4539b41da253a2eb..afc6c09432ab75d81f3f5f5ce3f0c5af42e89eac 100644 (file)
@@ -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);
 
index 2a78e2da17bb8703ee1812fd98d5667e155dcea6..2535230472fdaac472b9f4443476ebdb99dabbf3 100644 (file)
@@ -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);
 
index 5d1f3f50b3093d916f827a8cc3c2733427e60b0b..4c4f9e32de4402aadea9e670c69b7bd859d32f39 100644 (file)
@@ -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)
index 04a89eb219a7d651bee51e6d07572d82ce709d66..52106acf4116d5029cf4436754843fe6dab2e342 100644 (file)
@@ -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); \
index dc2da48e93e6770662c94014a4eb5f6484c1c1f5..3f30e52d39510734a55541dfb74035f313840170 100644 (file)
@@ -2363,10 +2363,32 @@ 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)
index 0f8f8c1b44f18ec972fa7bd00f7c082cc66a4f3f..e0b324bfdc894b6e4c491209a2384e54e86269ec 100644 (file)
@@ -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().
    */
index fbb84a1447b796977082e04724c52f1cc895578b..4eaa79f96ad0461ecbf7e93e8716965fbff706c3 100644 (file)
@@ -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();
index 25cb1ea100471b38c58e282747f06c2ea1dfc78c..823f1d7bde73ed39d4678fd48494aea124a751f2 100644 (file)
@@ -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);
index 19f63c3ce820bf951f4dc26785fddb493cc0d4ba..801c6357ac518bf3d714054252db079a9e539375 100644 (file)
@@ -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 {
index 106c6173d33573b06e721ebc83e2476843f5aaee..755ca1fde6a8d1832911377f418b38f9ca8c869f 100644 (file)
--- 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)
         {