diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2016-10-14 10:22:07 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2016-10-14 11:39:02 +0200 |
commit | 2e03a21f0d038cff25e7920ebc3bb8e6a89ea2ce (patch) | |
tree | 15520bdaaea5b6e2bd2d8295be14d85dc4b2fc7f | |
parent | cc13856fd3bff6cc1918851ae2c3618a3453fbe5 (diff) | |
download | gnutls-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.h | 6 | ||||
-rw-r--r-- | lib/handshake.c | 15 | ||||
-rw-r--r-- | lib/state.c | 2 |
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; } |