summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2016-10-14 10:22:07 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2016-10-14 11:39:02 +0200
commit2e03a21f0d038cff25e7920ebc3bb8e6a89ea2ce (patch)
tree15520bdaaea5b6e2bd2d8295be14d85dc4b2fc7f
parentcc13856fd3bff6cc1918851ae2c3618a3453fbe5 (diff)
downloadgnutls-tmp-multi-alert.tar.gz
handshake: set a maximum number of warning messages that can be received per handshaketmp-multi-alert
That is to avoid DoS due to the assymetry of cost of sending an alert vs the cost of processing.
-rw-r--r--lib/gnutls_int.h6
-rw-r--r--lib/handshake.c15
-rw-r--r--lib/state.c2
3 files changed, 14 insertions, 9 deletions
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index 11f4f41f30..aa757316ff 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -976,9 +976,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;
/* should be non-zero when a handshake is in progress */
bool handshake_in_progress;
diff --git a/lib/handshake.c b/lib/handshake.c
index 8224077083..f81dd74beb 100644
--- a/lib/handshake.c
+++ b/lib/handshake.c
@@ -2675,12 +2675,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); \
/* do not allow non-fatal errors at this point */ \
diff --git a/lib/state.c b/lib/state.c
index 866019e689..08861f017b 100644
--- a/lib/state.c
+++ b/lib/state.c
@@ -287,7 +287,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;
}