diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2016-10-14 10:22:07 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2016-10-14 12:50:41 +0200 |
commit | 1ffb827e45721ef56982d0ffd5c5de52376c428e (patch) | |
tree | 6d3338b816860f66ada9868825b9c582dc757fea | |
parent | 9f69b1c4eb9bb7591a05646412d290b28c37b86b (diff) | |
download | gnutls-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.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; } |