Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 488f7d353752a24f1cc3f6fc2e121835 > files > 7

gnutls-1.4.1-10.el5_9.1.src.rpm

diff -up gnutls-1.4.1/doc/manpages/gnutls_safe_negotiation_set_initial.3.reneg gnutls-1.4.1/doc/manpages/gnutls_safe_negotiation_set_initial.3
--- gnutls-1.4.1/doc/manpages/gnutls_safe_negotiation_set_initial.3.reneg	2010-03-09 14:18:56.000000000 +0100
+++ gnutls-1.4.1/doc/manpages/gnutls_safe_negotiation_set_initial.3	2010-03-09 14:18:56.000000000 +0100
@@ -0,0 +1,41 @@
+.\" DO NOT MODIFY THIS FILE!  It was generated by gdoc.
+.TH "gnutls_safe_negotiation_set_initial" 3 "2.9.10" "gnutls" "gnutls"
+.SH NAME
+gnutls_safe_negotiation_set_initial \- API function
+.SH SYNOPSIS
+.B #include <gnutls/gnutls.h>
+.sp
+.BI "void gnutls_safe_negotiation_set_initial(gnutls_session_t " session ", int " value ");"
+.SH ARGUMENTS
+.IP "gnutls_session_t session" 12
+is a \fBgnutls_session_t\fP structure.
+.IP "int value" 12
+0 to disable and 1 to enable
+.SH "DESCRIPTION"
+Used to enable and disable initial safe renegotiation for the current
+session. By default it is allowed for a client to not advertise safe
+renegotiation capability but there might be cases where signalling
+a client of its insecurity by rejecting session might be beneficial.
+This option has meaning only in server side.
+.SH "REPORTING BUGS"
+Report bugs to <bug-gnutls@gnu.org>.
+GnuTLS home page: http://www.gnu.org/software/gnutls/
+General help using GNU software: http://www.gnu.org/gethelp/
+.SH COPYRIGHT
+Copyright \(co 2008 Free Software Foundation.
+.br
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
+.SH "SEE ALSO"
+The full documentation for
+.B gnutls
+is maintained as a Texinfo manual.  If the
+.B info
+and
+.B gnutls
+programs are properly installed at your site, the command
+.IP
+.B info gnutls
+.PP
+should give you access to the complete manual.
diff -up gnutls-1.4.1/doc/manpages/gnutls_safe_renegotiation_set.3.reneg gnutls-1.4.1/doc/manpages/gnutls_safe_renegotiation_set.3
--- gnutls-1.4.1/doc/manpages/gnutls_safe_renegotiation_set.3.reneg	2010-03-09 14:18:56.000000000 +0100
+++ gnutls-1.4.1/doc/manpages/gnutls_safe_renegotiation_set.3	2010-03-09 14:18:56.000000000 +0100
@@ -0,0 +1,40 @@
+.\" DO NOT MODIFY THIS FILE!  It was generated by gdoc.
+.TH "gnutls_safe_renegotiation_set" 3 "2.9.10" "gnutls" "gnutls"
+.SH NAME
+gnutls_safe_renegotiation_set \- API function
+.SH SYNOPSIS
+.B #include <gnutls/gnutls.h>
+.sp
+.BI "void gnutls_safe_renegotiation_set(gnutls_session_t " session ", int " value ");"
+.SH ARGUMENTS
+.IP "gnutls_session_t session" 12
+is a \fBgnutls_session_t\fP structure.
+.IP "int value" 12
+0 to disable and 1 to enable
+.SH "DESCRIPTION"
+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.
+.SH "REPORTING BUGS"
+Report bugs to <bug-gnutls@gnu.org>.
+GnuTLS home page: http://www.gnu.org/software/gnutls/
+General help using GNU software: http://www.gnu.org/gethelp/
+.SH COPYRIGHT
+Copyright \(co 2008 Free Software Foundation.
+.br
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
+.SH "SEE ALSO"
+The full documentation for
+.B gnutls
+is maintained as a Texinfo manual.  If the
+.B info
+and
+.B gnutls
+programs are properly installed at your site, the command
+.IP
+.B info gnutls
+.PP
+should give you access to the complete manual.
diff -up gnutls-1.4.1/doc/manpages/Makefile.in.reneg gnutls-1.4.1/doc/manpages/Makefile.in
--- gnutls-1.4.1/doc/manpages/Makefile.in.reneg	2006-07-14 12:03:28.000000000 +0200
+++ gnutls-1.4.1/doc/manpages/Makefile.in	2010-03-09 14:18:56.000000000 +0100
@@ -596,7 +596,7 @@ APIMANS = gnutls_server_name_get.3 gnutl
 	gnutls_openpgp_privkey_init.3 gnutls_openpgp_privkey_deinit.3 \
 	gnutls_openpgp_privkey_import.3 \
 	gnutls_openpgp_privkey_get_pk_algorithm.3 \
-	gnutls_openpgp_key_to_xml.3
+	gnutls_openpgp_key_to_xml.3 gnutls_safe_negotiation_set_initial.3 gnutls_safe_renegotiation_set.3
 SRPMANS = gnutls_srp_base64_encode.3 gnutls_srp_base64_encode_alloc.3 gnutls_srp_base64_decode.3 gnutls_srp_base64_decode_alloc.3 gnutls_srp_free_client_credentials.3 gnutls_srp_allocate_client_credentials.3 gnutls_srp_set_client_credentials.3 gnutls_srp_free_server_credentials.3 gnutls_srp_allocate_server_credentials.3 gnutls_srp_set_server_credentials_file.3 gnutls_srp_set_server_credentials_function.3 gnutls_srp_set_client_credentials_function.3 gnutls_srp_server_get_username.3 gnutls_srp_verifier.3
 all: all-am
 
diff -up gnutls-1.4.1/includes/gnutls/gnutls.h.in.reneg gnutls-1.4.1/includes/gnutls/gnutls.h.in
--- gnutls-1.4.1/includes/gnutls/gnutls.h.in.reneg	2006-05-05 11:07:42.000000000 +0200
+++ gnutls-1.4.1/includes/gnutls/gnutls.h.in	2010-03-09 14:18:56.000000000 +0100
@@ -69,6 +69,7 @@ extern "C"
 
   typedef enum gnutls_cipher_algorithm
   {
+    GNUTLS_CIPHER_UNKNOWN = 0,
     GNUTLS_CIPHER_NULL = 1,
     GNUTLS_CIPHER_ARCFOUR_128,
     GNUTLS_CIPHER_3DES_CBC,
@@ -81,6 +82,7 @@ extern "C"
 
   typedef enum
   {
+    GNUTLS_KX_UNKNOWN = 0,
     GNUTLS_KX_RSA = 1,
     GNUTLS_KX_DHE_DSS,
     GNUTLS_KX_DHE_RSA,
@@ -423,6 +425,11 @@ extern "C"
 			      void *data, size_t * data_length,
 			      unsigned int *type, unsigned int indx);
 
+  /* Safe renegotiation */
+  void gnutls_safe_negotiation_set_initial (gnutls_session_t session, int value);
+
+  void gnutls_safe_renegotiation_set (gnutls_session_t session, int value);
+
 /* functions to set priority of cipher suites 
  */
   int gnutls_cipher_set_priority (gnutls_session_t session, const int *list);
@@ -1148,6 +1155,8 @@ extern "C"
 #define GNUTLS_E_WARNING_IA_FPHF_RECEIVED -103
 
 #define GNUTLS_E_IA_VERIFY_FAILED -104
+#define GNUTLS_E_SAFE_RENEGOTIATION_FAILED -107
+#define GNUTLS_E_UNSAFE_RENEGOTIATION_DENIED -108
 
 #define GNUTLS_E_BASE64_ENCODING_ERROR -201
 #define GNUTLS_E_INCOMPATIBLE_GCRYPT_LIBRARY -202	/* obsolete */
diff -up gnutls-1.4.1/lib/ext_safe_renegotiation.c.reneg gnutls-1.4.1/lib/ext_safe_renegotiation.c
--- gnutls-1.4.1/lib/ext_safe_renegotiation.c.reneg	2010-03-09 14:18:56.000000000 +0100
+++ gnutls-1.4.1/lib/ext_safe_renegotiation.c	2010-03-09 14:18:56.000000000 +0100
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+ *
+ * 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>
+
+int
+_gnutls_safe_renegotiation_recv_params (gnutls_session_t session, 
+		const opaque * data, size_t _data_size)
+{
+  tls_ext_st *ext = &session->security_parameters.extensions;
+  int len = data[0];
+  ssize_t data_size = _data_size;
+
+  DECR_LEN (data_size, len+1 /* count the first byte and payload */);
+
+  /* It is not legal to receive this extension on a renegotiation and
+   * not receive it on the initial negotiation.
+   */
+  if (session->internals.initial_negotiation_completed != 0 &&
+    session->internals.connection_using_safe_renegotiation == 0)
+    {
+      gnutls_assert();
+      return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+    }
+
+  if (len > sizeof (ext->ri_extension_data))
+    {
+      gnutls_assert();
+      return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+    }
+
+  if (len > 0)
+    memcpy (ext->ri_extension_data, &data[1], len);
+  ext->ri_extension_data_len = len;
+
+  /* "safe renegotiation received" means on *this* handshake; "connection using
+   * safe renegotiation" means that the initial hello received on the connection
+   * indicated safe renegotiation. 
+   */
+  session->internals.safe_renegotiation_received = 1;
+  session->internals.connection_using_safe_renegotiation = 1;
+
+  return 0;
+}
+
+int
+_gnutls_safe_renegotiation_send_params (gnutls_session_t session, 
+		opaque * data, size_t _data_size)
+{
+  /* The format of this extension is a one-byte length of verify data followed
+   * by the verify data itself. Note that the length byte does not include
+   * itself; IOW, empty verify data is represented as a length of 0. That means
+   * the minimum extension is one byte: 0x00.
+   */
+  ssize_t data_size = _data_size;
+  tls_ext_st *ext = &session->security_parameters.extensions;
+
+
+  data[0] = 0;
+
+  /* Always offer the extension if we're a client */
+  if (session->internals.connection_using_safe_renegotiation ||
+     session->security_parameters.entity == GNUTLS_CLIENT)
+    {
+      DECR_LEN (data_size, 1);
+      data[0] = ext->client_verify_data_len;
+
+      DECR_LEN (data_size, ext->client_verify_data_len);
+
+      if (ext->client_verify_data_len > 0)
+        memcpy(&data[1], 
+	     ext->client_verify_data, 
+	     ext->client_verify_data_len);
+
+      if (session->security_parameters.entity == GNUTLS_SERVER)
+	{
+	  data[0] += ext->server_verify_data_len;
+
+	  DECR_LEN (data_size, ext->server_verify_data_len);
+
+	  if (ext->server_verify_data_len > 0)
+  	    memcpy(&data[1 + ext->client_verify_data_len],
+		 ext->server_verify_data,
+		 ext->server_verify_data_len);
+	}
+    }
+  else
+    return 0;
+
+  return 1 + data[0]; /* don't forget the length byte */
+}
+
+/**
+ * gnutls_safe_negotiation_set_initial:
+ * @session: is a #gnutls_session_t structure.
+ * @value: 0 to disable and 1 to enable
+ *
+ * Used to enable and disable initial safe renegotiation for the current
+ * session. By default it is allowed for a client to not advertise safe
+ * renegotiation capability but there might be cases where signalling
+ * a client of its insecurity by rejecting session might be beneficial.
+ * This option has meaning only in server side.
+ **/
+void
+gnutls_safe_negotiation_set_initial (gnutls_session_t session, int value)
+{
+  session->internals.initial_safe_renegotiation = value;
+}
+
+/**
+ * gnutls_safe_renegotiation_set:
+ * @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->internals.unsafe_renegotiation = 1-value;
+}
diff -up gnutls-1.4.1/lib/ext_safe_renegotiation.h.reneg gnutls-1.4.1/lib/ext_safe_renegotiation.h
--- gnutls-1.4.1/lib/ext_safe_renegotiation.h.reneg	2010-03-09 14:18:56.000000000 +0100
+++ gnutls-1.4.1/lib/ext_safe_renegotiation.h	2010-03-09 14:18:56.000000000 +0100
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+ *
+ * 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
+ *
+ */
+
+#ifndef EXT_SAFE_RENEGOTIATION_H
+# define EXT_SAFE_RENEGOTIATION_H
+
+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);
+
+#endif /* EXT_SAFE_RENEGOTIATION_H */
diff -up gnutls-1.4.1/lib/gnutls_alert.c.reneg gnutls-1.4.1/lib/gnutls_alert.c
--- gnutls-1.4.1/lib/gnutls_alert.c.reneg	2006-03-08 11:44:59.000000000 +0100
+++ gnutls-1.4.1/lib/gnutls_alert.c	2010-03-09 14:18:56.000000000 +0100
@@ -198,6 +198,7 @@ gnutls_error_to_alert (int err, int *lev
     case GNUTLS_E_INSUFFICIENT_CREDENTIALS:
     case GNUTLS_E_NO_CIPHER_SUITES:
     case GNUTLS_E_NO_COMPRESSION_ALGORITHMS:
+    case GNUTLS_E_SAFE_RENEGOTIATION_FAILED:
       ret = GNUTLS_A_HANDSHAKE_FAILURE;
       _level = GNUTLS_AL_FATAL;
       break;
@@ -211,6 +212,7 @@ gnutls_error_to_alert (int err, int *lev
       _level = GNUTLS_AL_FATAL;
       break;
     case GNUTLS_E_REHANDSHAKE:
+    case GNUTLS_E_UNSAFE_RENEGOTIATION_DENIED:
       ret = GNUTLS_A_NO_RENEGOTIATION;
       _level = GNUTLS_AL_WARNING;
       break;
diff -up gnutls-1.4.1/lib/gnutls_algorithms.c.reneg gnutls-1.4.1/lib/gnutls_algorithms.c
--- gnutls-1.4.1/lib/gnutls_algorithms.c.reneg	2006-03-08 11:44:59.000000000 +0100
+++ gnutls-1.4.1/lib/gnutls_algorithms.c	2010-03-09 14:18:56.000000000 +0100
@@ -373,6 +373,10 @@ typedef struct
 #define GNUTLS_DHE_RSA_AES_128_CBC_SHA1 { 0x00, 0x33 }
 #define GNUTLS_DHE_RSA_AES_256_CBC_SHA1 { 0x00, 0x39 }
 
+/* Safe renegotiation */
+
+#define GNUTLS_RENEGO_PROTECTION_REQUEST { GNUTLS_RENEGO_PROTECTION_REQUEST_MAJOR, GNUTLS_RENEGO_PROTECTION_REQUEST_MINOR }
+
 #define CIPHER_SUITES_COUNT sizeof(cs_algorithms)/sizeof(gnutls_cipher_suite_entry)-1
 
 static const gnutls_cipher_suite_entry cs_algorithms[] = {
@@ -502,6 +506,9 @@ static const gnutls_cipher_suite_entry c
   GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_RSA_AES_256_CBC_SHA1,
 			     GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_RSA,
 			     GNUTLS_MAC_SHA1, GNUTLS_SSL3),
+  GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_RENEGO_PROTECTION_REQUEST,
+			     GNUTLS_CIPHER_UNKNOWN, GNUTLS_KX_UNKNOWN,
+			     GNUTLS_MAC_UNKNOWN, GNUTLS_SSL3),
   {0, {{0, 0}}, 0, 0, 0, 0}
 };
 
diff -up gnutls-1.4.1/lib/gnutls_algorithms.h.reneg gnutls-1.4.1/lib/gnutls_algorithms.h
--- gnutls-1.4.1/lib/gnutls_algorithms.h.reneg	2006-03-08 11:44:59.000000000 +0100
+++ gnutls-1.4.1/lib/gnutls_algorithms.h	2010-03-09 14:18:56.000000000 +0100
@@ -27,6 +27,9 @@
 
 #include "gnutls_auth.h"
 
+#define GNUTLS_RENEGO_PROTECTION_REQUEST_MAJOR 0x00
+#define GNUTLS_RENEGO_PROTECTION_REQUEST_MINOR 0xFF
+
 /* Functions for version handling. */
 gnutls_protocol_t _gnutls_version_lowest (gnutls_session_t session);
 gnutls_protocol_t _gnutls_version_max (gnutls_session_t session);
diff -up gnutls-1.4.1/lib/gnutls_constate.c.reneg gnutls-1.4.1/lib/gnutls_constate.c
--- gnutls-1.4.1/lib/gnutls_constate.c.reneg	2006-03-08 11:44:59.000000000 +0100
+++ gnutls-1.4.1/lib/gnutls_constate.c	2010-03-09 14:18:56.000000000 +0100
@@ -429,6 +429,16 @@ _gnutls_set_write_keys (gnutls_session_t
 			   export_flag);
 }
 
+#define CPY_EXTENSIONS \
+	memcpy(dst->extensions.server_names, src->extensions.server_names, sizeof(src->extensions.server_names)); \
+	dst->extensions.server_names_size = src->extensions.server_names_size; \
+	memcpy(dst->extensions.srp_username, src->extensions.srp_username, sizeof(src->extensions.srp_username)); \
+	dst->extensions.gnutls_ia_enable = src->extensions.gnutls_ia_enable; \
+	dst->extensions.gnutls_ia_peer_enable = src->extensions.gnutls_ia_peer_enable; \
+	dst->extensions.gnutls_ia_allowskip = src->extensions.gnutls_ia_allowskip; \
+	dst->extensions.gnutls_ia_peer_allowskip = src->extensions.gnutls_ia_peer_allowskip
+
+
 #define CPY_COMMON dst->entity = src->entity; \
 	dst->kx_algorithm = src->kx_algorithm; \
 	memcpy( &dst->current_cipher_suite, &src->current_cipher_suite, sizeof(cipher_suite_st)); \
@@ -442,7 +452,7 @@ _gnutls_set_write_keys (gnutls_session_t
 	dst->max_record_recv_size = src->max_record_recv_size; \
 	dst->max_record_send_size = src->max_record_send_size; \
 	dst->version = src->version; \
-	memcpy( &dst->extensions, &src->extensions, sizeof(tls_ext_st)); \
+	CPY_EXTENSIONS; \
 	memcpy( &dst->inner_secret, &src->inner_secret, TLS_MASTER_SIZE);
 
 static void
diff -up gnutls-1.4.1/lib/gnutls_errors.c.reneg gnutls-1.4.1/lib/gnutls_errors.c
--- gnutls-1.4.1/lib/gnutls_errors.c.reneg	2006-03-08 11:46:58.000000000 +0100
+++ gnutls-1.4.1/lib/gnutls_errors.c	2010-03-09 14:18:56.000000000 +0100
@@ -208,6 +208,10 @@ static const gnutls_error_entry error_al
 	       GNUTLS_E_NO_CIPHER_SUITES, 1),
   ERROR_ENTRY (N_("Could not get OpenPGP key."),
 	       GNUTLS_E_OPENPGP_GETKEY_FAILED, 1),
+  ERROR_ENTRY (N_("Safe renegotiation failed."),
+	       GNUTLS_E_SAFE_RENEGOTIATION_FAILED, 1),
+  ERROR_ENTRY (N_("Unsafe renegotiation denied."),
+	       GNUTLS_E_UNSAFE_RENEGOTIATION_DENIED, 1),
 
   ERROR_ENTRY (N_("The SRP username supplied is illegal."),
 	       GNUTLS_E_ILLEGAL_SRP_USERNAME, 1),
diff -up gnutls-1.4.1/lib/gnutls_extensions.c.reneg gnutls-1.4.1/lib/gnutls_extensions.c
--- gnutls-1.4.1/lib/gnutls_extensions.c.reneg	2006-03-08 11:44:59.000000000 +0100
+++ gnutls-1.4.1/lib/gnutls_extensions.c	2010-03-09 14:18:56.000000000 +0100
@@ -35,6 +35,7 @@
 #include <ext_server_name.h>
 #include <ext_srp.h>
 #include <ext_inner_application.h>
+#include <ext_safe_renegotiation.h>
 #include <gnutls_num.h>
 
 /* Key Exchange Section */
@@ -63,6 +64,9 @@ gnutls_extension_entry _gnutls_extension
   GNUTLS_EXTENSION_ENTRY (GNUTLS_EXTENSION_INNER_APPLICATION,
 			  _gnutls_inner_application_recv_params,
 			  _gnutls_inner_application_send_params),
+  GNUTLS_EXTENSION_ENTRY (GNUTLS_EXTENSION_SAFE_RENEGOTIATION,
+			  _gnutls_safe_renegotiation_recv_params,
+			  _gnutls_safe_renegotiation_send_params),
   {0, 0, 0, 0}
 };
 
@@ -70,17 +74,17 @@ gnutls_extension_entry _gnutls_extension
         gnutls_extension_entry *p; \
                 for(p = _gnutls_extensions; p->name != NULL; p++) { b ; }
 
-#define GNUTLS_EXTENSION_LOOP(a) \
-                        GNUTLS_EXTENSION_LOOP2( if(p->type == type) { a; break; } )
+#define GNUTLS_EXTENSION_LOOP(r,a) \
+                        GNUTLS_EXTENSION_LOOP2( if((!r || p->type == GNUTLS_EXTENSION_SAFE_RENEGOTIATION) && p->type == type) { a; break; } )
 
 
 /* EXTENSION functions */
 
 ext_recv_func
-_gnutls_ext_func_recv (uint16_t type)
+_gnutls_ext_func_recv (uint16_t type, int resume)
 {
   ext_recv_func ret = NULL;
-  GNUTLS_EXTENSION_LOOP (ret = p->gnutls_ext_func_recv);
+  GNUTLS_EXTENSION_LOOP (resume, ret = p->gnutls_ext_func_recv);
   return ret;
 
 }
@@ -89,7 +93,7 @@ ext_send_func
 _gnutls_ext_func_send (uint16_t type)
 {
   ext_send_func ret = NULL;
-  GNUTLS_EXTENSION_LOOP (ret = p->gnutls_ext_func_send);
+  GNUTLS_EXTENSION_LOOP (0, ret = p->gnutls_ext_func_send);
   return ret;
 
 }
@@ -100,7 +104,7 @@ _gnutls_extension_get_name (uint16_t typ
   const char *ret = NULL;
 
   /* avoid prefix */
-  GNUTLS_EXTENSION_LOOP (ret = p->name + sizeof ("GNUTLS_EXTENSION_") - 1);
+  GNUTLS_EXTENSION_LOOP (0, ret = p->name + sizeof ("GNUTLS_EXTENSION_") - 1);
 
   return ret;
 }
@@ -127,7 +131,7 @@ _gnutls_extension_list_check (gnutls_ses
 
 int
 _gnutls_parse_extensions (gnutls_session_t session, const opaque * data,
-			  int data_size)
+			  int data_size, int resume)
 {
   int next, ret;
   int pos = 0;
@@ -179,7 +183,7 @@ _gnutls_parse_extensions (gnutls_session
       sdata = &data[pos];
       pos += size;
 
-      ext_recv = _gnutls_ext_func_recv (type);
+      ext_recv = _gnutls_ext_func_recv (type, resume);
       if (ext_recv == NULL)
 	continue;
       if ((ret = ext_recv (session, sdata, size)) < 0)
@@ -199,7 +203,7 @@ _gnutls_parse_extensions (gnutls_session
  * This list is used to check whether the (later) received
  * extensions are the ones we requested.
  */
-static void
+void
 _gnutls_extension_list_add (gnutls_session_t session, uint16_t type)
 {
 
diff -up gnutls-1.4.1/lib/gnutls_extensions.h.reneg gnutls-1.4.1/lib/gnutls_extensions.h
--- gnutls-1.4.1/lib/gnutls_extensions.h.reneg	2006-03-08 11:44:59.000000000 +0100
+++ gnutls-1.4.1/lib/gnutls_extensions.h	2010-03-09 14:18:56.000000000 +0100
@@ -25,15 +25,16 @@
 #include <gnutls_int.h>
 
 const char *_gnutls_extension_get_name (uint16_t type);
-int _gnutls_parse_extensions (gnutls_session_t, const opaque *, int);
+int _gnutls_parse_extensions (gnutls_session_t, const opaque *, int, int);
 int _gnutls_gen_extensions (gnutls_session_t session, opaque * data,
 			    size_t data_size);
 
 typedef int (*ext_recv_func) (gnutls_session_t, const opaque *, size_t);	/* recv data */
 typedef int (*ext_send_func) (gnutls_session_t, opaque *, size_t);	/* send data */
+void _gnutls_extension_list_add (gnutls_session_t session, uint16_t type);
 
 ext_send_func _gnutls_ext_func_send (uint16_t type);
-ext_recv_func _gnutls_ext_func_recv (uint16_t type);
+ext_recv_func _gnutls_ext_func_recv (uint16_t type, int resume);
 
 typedef struct
 {
diff -up gnutls-1.4.1/lib/gnutls_handshake.c.reneg gnutls-1.4.1/lib/gnutls_handshake.c
--- gnutls-1.4.1/lib/gnutls_handshake.c.reneg	2010-03-09 14:18:56.000000000 +0100
+++ gnutls-1.4.1/lib/gnutls_handshake.c	2010-03-09 14:19:22.000000000 +0100
@@ -47,6 +47,7 @@
 #include <gnutls_record.h>
 #include <gnutls_state.h>
 #include <ext_srp.h>
+#include <ext_safe_renegotiation.h>
 #include <gnutls_rsa_export.h>	/* for gnutls_get_rsa_params() */
 #include <auth_anon.h>		/* for gnutls_anon_server_credentials_t */
 #include <auth_psk.h>		/* for gnutls_psk_server_credentials_t */
@@ -338,7 +339,33 @@ _gnutls_read_client_hello (gnutls_sessio
   pos += session_id_len;
 
   if (ret == 0)
-    {				/* resumed! */
+    { /* resumed using default TLS resumption! */
+      /* Parse only the safe renegotiation extension
+       * We don't want to parse any other extensions since
+       * we don't want new extension values to overwrite the
+       * resumed ones.
+       */
+       
+      /* move forward to extensions */
+      DECR_LEN (len, 2);
+      suite_size = _gnutls_read_uint16 (&data[pos]);
+      pos += 2;
+
+      DECR_LEN (len, suite_size);
+      pos += suite_size;
+      
+      DECR_LEN (len, 1);
+      z = data[pos++];	/* z is the number of compression methods */
+      DECR_LEN (len, z);
+      pos += z;
+
+      ret = _gnutls_parse_extensions (session, &data[pos], len, 1);
+      if (ret < 0)
+        {
+          gnutls_assert ();
+          return ret;
+        }
+
       resume_copy_required_values (session);
       session->internals.resumed = RESUME_TRUE;
       return 0;
@@ -379,16 +406,16 @@ _gnutls_read_client_hello (gnutls_sessio
     }
 
   /* Parse the extensions (if any)
+   *
+   * Unconditionally try to parse extensions; safe renegotiation uses them in
+   * sslv3 and higher, even though sslv3 doesn't officially support them.
    */
-  if (ver >= GNUTLS_TLS1)
-    {
-      ret = _gnutls_parse_extensions (session, &data[pos], len);	/* len is the rest of the parsed length */
+      ret = _gnutls_parse_extensions (session, &data[pos], len, 0);	/* len is the rest of the parsed length */
       if (ret < 0)
 	{
 	  gnutls_assert ();
 	  return ret;
 	}
-    }
 
   /* select an appropriate cipher suite
    */
@@ -485,6 +512,31 @@ _gnutls_send_finished (gnutls_session_t 
 
     }
 
+  /* Save data for safe renegotiation. 
+   */
+  if (data_size > MAX_VERIFY_DATA_SIZE) 
+    {
+      gnutls_assert ();
+      return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+    }
+
+  if (session->security_parameters.entity == GNUTLS_CLIENT)
+    {
+      session->security_parameters.extensions.client_verify_data_len = 
+	      data_size;
+
+      memcpy (session->security_parameters.extensions.client_verify_data,
+	      data, data_size);
+    }
+  else
+    {
+      session->security_parameters.extensions.server_verify_data_len = 
+	      data_size;
+
+      memcpy (session->security_parameters.extensions.server_verify_data,
+	      data, data_size);
+    }
+
   ret =
     _gnutls_send_handshake (session, data, data_size,
 			    GNUTLS_HANDSHAKE_FINISHED);
@@ -502,6 +554,7 @@ _gnutls_recv_finished (gnutls_session_t 
   int data_size;
   int ret;
   int vrfysize;
+  tls_ext_st *ext;
 
   ret =
     _gnutls_recv_handshake (session, &vrfy, &vrfysize,
@@ -559,6 +612,28 @@ _gnutls_recv_finished (gnutls_session_t 
     }
   gnutls_free (vrfy);
 
+  /* Save peer's verify data for safe renegotiation */
+  if (data_size > MAX_VERIFY_DATA_SIZE)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+    }
+
+  ext = &session->security_parameters.extensions;
+
+  if (session->security_parameters.entity == GNUTLS_CLIENT)
+    {
+      memcpy (ext->server_verify_data, data, data_size);
+      ext->server_verify_data_len = data_size;
+    }
+  else
+    {
+      memcpy (ext->client_verify_data, data, data_size);
+      ext->client_verify_data_len = data_size;
+    }
+
+  session->internals.initial_negotiation_completed = 1;
+
   return ret;
 }
 
@@ -613,6 +688,25 @@ _gnutls_server_select_suite (gnutls_sess
 					 * supported by the peer.
 					 */
 
+  /* First, check for safe renegotiation SCSV.
+   */
+  {
+    int offset;
+
+    for(offset = 0; offset < datalen; offset += 2)
+      {
+	/* TLS_RENEGO_PROTECTION_REQUEST = { 0x00, 0xff } */
+        if (data[offset]   == GNUTLS_RENEGO_PROTECTION_REQUEST_MAJOR &&
+            data[offset+1] == GNUTLS_RENEGO_PROTECTION_REQUEST_MINOR)
+          {
+	    _gnutls_handshake_log ("HSK[%p]: Received safe renegotiation CS\n", session);
+            session->internals.safe_renegotiation_received = 1;
+            session->internals.connection_using_safe_renegotiation = 1;
+	    break;
+          }
+      }
+  }
+
   pk_algo = _gnutls_server_find_pk_algos_in_ciphersuites (data, datalen);
 
   x = _gnutls_supported_ciphersuites (session, &ciphers);
@@ -1456,7 +1550,20 @@ _gnutls_read_server_hello (gnutls_sessio
    */
   if (_gnutls_client_check_if_resuming
       (session, &data[pos], session_id_len) == 0)
-    return 0;
+    {
+      pos += session_id_len + 2 + 1;
+      DECR_LEN (len, 2+1);
+
+      ret = _gnutls_parse_extensions (session,
+				  &data[pos], len, 1);
+      if (ret < 0)
+        {
+          gnutls_assert ();
+          return ret;
+        }
+      return 0;
+    }
+
   pos += session_id_len;
 
 
@@ -1488,30 +1595,30 @@ _gnutls_read_server_hello (gnutls_sessio
 
   /* Parse extensions.
    */
-  if (version >= GNUTLS_TLS1)
-    {
-      ret = _gnutls_parse_extensions (session, &data[pos], len);	/* len is the rest of the parsed length */
+  ret = _gnutls_parse_extensions (session, &data[pos], len, 0);	/* len is the rest of the parsed length */
       if (ret < 0)
 	{
 	  gnutls_assert ();
 	  return ret;
 	}
-    }
   return ret;
 }
 
 
 /* This function copies the appropriate ciphersuites to a locally allocated buffer
- * Needed in client hello messages. Returns the new data length.
+ * Needed in client hello messages. Returns the new data length. If add_scsv is
+ * true, add the special safe renegotiation CS.
  */
 static int
 _gnutls_copy_ciphersuites (gnutls_session_t session,
-			   opaque * ret_data, size_t ret_data_size)
+			   opaque * ret_data, size_t ret_data_size,
+			   int add_scsv)
 {
   int ret, i;
   cipher_suite_st *cipher_suites;
   uint16_t cipher_num;
   int datalen, pos;
+  uint16_t loop_max;
 
   ret = _gnutls_supported_ciphersuites_sorted (session, &cipher_suites);
   if (ret < 0)
@@ -1542,6 +1649,9 @@ _gnutls_copy_ciphersuites (gnutls_sessio
       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
     }
 
+  if (add_scsv)
+    ++ret;
+
   cipher_num = ret;
 
   cipher_num *= sizeof (uint16_t);	/* in order to get bytes */
@@ -1559,11 +1669,21 @@ _gnutls_copy_ciphersuites (gnutls_sessio
   _gnutls_write_uint16 (cipher_num, ret_data);
   pos += 2;
 
-  for (i = 0; i < (cipher_num / 2); i++)
+  loop_max = add_scsv ? cipher_num - 2 : cipher_num;
+
+  for (i = 0; i < (loop_max / 2); i++)
     {
       memcpy (&ret_data[pos], cipher_suites[i].suite, 2);
       pos += 2;
     }
+
+  if (add_scsv)
+    {
+      /* Safe renegotiation signalling CS value is { 0x00, 0xff } */
+      ret_data[pos++] = 0x00;
+      ret_data[pos++] = 0xff;
+    }
+
   gnutls_free (cipher_suites);
 
   return datalen;
@@ -1628,6 +1748,7 @@ _gnutls_send_client_hello (gnutls_sessio
   opaque rnd[TLS_RANDOM_SIZE];
   gnutls_protocol_t hver;
   opaque extdata[MAX_EXT_DATA_LENGTH];
+  int rehandshake = 0;
 
   opaque *SessionID =
     session->internals.resumed_security_parameters.session_id;
@@ -1639,6 +1760,11 @@ _gnutls_send_client_hello (gnutls_sessio
   else if (session_id_len == 0)
     SessionID = NULL;
 
+  /* note that rehandshake is different than resuming
+   */
+  if (session->security_parameters.session_id_size)
+    rehandshake = 1;
+
   if (again == 0)
     {
 
@@ -1657,7 +1783,12 @@ _gnutls_send_client_hello (gnutls_sessio
        * version number to the previously established.
        */
       if (SessionID == NULL)
-	hver = _gnutls_version_max (session);
+	{
+          if (rehandshake) /* already negotiated version thus version_max == negotiated version */
+            hver = session->security_parameters.version;
+          else /* new handshake. just get the max */
+            hver = _gnutls_version_max (session);
+	}
       else
 	{			/* we are resuming a session */
 	  hver = session->internals.resumed_security_parameters.version;
@@ -1712,9 +1843,20 @@ _gnutls_send_client_hello (gnutls_sessio
 
 
       /* Copy the ciphersuites.
-       */
-      extdatalen =
-	_gnutls_copy_ciphersuites (session, extdata, sizeof (extdata));
+       *
+       * If using SSLv3 Send TLS_RENEGO_PROTECTION_REQUEST SCSV for MITM
+       * prevention on initial negotiation (but not renegotiation; that's
+       * handled with the RI extension below).
+       */
+      if(!session->internals.initial_negotiation_completed &&
+	 session->security_parameters.entity == GNUTLS_CLIENT &&
+	 gnutls_protocol_get_version (session) == GNUTLS_SSL3)
+        {
+	  extdatalen = _gnutls_copy_ciphersuites (session, extdata, sizeof (extdata), TRUE);
+	  _gnutls_extension_list_add (session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION);
+	}
+      else
+	extdatalen = _gnutls_copy_ciphersuites (session, extdata, sizeof (extdata), FALSE);
       if (extdatalen > 0)
 	{
 	  datalen += extdatalen;
@@ -1792,6 +1934,51 @@ _gnutls_send_client_hello (gnutls_sessio
 	      return extdatalen;
 	    }
 	}
+      else if(session->internals.initial_negotiation_completed != 0)
+        {
+	  opaque buf[256]; /* opaque renegotiated_connection<0..255> */
+
+	  /* For SSLv3 only, we will (only) to send the RI extension; we must
+	   * send it every time we renegotiate. We don't want to send anything
+	   * else, out of concern for interoperability.
+	   *
+	   * If this is an initial negotiation, we already sent SCSV above.
+	   */
+
+	  _gnutls_extension_list_add (session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION);
+
+	  ret = _gnutls_safe_renegotiation_send_params (session, buf, sizeof(buf));
+
+	  if (ret < 0)
+	    {
+	      gnutls_assert ();
+	      gnutls_free (data);
+	      return ret;
+	    }
+
+	  datalen += ret + 6; /* extlen(2) + type(2) + len(2) + ret */
+
+	  data = gnutls_realloc_fast (data, datalen);
+	  if (data == NULL)
+	    {
+	      gnutls_assert ();
+	      return GNUTLS_E_MEMORY_ERROR;
+	    }
+
+	  /* total extensions length (one extension, with type(2) + len(2)) */
+	  _gnutls_write_uint16 (4 + ret, &data[pos]);
+	  pos += 2;
+
+	  /* TLS RI extension type is 0xff01 */
+	  data[pos++] = 0xff;
+	  data[pos++] = 0x01;
+
+	  _gnutls_write_uint16 (ret, &data[pos]);
+	  pos += 2;
+
+	  memcpy(&data[pos], buf, ret);
+	  pos += ret;
+	}
     }
 
   ret =
@@ -1920,6 +2107,8 @@ _gnutls_send_hello (gnutls_session_t ses
 {
   int ret;
 
+  session->internals.safe_renegotiation_received = 0;
+
   if (session->security_parameters.entity == GNUTLS_CLIENT)
     {
       ret = _gnutls_send_client_hello (session, again);
@@ -1941,6 +2130,7 @@ int
 _gnutls_recv_hello (gnutls_session_t session, opaque * data, int datalen)
 {
   int ret;
+  tls_ext_st *ext;
 
   if (session->security_parameters.entity == GNUTLS_CLIENT)
     {
@@ -1962,6 +2152,86 @@ _gnutls_recv_hello (gnutls_session_t ses
 	}
     }
 
+  /* Safe renegotiation */
+  ext = &session->security_parameters.extensions;
+
+  if (session->internals.safe_renegotiation_received)
+    {
+      if ((ext->ri_extension_data_len < ext->client_verify_data_len) ||
+	  (memcmp (ext->ri_extension_data,
+		   ext->client_verify_data,
+		   ext->client_verify_data_len)))
+	{
+	  gnutls_assert();
+	  _gnutls_handshake_log ("Safe renegotiation failed [1]\n");
+	  return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+	}
+      if (session->security_parameters.entity == GNUTLS_CLIENT)
+        {
+	  if ((ext->ri_extension_data_len !=
+	       ext->client_verify_data_len + ext->server_verify_data_len) ||
+	       memcmp (ext->ri_extension_data + ext->client_verify_data_len,
+		       ext->server_verify_data, ext->server_verify_data_len) != 0)
+	    {
+	      gnutls_assert();
+	      _gnutls_handshake_log ("Safe renegotiation failed [2]\n");
+	      return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+	    }
+	}
+      else /* Make sure there are 0 extra bytes */
+	{
+	  if (ext->ri_extension_data_len != ext->client_verify_data_len)
+	    {
+	      gnutls_assert();
+	      _gnutls_handshake_log ("Safe renegotiation failed [3]\n");
+	      return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+	    }
+	}
+
+      _gnutls_handshake_log ("Safe renegotiation succeeded.\n");
+    }
+  else /* safe renegotiation not received... */
+    {
+      if (session->internals.connection_using_safe_renegotiation)
+	{
+	  gnutls_assert();
+	  _gnutls_handshake_log ("Peer previously asked for safe renegotiation!\n");
+	  return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+	}
+
+      /* Clients can't tell if it's an initial negotiation */
+      if (session->internals.initial_negotiation_completed ||
+	  session->security_parameters.entity == GNUTLS_CLIENT)
+	{
+	  if (session->internals.unsafe_renegotiation != 0)
+	    {
+	      _gnutls_handshake_log ("Allowing unsafe (re)negotiation!\n");
+	    }
+	  else
+	    {
+	      gnutls_assert();
+	      _gnutls_handshake_log ("Denying unsafe (re)negotiation.\n");
+	      if (session->security_parameters.entity == GNUTLS_SERVER)
+		return GNUTLS_E_UNSAFE_RENEGOTIATION_DENIED; /* send no renegotiation alert */
+	      else
+		return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+	    }
+	}
+      else
+	{
+	  if (session->internals.initial_safe_renegotiation==0)
+	    {
+	      _gnutls_handshake_log ("Allowing unsafe initial negotiation!\n");
+	    }
+	  else
+	    {
+	      gnutls_assert();
+	      _gnutls_handshake_log ("Denying unsafe initial negotiation.\n");
+	      return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
+	    }
+	}
+    }
+
   return ret;
 }
 
diff -up gnutls-1.4.1/lib/gnutls_int.h.reneg gnutls-1.4.1/lib/gnutls_int.h
--- gnutls-1.4.1/lib/gnutls_int.h.reneg	2006-05-05 11:07:42.000000000 +0200
+++ gnutls-1.4.1/lib/gnutls_int.h	2010-03-09 14:18:56.000000000 +0100
@@ -138,7 +138,8 @@ typedef enum extensions_t
 { GNUTLS_EXTENSION_SERVER_NAME = 0,
   GNUTLS_EXTENSION_MAX_RECORD_SIZE = 1, GNUTLS_EXTENSION_SRP = 6,
   GNUTLS_EXTENSION_CERT_TYPE = 7,
-  GNUTLS_EXTENSION_INNER_APPLICATION = 37703
+  GNUTLS_EXTENSION_INNER_APPLICATION = 37703,
+  GNUTLS_EXTENSION_SAFE_RENEGOTIATION = 65281, /* aka: 0xff01 */
 } extensions_t;
 
 typedef enum
@@ -254,6 +255,8 @@ typedef struct
 
 #define MAX_SERVER_NAME_EXTENSIONS 3
 
+#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];
@@ -262,6 +265,14 @@ typedef struct
   opaque srp_username[MAX_SRP_USERNAME + 1];
   int gnutls_ia_enable, gnutls_ia_peer_enable;
   int gnutls_ia_allowskip, gnutls_ia_peer_allowskip;
+
+  /* Safe renegotiation. */
+  uint8_t client_verify_data[MAX_VERIFY_DATA_SIZE]; 
+  size_t client_verify_data_len;
+  uint8_t server_verify_data[MAX_VERIFY_DATA_SIZE];
+  size_t server_verify_data_len;
+  uint8_t ri_extension_data[MAX_VERIFY_DATA_SIZE*2]; /* max signal is 72 bytes in s->c sslv3 */
+  size_t ri_extension_data_len;
 } tls_ext_st;
 
 /* auth_info_t structures now MAY contain malloced 
@@ -595,6 +606,12 @@ typedef struct
    */
   gnutls_datum_t recv_buffer;
 
+  int safe_renegotiation_received:1;
+  int initial_negotiation_completed:1;
+  int connection_using_safe_renegotiation:1;
+  int unsafe_renegotiation:1;
+  int initial_safe_renegotiation:1;
+
   /* If you add anything here, check _gnutls_handshake_internal_state_clear().
    */
 } internals_st;
diff -up gnutls-1.4.1/lib/gnutls_record.c.reneg gnutls-1.4.1/lib/gnutls_record.c
--- gnutls-1.4.1/lib/gnutls_record.c.reneg	2006-03-08 11:44:59.000000000 +0100
+++ gnutls-1.4.1/lib/gnutls_record.c	2010-03-09 14:18:56.000000000 +0100
@@ -731,6 +731,14 @@ record_check_type (gnutls_session_t sess
 	  if (session->security_parameters.entity == GNUTLS_SERVER)
 	    {
 	      gnutls_assert ();
+	      ret =
+		_gnutls_record_buffer_put (recv_type, session, (void *) data,
+					   data_size);
+	      if (ret < 0)
+		{
+		  gnutls_assert ();
+		  return ret;
+		}
 	      return GNUTLS_E_REHANDSHAKE;
 	    }
 
diff -up gnutls-1.4.1/lib/gnutls_state.c.reneg gnutls-1.4.1/lib/gnutls_state.c
--- gnutls-1.4.1/lib/gnutls_state.c.reneg	2006-04-26 11:19:50.000000000 +0200
+++ gnutls-1.4.1/lib/gnutls_state.c	2010-03-09 14:18:56.000000000 +0100
@@ -203,6 +203,7 @@ _gnutls_handshake_internal_state_clear (
   session->internals.adv_version_minor = 0;
   session->internals.adv_version_minor = 0;
   session->internals.direction = 0;
+  session->internals.safe_renegotiation_received = 0;
 
   /* use out of band data for the last
    * handshake messages received.
diff -up gnutls-1.4.1/lib/Makefile.am.reneg gnutls-1.4.1/lib/Makefile.am
--- gnutls-1.4.1/lib/Makefile.am.reneg	2006-06-09 11:55:18.000000000 +0200
+++ gnutls-1.4.1/lib/Makefile.am	2010-03-09 14:18:56.000000000 +0100
@@ -73,7 +73,7 @@ COBJECTS = gnutls_record.c gnutls_compre
 	ext_max_record.c gnutls_alert.c gnutls_str.c gnutls_state.c	\
 	gnutls_x509.c ext_cert_type.c gnutls_rsa_export.c		\
 	auth_rsa_export.c ext_server_name.c auth_dh_common.c		\
-	gnutls_helper.c ext_inner_application.c
+	gnutls_helper.c ext_inner_application.c ext_safe_renegotiation.c
 
 HFILES = debug.h gnutls_compress.h defines.h gnutls_cipher.h		\
 	gnutls_buffers.h gnutls_errors.h gnutls_int.h			\
@@ -90,7 +90,7 @@ HFILES = debug.h gnutls_compress.h defin
 	gnutls_rsa_export.h ext_server_name.h auth_dh_common.h		\
 	ext_srp.h gnutls_srp.h auth_srp.h auth_srp_passwd.h		\
 	gnutls_helper.h auth_psk.h auth_psk_passwd.h			\
-	ext_inner_application.h
+	ext_inner_application.h ext_safe_renegotiation.h
 
 # Separate so we can create the documentation
 
diff -up gnutls-1.4.1/lib/Makefile.in.reneg gnutls-1.4.1/lib/Makefile.in
--- gnutls-1.4.1/lib/Makefile.in.reneg	2006-07-14 12:01:17.000000000 +0200
+++ gnutls-1.4.1/lib/Makefile.in	2010-03-09 14:18:56.000000000 +0100
@@ -152,7 +152,8 @@ am__objects_2 = gnutls_record.lo gnutls_
 	ext_max_record.lo gnutls_alert.lo gnutls_str.lo \
 	gnutls_state.lo gnutls_x509.lo ext_cert_type.lo \
 	gnutls_rsa_export.lo auth_rsa_export.lo ext_server_name.lo \
-	auth_dh_common.lo gnutls_helper.lo ext_inner_application.lo
+	auth_dh_common.lo gnutls_helper.lo ext_inner_application.lo \
+	ext_safe_renegotiation.lo
 am__objects_3 = ext_srp.lo gnutls_srp.lo auth_srp.lo \
 	auth_srp_passwd.lo auth_srp_sb64.lo auth_srp_rsa.lo
 am__objects_4 = auth_psk.lo auth_psk_passwd.lo gnutls_psk.lo \
@@ -429,7 +430,7 @@ COBJECTS = gnutls_record.c gnutls_compre
 	ext_max_record.c gnutls_alert.c gnutls_str.c gnutls_state.c	\
 	gnutls_x509.c ext_cert_type.c gnutls_rsa_export.c		\
 	auth_rsa_export.c ext_server_name.c auth_dh_common.c		\
-	gnutls_helper.c ext_inner_application.c
+	gnutls_helper.c ext_inner_application.c ext_safe_renegotiation.c
 
 HFILES = debug.h gnutls_compress.h defines.h gnutls_cipher.h		\
 	gnutls_buffers.h gnutls_errors.h gnutls_int.h			\
@@ -446,7 +447,7 @@ HFILES = debug.h gnutls_compress.h defin
 	gnutls_rsa_export.h ext_server_name.h auth_dh_common.h		\
 	ext_srp.h gnutls_srp.h auth_srp.h auth_srp_passwd.h		\
 	gnutls_helper.h auth_psk.h auth_psk_passwd.h			\
-	ext_inner_application.h
+	ext_inner_application.h ext_safe_renegotiation.h
 
 
 # Separate so we can create the documentation
diff -up gnutls-1.4.1/src/cli.c.reneg gnutls-1.4.1/src/cli.c
--- gnutls-1.4.1/src/cli.c.reneg	2006-07-10 23:09:45.000000000 +0200
+++ gnutls-1.4.1/src/cli.c	2010-03-09 14:18:56.000000000 +0100
@@ -52,7 +52,7 @@
 #define MAX_BUF 4096
 
 /* global stuff here */
-int resume, starttls, insecure;
+int resume, starttls, insecure, rehandshake;
 char *hostname = NULL;
 char *service;
 int record_max_size;
@@ -474,7 +474,7 @@ handle_error (socket_st *hd, int err)
        */
     }
 
-  check_rehandshake (hd, ret);
+  check_rehandshake (hd, err);
 
   return ret;
 }
@@ -590,6 +590,23 @@ after_handshake:
 
   printf ("\n- Simple Client Mode:\n\n");
 
+  if (rehandshake)
+    {
+      ret = do_handshake (&hd);
+
+      if (ret < 0)
+	{
+	  fprintf (stderr, "*** ReHandshake has failed\n");
+	  gnutls_perror (ret);
+	  gnutls_deinit (hd.session);
+	  return 1;
+	}
+      else
+	{
+	  printf ("- ReHandshake was completed\n");
+	}
+    }
+
 #ifndef _WIN32
   signal (SIGALRM, &starttls_alarm);
 #endif
@@ -741,6 +758,7 @@ gaa_parser (int argc, char **argv)
   print_cert = info.print_cert;
   starttls = info.starttls;
   resume = info.resume;
+  rehandshake = info.rehandshake;
   insecure = info.insecure;
   service = info.port;
   record_max_size = info.record_size;
@@ -862,6 +880,11 @@ do_handshake (socket_st * socket)
       socket->secure = 1;
 
     }
+  else
+    {
+      gnutls_alert_send_appropriate(socket->session, ret);
+      shutdown (socket->fd, SHUT_RDWR);
+    }
   return ret;
 }
 
diff -up gnutls-1.4.1/src/cli-gaa.c.reneg gnutls-1.4.1/src/cli-gaa.c
--- gnutls-1.4.1/src/cli-gaa.c.reneg	2006-05-12 14:02:44.000000000 +0200
+++ gnutls-1.4.1/src/cli-gaa.c	2010-03-09 14:18:56.000000000 +0100
@@ -127,6 +127,7 @@ static void __gaa_helpsingle(char short_
 void gaa_help(void)
 {
 	printf("GNU TLS test client\nUsage:  gnutls-cli [options] hostname\n\n\n");
+	__gaa_helpsingle('e', "rehandshake", "", "Connect, establish a session and rehandshake immediately.");
 	__gaa_helpsingle('d', "debug", "integer ", "Enable debugging");
 	__gaa_helpsingle('r', "resume", "", "Connect, establish a session. Connect again and resume this session.");
 	__gaa_helpsingle('s', "starttls", "", "Connect, establish a plain session and start TLS when EOF or a SIGALRM is received.");
@@ -248,6 +249,7 @@ struct _gaainfo
 	int crlf;
 #line 20 "cli.gaa"
 	int starttls;
+	int rehandshake;
 #line 17 "cli.gaa"
 	int resume;
 #line 14 "cli.gaa"
@@ -306,7 +308,7 @@ static int gaa_error = 0;
 #define GAA_MULTIPLE_OPTION     3
 
 #define GAA_REST                0
-#define GAA_NB_OPTION           35
+#define GAA_NB_OPTION           36
 #define GAAOPTID_copyright	1
 #define GAAOPTID_version	2
 #define GAAOPTID_help	3
@@ -342,6 +344,7 @@ static int gaa_error = 0;
 #define GAAOPTID_starttls	33
 #define GAAOPTID_resume	34
 #define GAAOPTID_debug	35
+#define GAAOPTID_rehandshake	36
 
 #line 168 "gaa.skel"
 
@@ -727,6 +730,7 @@ static int gaa_get_option_num(char *str,
 			GAA_CHECK1STR("", GAAOPTID_crlf);
 			GAA_CHECK1STR("s", GAAOPTID_starttls);
 			GAA_CHECK1STR("r", GAAOPTID_resume);
+			GAA_CHECK1STR("e", GAAOPTID_rehandshake);
 
 #line 277 "gaa.skel"
         break;
@@ -766,6 +770,7 @@ static int gaa_get_option_num(char *str,
 			GAA_CHECKSTR("starttls", GAAOPTID_starttls);
 			GAA_CHECKSTR("resume", GAAOPTID_resume);
 			GAA_CHECKSTR("debug", GAAOPTID_debug);
+			GAA_CHECKSTR("rehandshake", GAAOPTID_rehandshake);
 
 #line 281 "gaa.skel"
 	break;
@@ -1098,6 +1103,12 @@ static int gaa_try(int gaa_num, int gaa_
 
 		return GAA_OK;
 		break;
+	case GAAOPTID_rehandshake:
+	OK = 0;
+{ gaaval->rehandshake = 1 ;};
+
+		return GAA_OK;
+		break;
 	case GAAOPTID_resume:
 	OK = 0;
 #line 18 "cli.gaa"
@@ -1157,7 +1168,7 @@ int gaa(int argc, char **argv, gaainfo *
 	gaaval->x509_keyfile=NULL; gaaval->x509_certfile=NULL; gaaval->crlf = 0; gaaval->xml = 0;
 	gaaval->srp_username=NULL; gaaval->srp_passwd=NULL; gaaval->fmtder = 0; gaaval->starttls =0; 
 	gaaval->debug = 0; gaaval->print_cert = 0; gaaval->verbose = 0; gaaval->psk_key = NULL; 
-	gaaval->psk_username = NULL; ;};
+	gaaval->psk_username = NULL; gaaval->rehandshake = 0; ;};
 
     }
     inited = 1;
diff -up gnutls-1.4.1/src/cli-gaa.h.reneg gnutls-1.4.1/src/cli-gaa.h
--- gnutls-1.4.1/src/cli-gaa.h.reneg	2006-03-08 11:20:00.000000000 +0100
+++ gnutls-1.4.1/src/cli-gaa.h	2010-03-09 14:18:56.000000000 +0100
@@ -80,6 +80,7 @@ struct _gaainfo
 	int crlf;
 #line 20 "cli.gaa"
 	int starttls;
+	int rehandshake;
 #line 17 "cli.gaa"
 	int resume;
 #line 14 "cli.gaa"
diff -up gnutls-1.4.1/src/serv.c.reneg gnutls-1.4.1/src/serv.c
--- gnutls-1.4.1/src/serv.c.reneg	2006-07-10 23:09:09.000000000 +0200
+++ gnutls-1.4.1/src/serv.c	2010-03-09 14:18:56.000000000 +0100
@@ -998,7 +998,7 @@ main (int argc, char **argv)
 			ret =
 			  gnutls_alert_send_appropriate (j->tls_session, r);
 		      }
-		    while (ret == GNUTLS_E_AGAIN);
+		    while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
 		    j->http_state = HTTP_STATE_CLOSING;
 		  }
 		else if (r == 0)
@@ -1029,14 +1029,37 @@ 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);
-		      }
-
+		        fprintf(stderr, "*** Received hello message\n");
+		        do 
+		          {
+		            r = gnutls_handshake (j->tls_session);
+                          } 
+                        while (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN);
+                        if (r < 0) 
+                          {
+
+  		            do
+		              {
+			        ret = gnutls_alert_send_appropriate (j->tls_session, r);
+		              }
+		            while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
+
+                            GERR (r);
+ 		            j->http_state = HTTP_STATE_CLOSING;
+                          }
+                      }
+                    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
 		  {