]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added safe renegotiation patch from Steve Dispensa, modified to suit gnutls
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Sun, 10 Jan 2010 13:21:42 +0000 (14:21 +0100)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Sun, 10 Jan 2010 23:26:51 +0000 (00:26 +0100)
code style and error checking. Modified to conform to draft-ietf-tls-renegotiation-03.txt.

gnutls-cli will search input for **RENEGOTIATION** to perform a renegotiation
and gnutls-serv will perform one if requested.

13 files changed:
doc/manpages/gnutls-cli.1
doc/manpages/gnutls-serv.1
lib/Makefile.am
lib/ext_safe_renegotiation.c [new file with mode: 0644]
lib/ext_safe_renegotiation.h [new file with mode: 0644]
lib/gnutls_errors.c
lib/gnutls_extensions.c
lib/gnutls_handshake.c
lib/gnutls_int.h
lib/gnutls_priority.c
lib/includes/gnutls/gnutls.h.in
src/cli.c
src/serv.c

index 82823a346667e31f29cd89d51075cc0e144b4fd0..6ca8da4266d95c6ac0ac3056d4c65157399dbae5 100644 (file)
@@ -78,6 +78,9 @@ Special keywords:
 "%SSL3_RECORD_VERSION" force SSL3.0 record version in the first client
 hello. This is to avoid buggy servers from terminating connection.
 .IP
+"%UNSAFE_RENEGOTIATION" will enable unsafe renegotiation (default
+behaviour at 2.8.5 and earlier releases)
+.IP
 To avoid collisions in order to specify a compression algorithm in
 this string you have to prefix it with "COMP-", protocol versions
 with "VERS-" and certificate types with "CTYPE-". All other
index 9b8c4252ea5898d950ffbdff19885c9e01cd8284..e1b5bd16e92a9627c0d4df7420013ccd2c483d3c 100644 (file)
@@ -75,6 +75,9 @@ Special keywords:
 .IP
 "%COMPAT" will enable compatibility features for a server.
 .IP
+"%UNSAFE_RENEGOTIATION" will enable unsafe renegotiation (default
+behaviour at 2.8.5 and earlier releases)
+.IP
 To avoid collisions in order to specify a compression algorithm in
 this string you have to prefix it with "COMP-", protocol versions
 with "VERS-" and certificate types with "CTYPE-". All other
index 54a91b737a8f1e78a696a56cbc702d60031dd7b1..fd366f0f5b3cbda920e7416cfc5acbb524df24a5 100644 (file)
@@ -81,7 +81,7 @@ COBJECTS = gnutls_record.c gnutls_compress.c debug.c gnutls_cipher.c  \
        auth_dh_common.c gnutls_helper.c gnutls_supplemental.c          \
        crypto.c random.c pk-libgcrypt.c mpi-libgcrypt.c cryptodev.c    \
        rnd-libgcrypt.c cipher-libgcrypt.c mac-libgcrypt.c ext_signature.c \
-       crypto-api.c
+       crypto-api.c ext_safe_renegotiation.c
 
 if ENABLE_OPRFI
 COBJECTS += $(OPRFI_COBJECTS)
@@ -101,7 +101,8 @@ HFILES = debug.h gnutls_compress.h gnutls_cipher.h gnutls_buffers.h \
        ext_srp.h gnutls_srp.h auth_srp.h auth_srp_passwd.h             \
        gnutls_helper.h auth_psk.h auth_psk_passwd.h                    \
        gnutls_supplemental.h ext_oprfi.h crypto.h random.h             \
-       ext_session_ticket.h ext_signature.h gnutls_cryptodev.h
+       ext_session_ticket.h ext_signature.h gnutls_cryptodev.h         \
+       ext_safe_renegotiation.h
 
 # Separate so we can create the documentation
 
diff --git a/lib/ext_safe_renegotiation.c b/lib/ext_safe_renegotiation.c
new file mode 100644 (file)
index 0000000..1020a49
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2009 Free Software Foundation
+ *
+ * Author: Steve Dispensa (<dispensa@phonefactor.com>)
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ */
+
+#include <gnutls_int.h>
+#include <ext_safe_renegotiation.h>
+#include "gnutls_errors.h"
+
+/* Each peer processes the extension in the same way - by moving the "current"
+ * value to "previous" and setting new "current" values.
+ */
+int
+_gnutls_safe_renegotiation_recv_params (gnutls_session_t session, 
+               const opaque * data, size_t _data_size)
+{
+  ssize_t data_size = _data_size;
+  uint8_t len;
+
+  DECR_LEN (data_size, 1);
+  len = data[0];
+  DECR_LEN (data_size, len);
+  
+  if (len >= MAX_VERIFY_DATA_SIZE)
+    {
+      gnutls_assert();
+      return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+    }
+
+  memcpy (session->security_parameters.extensions.previous_verify_data,
+         session->security_parameters.extensions.current_verify_data,
+         session->security_parameters.extensions.current_verify_data_len);
+
+  session->security_parameters.extensions.previous_verify_data_len =
+         session->security_parameters.extensions.current_verify_data_len;
+
+  memcpy (session->security_parameters.extensions.current_verify_data,
+         &data[1], len);
+
+  if (session->security_parameters.entity == GNUTLS_SERVER)
+    len *= 2;
+
+  session->security_parameters.extensions.current_verify_data_len = len;
+
+  session->security_parameters.extensions.safe_renegotiation_received = 1;
+  
+
+  return 0;
+}
+
+/* As a client, this sends the verify information that was saved during the
+ * previous finished message. As a server, echo back whatever we just received.
+ */
+int
+_gnutls_safe_renegotiation_send_params (gnutls_session_t session, 
+               opaque * data, size_t data_size)
+{
+  uint8_t len = 0; /* return 0 if we're not sending this ext */
+
+  if(session->security_parameters.extensions.safe_renegotiation_received ||
+     session->security_parameters.entity == GNUTLS_CLIENT)
+    {
+      if (!session->security_parameters.extensions.disable_safe_renegotiation)
+        {
+          len = session->security_parameters.extensions.current_verify_data_len;
+
+         /* client only sends its verification data */
+         if (session->security_parameters.entity == GNUTLS_CLIENT)
+           {
+              len /= 2;
+            }
+
+          if (data_size < len + 1) /* save room for the length byte */
+            {
+              gnutls_assert ();
+              return GNUTLS_E_SHORT_MEMORY_BUFFER;
+            }
+
+          data[0] = len++; /* return total length = len + length byte */
+          memcpy (&data[1], 
+                 session->security_parameters.extensions.current_verify_data,
+                 session->security_parameters.extensions.current_verify_data_len);
+        }
+    }
+
+  return len;
+}
+
+/**
+  * gnutls_safe_renegotiation_set - Used to enable and disable safe renegotiation
+  * @session: is a #gnutls_session_t structure.
+  * @value: 0 to disable and 1 to enable
+  *
+  * Used to enable and disable safe renegotiation for the current
+  * session. Normally you shouldn't cope with this function since the
+  * default (enable) is sufficient, but there might be servers that
+  * cannot handle or correctly handle the extension.
+  **/
+void
+gnutls_safe_renegotiation_set (gnutls_session_t session, int value)
+{
+       session->security_parameters.extensions.disable_safe_renegotiation = 1-value;
+}
+
diff --git a/lib/ext_safe_renegotiation.h b/lib/ext_safe_renegotiation.h
new file mode 100644 (file)
index 0000000..dab23a4
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2009 Free Software Foundation
+ *
+ * Author: Steve Dispensa (<dispensa@phonefactor.com>)
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ */
+
+int _gnutls_safe_renegotiation_recv_params (gnutls_session_t state, 
+               const opaque * data, size_t data_size);
+int _gnutls_safe_renegotiation_send_params (gnutls_session_t state, 
+               opaque * data, size_t);
+void gnutls_safe_renegotiation_set (gnutls_session_t session, int value);
index fdea4ef0093f95e79d7d95c5f2bc9517b7786009..086386c4f19d60fae96de2deea37412fef2ebffa 100644 (file)
@@ -220,6 +220,8 @@ static const gnutls_error_entry error_algorithms[] = {
               GNUTLS_E_OPENPGP_GETKEY_FAILED, 1),
   ERROR_ENTRY (N_("Could not find OpenPGP subkey."),
               GNUTLS_E_OPENPGP_SUBKEY_ERROR, 1),
+  ERROR_ENTRY (N_("Safe renegotiation failed."),
+              GNUTLS_E_SAFE_RENEGOTIATION_FAILED, 1),
 
   ERROR_ENTRY (N_("The SRP username supplied is illegal."),
               GNUTLS_E_ILLEGAL_SRP_USERNAME, 1),
index b3f388ce735cf67eea528440b64ef61454384f9f..eccbc5af274fc6f2c4cecf4251d7765e8f41e28d 100644 (file)
@@ -36,6 +36,7 @@
 #include <ext_oprfi.h>
 #include <ext_srp.h>
 #include <ext_session_ticket.h>
+#include <ext_safe_renegotiation.h>
 #include <ext_signature.h>
 #include <gnutls_num.h>
 
@@ -320,6 +321,14 @@ _gnutls_ext_init (void)
   if (ret != GNUTLS_E_SUCCESS)
     return ret;
 
+  ret = gnutls_ext_register (GNUTLS_EXTENSION_SAFE_RENEGOTIATION,
+                            "SAFE_RENEGOTIATION",
+                            GNUTLS_EXT_TLS,
+                            _gnutls_safe_renegotiation_recv_params,
+                            _gnutls_safe_renegotiation_send_params);
+  if (ret != GNUTLS_E_SUCCESS)
+    return ret;
+
 #ifdef ENABLE_OPRFI
   ret = gnutls_ext_register (GNUTLS_EXTENSION_OPAQUE_PRF_INPUT,
                             "OPAQUE_PRF_INPUT",
index aca1aab73f16ef27b50103ad8196eb02d92936d2..95d6233e5f22ab84c547ec74b2bac6347e84b4e1 100644 (file)
@@ -384,6 +384,26 @@ _gnutls_user_hello_func (gnutls_session_t session,
   return 0;
 }
 
+/* traverses the list of ciphersuites to find the
+ * SCSV (Secure Renegotiation indicator) ciphersuite.
+ */
+static int check_for_scsv(opaque* data, size_t datalen)
+{
+int j;
+  /* check for Safe renegotiation ciphersuite 
+   * FIXME: apply correct values here.
+   */
+  for (j = 0; j < datalen; j += 2)
+    {
+         if (data[j] == 0xFF && data[j+1] == 0xFF)
+           {
+                 return 1;
+               }
+       }
+       
+  return 0;
+}
+
 /* Read a client hello packet. 
  * A client hello must be a known version client hello
  * or version 2.0 client hello (only for compatibility
@@ -452,6 +472,7 @@ _gnutls_read_client_hello (gnutls_session_t session, opaque * data,
     {                          /* resumed! */
       resume_copy_required_values (session);
       session->internals.resumed = RESUME_TRUE;
+      
       return _gnutls_user_hello_func (session, adv_version);
     }
   else
@@ -473,6 +494,14 @@ _gnutls_read_client_hello (gnutls_session_t session, opaque * data,
   suite_ptr = &data[pos];
   pos += suite_size;
 
+
+  if (session->security_parameters.extensions.initial_negotiation_completed != 0 \
+       && check_for_scsv(suite_ptr, suite_size) != 0)
+    {
+      gnutls_assert();
+      return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+    }
+
   /* Point to the compression methods
    */
   DECR_LEN (len, 1);
@@ -636,7 +665,7 @@ _gnutls_send_finished (gnutls_session_t session, int again)
          data_size = 36;
        }
       else
-       {                       /* TLS 1.0 */
+       { /* TLS 1.0 */
          ret = _gnutls_finished (session,
                                  session->security_parameters.entity, data);
          data_size = 12;
@@ -652,6 +681,21 @@ _gnutls_send_finished (gnutls_session_t session, int again)
        session->internals.finished_func (session, data, data_size);
     }
 
+  /* Save data for safe_renegotiation. 
+   */
+  if (session->security_parameters.entity == GNUTLS_CLIENT)
+    {
+      memcpy (session->security_parameters.extensions.current_verify_data,
+             data, data_size);
+    }
+  else
+    {
+      memcpy (&session->security_parameters.extensions.current_verify_data[data_size],
+             data, data_size);
+    }
+  session->security_parameters.extensions.current_verify_data_len = 
+             data_size*2;
+
   ret =
     _gnutls_send_handshake (session, data_size ? data : NULL, data_size,
                            GNUTLS_HANDSHAKE_FINISHED);
@@ -665,7 +709,7 @@ _gnutls_send_finished (gnutls_session_t session, int again)
 static int
 _gnutls_recv_finished (gnutls_session_t session)
 {
-  uint8_t data[36], *vrfy;
+  uint8_t data[MAX_VERIFY_DATA_SIZE], *vrfy;
   int data_size;
   int ret;
   int vrfysize;
@@ -726,6 +770,21 @@ _gnutls_recv_finished (gnutls_session_t session)
     }
   gnutls_free (vrfy);
 
+  /* For safe renegotiation */
+  if (session->security_parameters.entity == GNUTLS_CLIENT)
+    {
+      memcpy (&session->security_parameters.extensions.current_verify_data[data_size],
+          data, data_size);
+    }
+  else /* server */
+    {
+      memcpy (session->security_parameters.extensions.current_verify_data,
+          data, data_size);
+    }
+  session->security_parameters.extensions.current_verify_data_len = data_size*2;
+
+  session->security_parameters.extensions.initial_negotiation_completed = 1;
+
   return ret;
 }
 
@@ -765,7 +824,6 @@ _gnutls_server_find_pk_algos_in_ciphersuites (const opaque *
   return algo;
 }
 
-
 /* This selects the best supported ciphersuite from the given ones. Then
  * it adds the suite to the session and performs some checks.
  */
@@ -784,7 +842,7 @@ _gnutls_server_select_suite (gnutls_session_t session, opaque * data,
 
   x = _gnutls_supported_ciphersuites (session, &ciphers);
   if (x < 0)
-    {                          /* the case x==0 is handled within the function. */
+    { /* the case x==0 is handled within the function. */
       gnutls_assert ();
       return x;
     }
@@ -830,23 +888,28 @@ _gnutls_server_select_suite (gnutls_session_t session, opaque * data,
 
   retval = GNUTLS_E_UNKNOWN_CIPHER_SUITE;
 
-  for (j = 0; j < datalen; j += 2)
+  if (check_for_scsv(data, datalen) != 0)
     {
-      for (i = 0; i < x; i++)
-       {
-         if (memcmp (ciphers[i].suite, &data[j], 2) == 0)
-           {
-             memcpy (&cs.suite, &data[j], 2);
+      session->security_parameters.extensions.safe_renegotiation_received = 1;
+    }
 
-             _gnutls_handshake_log
-               ("HSK[%p]: Selected cipher suite: %s\n", session,
-                _gnutls_cipher_suite_get_name (&cs));
-             memcpy (session->security_parameters.current_cipher_suite.suite,
-                     ciphers[i].suite, 2);
-             retval = 0;
-             goto finish;
-           }
-       }
+  for (j = 0; j < datalen; j += 2)
+    {
+         for (i = 0; i < x; i++)
+               {
+                 if (memcmp (ciphers[i].suite, &data[j], 2) == 0)
+                       {
+                         memcpy (&cs.suite, &data[j], 2);
+
+                         _gnutls_handshake_log
+                       ("HSK[%p]: Selected cipher suite: %s\n", session,
+                        _gnutls_cipher_suite_get_name (&cs));
+                         memcpy (session->security_parameters.current_cipher_suite.suite,
+                                 ciphers[i].suite, 2);
+                         retval = 0;
+                         goto finish;
+                       }
+               }
     }
 
 finish:
@@ -2169,6 +2232,8 @@ _gnutls_recv_hello (gnutls_session_t session, opaque * data, int datalen)
 {
   int ret;
 
+  session->security_parameters.extensions.safe_renegotiation_received = 0;
+
   if (session->security_parameters.entity == GNUTLS_CLIENT)
     {
       ret = _gnutls_read_server_hello (session, data, datalen);
@@ -2179,7 +2244,7 @@ _gnutls_recv_hello (gnutls_session_t session, opaque * data, int datalen)
        }
     }
   else
-    {                          /* Server side reading a client hello */
+    { /* Server side reading a client hello */
 
       ret = _gnutls_read_client_hello (session, data, datalen);
       if (ret < 0)
@@ -2189,6 +2254,46 @@ _gnutls_recv_hello (gnutls_session_t session, opaque * data, int datalen)
        }
     }
 
+  if (!session->security_parameters.extensions.disable_safe_renegotiation)
+    {
+      if (session->security_parameters.extensions.safe_renegotiation_received)
+        {
+          if ((session->security_parameters.extensions.current_verify_data_len !=
+               session->security_parameters.extensions.previous_verify_data_len) ||
+              (memcmp (session->security_parameters.extensions.current_verify_data,
+                       session->security_parameters.extensions.previous_verify_data,
+                       session->security_parameters.extensions.current_verify_data_len)))
+            {
+             gnutls_assert();
+              return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+            }
+         else
+            {
+              _gnutls_debug_log ("Safe renegotiation succeeded.\n");
+            }
+       }
+      else
+        {
+          if (session->security_parameters.extensions.initial_negotiation_completed)
+            {
+              if (session->internals.priorities.unsafe_renegotiation)
+                {
+                  _gnutls_handshake_log ("Allowing unsafe renegotiation!\n");
+                }
+              else
+                {
+                                 gnutls_assert();
+                  _gnutls_handshake_log ("Denying unsafe renegotiation.\n");
+                  return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+                }
+            }
+         else
+            {
+              _gnutls_handshake_log ("Allowing unsafe initial negotiation.\n");
+           }
+       }
+    }
+
   return ret;
 }
 
index a097bea1c88cdc2f55ab2fde31f1422938312001..bbb7d7f2a743e62a1e0108085bd9b4f427a35de6 100644 (file)
@@ -177,7 +177,8 @@ typedef enum extensions_t
   GNUTLS_EXTENSION_SRP = 12,
   GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS = 13,
   GNUTLS_EXTENSION_SESSION_TICKET = 35,
-  GNUTLS_EXTENSION_INNER_APPLICATION = 37703
+  GNUTLS_EXTENSION_INNER_APPLICATION = 37703,
+  GNUTLS_EXTENSION_SAFE_RENEGOTIATION = 0xff01,
 } extensions_t;
 
 typedef enum
@@ -306,6 +307,8 @@ struct gnutls_session_ticket_key_st {
   opaque mac_secret[SESSION_TICKET_MAC_SECRET_SIZE];
 };
 
+#define MAX_VERIFY_DATA_SIZE 36 /* in SSL 3.0, 12 in TLS 1.0 */
+
 typedef struct
 {
   server_name_st server_names[MAX_SERVER_NAME_EXTENSIONS];
@@ -333,6 +336,16 @@ typedef struct
   opaque *oprfi_server;
   uint16_t oprfi_server_len;
 
+  /* Safe renegotiation. */
+  int disable_safe_renegotiation:1;
+  int safe_renegotiation_received:1;
+  int initial_negotiation_completed:1;
+  uint8_t current_verify_data[2*MAX_VERIFY_DATA_SIZE];
+  size_t current_verify_data_len;
+  uint8_t previous_verify_data[2*MAX_VERIFY_DATA_SIZE];
+  size_t previous_verify_data_len;
+
+  /* Session Ticket */
   opaque *session_ticket;
   uint16_t session_ticket_len;
   struct gnutls_session_ticket_key_st *session_ticket_key;
@@ -446,7 +459,8 @@ struct gnutls_priority_st
   priority_st sign_algo;
 
   /* to disable record padding */
-  int no_padding;
+  int no_padding:1;
+  int unsafe_renegotiation:1;
   int ssl3_record_version;
   int additional_verify_flags;
 };
index 8700f90fb37313fc14a1617b7ae07dad7c5bbe5e..88e454e52f85b394cd902a8ac2749dcc9c525093 100644 (file)
@@ -522,6 +522,8 @@ gnutls_priority_set (gnutls_session_t session, gnutls_priority_t priority)
  *
  * "%COMPAT" will enable compatibility features for a server.
  *
+ * "%UNSAFE_RENEGOTIATION" will allow unsafe renegotiation.
+ *
  * "%SSL3_RECORD_VERSION" will use SSL3.0 record version in client hello.
  *
  * "%VERIFY_ALLOW_SIGN_RSA_MD5" will allow RSA-MD5 signatures in
@@ -711,6 +713,9 @@ gnutls_priority_init (gnutls_priority_t * priority_cache,
                               "VERIFY_ALLOW_X509_V1_CA_CRT") == 0)
            (*priority_cache)->additional_verify_flags |=
              GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT;
+         else if (strcasecmp (&broken_list[i][1],
+                              "UNSAFE_RENEGOTIATION") == 0)
+           (*priority_cache)->unsafe_renegotiation = 1;
          else
            goto error;
        }
index f148c1635e3faeed98b828bd428b3c3712af6330..74ab94eee63fdb1970f42d1bbfedd6f7080c7bda 100644 (file)
@@ -533,6 +533,9 @@ extern "C" {
                              void *data, size_t * data_length,
                              unsigned int *type, unsigned int indx);
 
+  /* Safe renegotiation */
+  void gnutls_safe_renegotiation_set (gnutls_session_t session, int value);
+
   /* Opaque PRF Input
    * http://tools.ietf.org/id/draft-rescorla-tls-opaque-prf-input-00.txt
    */
@@ -1382,6 +1385,7 @@ extern "C" {
 #define GNUTLS_E_IA_VERIFY_FAILED -104
 #define GNUTLS_E_UNKNOWN_ALGORITHM -105
 #define GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM -106
+#define GNUTLS_E_SAFE_RENEGOTIATION_FAILED -107
 
 #define GNUTLS_E_BASE64_ENCODING_ERROR -201
 #define GNUTLS_E_INCOMPATIBLE_GCRYPT_LIBRARY -202      /* obsolete */
index 2aa2da41978f32d2d4d38fe5c7e2dc2dfe1fa1bd..4e5bebe9d6fa6a53e6c160c6d5838d4521676ec4 100644 (file)
--- a/src/cli.c
+++ b/src/cli.c
@@ -826,6 +826,17 @@ after_handshake:
              continue;
            }
 
+          if (strstr(buffer, "**REHANDSHAKE**") != NULL) {
+           fprintf (stderr, "*** Starting TLS rehandshake\n");
+           ret = do_handshake (&hd);
+           if (ret < 0)
+             {
+               fprintf (stderr, "*** Rehandshake has failed\n");
+               user_term = 1;
+               retval = 1;
+               break;
+             }
+          }
          if (crlf != 0)
            {
              char *b = strchr (buffer, '\n');
index 12c5ec7d7631b1c8a4324e34342ebe085f9a3f09..f8c78a6be82cbeb45001346ecb62581f3dacb4f9 100644 (file)
@@ -1240,14 +1240,24 @@ main (int argc, char **argv)
                  }
                else if (r <= 0)
                  {
-                   j->http_state = HTTP_STATE_CLOSING;
-                   if (r < 0 && r != GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
+                   if (r == GNUTLS_E_REHANDSHAKE) 
                      {
-                       check_alert (j->tls_session, r);
-                       fprintf (stderr, "Error while receiving data\n");
-                       GERR (r);
-                     }
-
+                       do 
+                         {
+                           r = gnutls_handshake (j->tls_session);
+                          } 
+                        while (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN);
+                      }
+                    else
+                      { 
+                       j->http_state = HTTP_STATE_CLOSING;
+                       if (r < 0 && r != GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
+                         {
+                           check_alert (j->tls_session, r);
+                           fprintf (stderr, "Error while receiving data\n");
+                           GERR (r);
+                         }
+                        }
                  }
                else
                  {