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 13:22:20 +0200
commit648bf9b00e1cbf45c6d05fab07e91fad97e6926d (patch)
tree492b008f41b2224b928109601120cede61e3d54b
parent379d9fbe75b30013ba217d5478c9bf57e7ae459e (diff)
downloadgnutls-648bf9b00e1cbf45c6d05fab07e91fad97e6926d.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_handshake.c15
-rw-r--r--lib/gnutls_int.h6
-rw-r--r--lib/gnutls_state.c2
3 files changed, 14 insertions, 9 deletions
diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c
index 5e2c898170..4268903b31 100644
--- a/lib/gnutls_handshake.c
+++ b/lib/gnutls_handshake.c
@@ -2616,12 +2616,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/gnutls_int.h b/lib/gnutls_int.h
index 8283b22936..e32cbfa8ef 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -966,9 +966,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/gnutls_state.c b/lib/gnutls_state.c
index a25052ee1d..3a19a17ed1 100644
--- a/lib/gnutls_state.c
+++ b/lib/gnutls_state.c
@@ -263,7 +263,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;
}