Sophie

Sophie

distrib > Mageia > 5 > i586 > by-pkgid > bf312c95e3163b46257414776a42238b > files > 2

gnutls-3.2.21-1.3.mga5.src.rpm

From 1ffb827e45721ef56982d0ffd5c5de52376c428e Mon Sep 17 00:00:00 2001
From: Nikos Mavrogiannopoulos <nmav@redhat.com>
Date: Fri, 14 Oct 2016 10:22:07 +0200
Subject: [PATCH] handshake: set a maximum number of warning messages that can be received per handshake

That is to avoid DoS due to the assymetry of cost of sending an alert vs the cost
of processing.
---
 lib/gnutls_int.h |  6 +++---
 lib/handshake.c  | 15 ++++++++++-----
 lib/state.c      |  2 +-
 3 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index 11f4f41..aa75731 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -944,9 +944,9 @@ typedef struct {
 
 	/* DTLS session state */
 	dtls_st dtls;
-	/* In case of clients that don't handle GNUTLS_E_LARGE_PACKET, don't
-	 * force them into an infinite loop */
-	unsigned handshake_large_loops;
+	/* Protect from infinite loops due to GNUTLS_E_LARGE_PACKET non-handling
+	 * or due to multiple alerts being received. */
+	unsigned handshake_suspicious_loops;
 
 	/* if set it means that the master key was set using
 	 * gnutls_session_set_master() rather than being negotiated. */
diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c
index 8224077..f81dd74 100644
--- a/lib/gnutls_handshake.c
+++ b/lib/gnutls_handshake.c
@@ -2601,12 +2601,17 @@ gnutls_handshake_set_timeout(gnutls_session_t session, unsigned int ms)
 			return ret; \
 		if (ret == GNUTLS_E_GOT_APPLICATION_DATA && session->internals.initial_negotiation_completed != 0) \
 			return ret; \
-		if (ret == GNUTLS_E_LARGE_PACKET && session->internals.handshake_large_loops < 16) { \
-			session->internals.handshake_large_loops++; \
-			return ret; \
+		if (session->internals.handshake_suspicious_loops < 16) { \
+			if (ret == GNUTLS_E_LARGE_PACKET) { \
+				session->internals.handshake_suspicious_loops++; \
+				return ret; \
+			} \
+			/* a warning alert might interrupt handshake */ \
+			if (allow_alert != 0 && ret==GNUTLS_E_WARNING_ALERT_RECEIVED) { \
+				session->internals.handshake_suspicious_loops++; \
+				return ret; \
+			} \
 		} \
-                /* a warning alert might interrupt handshake */ \
-		if (allow_alert != 0 && ret==GNUTLS_E_WARNING_ALERT_RECEIVED) return ret; \
 		gnutls_assert(); \
 		ERR( str, ret); \
 		if (gnutls_error_is_fatal(ret) == 0) ret = gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); \
diff --git a/lib/gnutls_state.c b/lib/gnutls_state.c
index 866019e..08861f0 100644
--- a/lib/gnutls_state.c
+++ b/lib/gnutls_state.c
@@ -261,7 +261,7 @@ static void _gnutls_handshake_internal_state_init(gnutls_session_t session)
 
 	session->internals.resumable = RESUME_TRUE;
 
-	session->internals.handshake_large_loops = 0;
+	session->internals.handshake_suspicious_loops = 0;
 	session->internals.dtls.hsk_read_seq = 0;
 	session->internals.dtls.hsk_write_seq = 0;
 }
--
libgit2 0.24.0