summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2017-09-06 15:11:00 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2017-09-07 14:39:21 +0200
commitac664b9e4b98c4c220b9fc21e080361141945697 (patch)
treefc0bd762cdcabf9a17ae9d7d3568cd72564bc6be
parentbc952033c60a45b14d0515fc30a7f65c22708a5c (diff)
downloadgnutls-ac664b9e4b98c4c220b9fc21e080361141945697.tar.gz
handshake: check SCSVs prior to resuming a session
This ensures that extensions which are also available as SCSVs are parsed prior to resuming a session. This resolves an issue with openssl sending SCSV instead of an extension for the safe renegotiation. Relates #259 Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
-rw-r--r--lib/handshake.c25
-rw-r--r--lib/handshake.h2
-rw-r--r--lib/sslv2_compat.c2
3 files changed, 22 insertions, 7 deletions
diff --git a/lib/handshake.c b/lib/handshake.c
index 9a38cf8242..f96f949a3e 100644
--- a/lib/handshake.c
+++ b/lib/handshake.c
@@ -554,6 +554,10 @@ read_client_hello(gnutls_session_t session, uint8_t * data,
session->internals.resumption_requested = 1;
if (ret == 0) { /* resumed using default TLS resumption! */
+ ret = _gnutls_server_select_suite(session, suite_ptr, suite_size, 1);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
ret = resume_copy_required_values(session);
if (ret < 0)
return gnutls_assert_val(ret);
@@ -613,6 +617,10 @@ read_client_hello(gnutls_session_t session, uint8_t * data,
max_record_send_size =
session->security_parameters.max_record_send_size;
+ ret = _gnutls_server_select_suite(session, suite_ptr, suite_size, 1);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
ret = resume_copy_required_values(session);
if (ret < 0)
return gnutls_assert_val(ret);
@@ -622,7 +630,7 @@ read_client_hello(gnutls_session_t session, uint8_t * data,
/* select an appropriate cipher suite (as well as certificate)
*/
- ret = _gnutls_server_select_suite(session, suite_ptr, suite_size);
+ ret = _gnutls_server_select_suite(session, suite_ptr, suite_size, 0);
if (ret < 0) {
gnutls_assert();
return ret;
@@ -833,10 +841,13 @@ static int _gnutls_recv_finished(gnutls_session_t session)
/* This selects the best supported ciphersuite from the given ones. Then
* it adds the suite to the session and performs some checks.
+ *
+ * When @scsv_only is non-zero only the available SCSVs are parsed
+ * and acted upon.
*/
int
_gnutls_server_select_suite(gnutls_session_t session, uint8_t * data,
- unsigned int datalen)
+ unsigned int datalen, unsigned scsv_only)
{
int ret;
unsigned int i;
@@ -847,7 +858,9 @@ _gnutls_server_select_suite(gnutls_session_t session, uint8_t * data,
peer_clist.size = 0;
for (i = 0; i < datalen; i += 2) {
-#ifdef ENABLE_SSL3 /* No need to support certain SCSV's without SSL 3.0 */
+ /* we support the TLS renegotiation SCSV, even if we are
+ * not under SSL 3.0, because openssl sends this SCSV
+ * on resumption unconditionally. */
/* TLS_RENEGO_PROTECTION_REQUEST = { 0x00, 0xff } */
if (session->internals.priorities->sr != SR_DISABLED &&
data[i] == GNUTLS_RENEGO_PROTECTION_REQUEST_MAJOR &&
@@ -861,7 +874,6 @@ _gnutls_server_select_suite(gnutls_session_t session, uint8_t * data,
return retval;
}
}
-#endif
/* TLS_FALLBACK_SCSV */
if (data[i] == GNUTLS_FALLBACK_SCSV_MAJOR &&
@@ -873,7 +885,7 @@ _gnutls_server_select_suite(gnutls_session_t session, uint8_t * data,
if (gnutls_protocol_get_version(session) != max)
return gnutls_assert_val(GNUTLS_E_INAPPROPRIATE_FALLBACK);
- } else {
+ } else if (!scsv_only) {
if (peer_clist.size < MAX_CIPHERSUITE_SIZE) {
peer_clist.entry[peer_clist.size] = ciphersuite_to_entry(&data[i]);
if (peer_clist.entry[peer_clist.size] != NULL)
@@ -882,6 +894,9 @@ _gnutls_server_select_suite(gnutls_session_t session, uint8_t * data,
}
}
+ if (scsv_only)
+ return 0;
+
ret = _gnutls_figure_common_ciphersuite(session, &peer_clist, &selected);
if (ret < 0) {
return gnutls_assert_val(ret);
diff --git a/lib/handshake.h b/lib/handshake.h
index 3e24c2aeb2..41a2e9d32a 100644
--- a/lib/handshake.h
+++ b/lib/handshake.h
@@ -38,7 +38,7 @@ int _gnutls_set_client_random(gnutls_session_t session, uint8_t * rnd);
int _gnutls_find_pk_algos_in_ciphersuites(uint8_t * data, int datalen);
int _gnutls_server_select_suite(gnutls_session_t session, uint8_t * data,
- unsigned int datalen);
+ unsigned int datalen, unsigned int scsv_only);
int _gnutls_negotiate_version(gnutls_session_t session,
gnutls_protocol_t adv_version, uint8_t major, uint8_t minor);
diff --git a/lib/sslv2_compat.c b/lib/sslv2_compat.c
index 4f4b8f39fa..2887550255 100644
--- a/lib/sslv2_compat.c
+++ b/lib/sslv2_compat.c
@@ -74,7 +74,7 @@ _gnutls_handshake_select_v2_suite(gnutls_session_t session,
}
}
- ret = _gnutls_server_select_suite(session, _data, _datalen);
+ ret = _gnutls_server_select_suite(session, _data, _datalen, 0);
gnutls_free(_data);
return ret;