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.
"%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
.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
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)
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
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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);
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),
#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>
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",
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
{ /* resumed! */
resume_copy_required_values (session);
session->internals.resumed = RESUME_TRUE;
+
return _gnutls_user_hello_func (session, adv_version);
}
else
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);
data_size = 36;
}
else
- { /* TLS 1.0 */
+ { /* TLS 1.0 */
ret = _gnutls_finished (session,
session->security_parameters.entity, data);
data_size = 12;
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);
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;
}
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;
}
return algo;
}
-
/* This selects the best supported ciphersuite from the given ones. Then
* it adds the suite to the session and performs some checks.
*/
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;
}
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:
{
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);
}
}
else
- { /* Server side reading a client hello */
+ { /* Server side reading a client hello */
ret = _gnutls_read_client_hello (session, data, datalen);
if (ret < 0)
}
}
+ 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;
}
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
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];
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;
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;
};
*
* "%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
"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;
}
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
*/
#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 */
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');
}
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
{