diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2016-10-14 10:22:07 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2016-10-14 13:22:20 +0200 |
commit | 648bf9b00e1cbf45c6d05fab07e91fad97e6926d (patch) | |
tree | 492b008f41b2224b928109601120cede61e3d54b | |
parent | 379d9fbe75b30013ba217d5478c9bf57e7ae459e (diff) | |
download | gnutls-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.c | 15 | ||||
-rw-r--r-- | lib/gnutls_int.h | 6 | ||||
-rw-r--r-- | lib/gnutls_state.c | 2 |
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; } |