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 {