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 12:50:41 +0200
commit1ffb827e45721ef56982d0ffd5c5de52376c428e (patch)
tree6d3338b816860f66ada9868825b9c582dc757fea
parent9f69b1c4eb9bb7591a05646412d290b28c37b86b (diff)
downloadgnutls-1ffb827e45721ef56982d0ffd5c5de52376c428e.tar.gz
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.
-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;
}