Don't allow too many consecutive warning alerts
authorMatt Caswell <matt@openssl.org>
Wed, 21 Sep 2016 13:48:16 +0000 (14:48 +0100)
committerMatt Caswell <matt@openssl.org>
Wed, 21 Sep 2016 19:14:16 +0000 (20:14 +0100)
Certain warning alerts are ignored if they are received. This can mean that
no progress will be made if one peer continually sends those warning alerts.
Implement a count so that we abort the connection if we receive too many.

Issue reported by Shi Lei.

Reviewed-by: Rich Salz <rsalz@openssl.org>
ssl/d1_pkt.c
ssl/s3_pkt.c
ssl/ssl.h
ssl/ssl_locl.h

index df2e42e988f7e65f6525a633bcdb59f1eb24c585..7a02459f2b7876bfbfbbbe91e7d29fe4b16f4c4f 100644 (file)
@@ -951,6 +951,13 @@ int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
         goto start;
     }
 
+    /*
+     * Reset the count of consecutive warning alerts if we've got a non-empty
+     * record that isn't an alert.
+     */
+    if (rr->type != SSL3_RT_ALERT && rr->length != 0)
+        s->cert->alert_count = 0;
+
     /* we now have a packet which can be read and processed */
 
     if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec,
@@ -1217,6 +1224,14 @@ int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
 
         if (alert_level == SSL3_AL_WARNING) {
             s->s3->warn_alert = alert_descr;
+
+            s->cert->alert_count++;
+            if (s->cert->alert_count == MAX_WARN_ALERT_COUNT) {
+                al = SSL_AD_UNEXPECTED_MESSAGE;
+                SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_TOO_MANY_WARN_ALERTS);
+                goto f_err;
+            }
+
             if (alert_descr == SSL_AD_CLOSE_NOTIFY) {
 #ifndef OPENSSL_NO_SCTP
                 /*
index df124cf52caf019f665a4f794196a8fe4fe32c5b..be37ef0e50d8b00508cb0b5757522615aebc8050 100644 (file)
@@ -1229,6 +1229,13 @@ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
             return (ret);
     }
 
+    /*
+     * Reset the count of consecutive warning alerts if we've got a non-empty
+     * record that isn't an alert.
+     */
+    if (rr->type != SSL3_RT_ALERT && rr->length != 0)
+        s->cert->alert_count = 0;
+
     /* we now have a packet which can be read and processed */
 
     if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec,
@@ -1443,6 +1450,14 @@ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
 
         if (alert_level == SSL3_AL_WARNING) {
             s->s3->warn_alert = alert_descr;
+
+            s->cert->alert_count++;
+            if (s->cert->alert_count == MAX_WARN_ALERT_COUNT) {
+                al = SSL_AD_UNEXPECTED_MESSAGE;
+                SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_TOO_MANY_WARN_ALERTS);
+                goto f_err;
+            }
+
             if (alert_descr == SSL_AD_CLOSE_NOTIFY) {
                 s->shutdown |= SSL_RECEIVED_SHUTDOWN;
                 return (0);
index 2638755891fc65a02a0aa2ffe4478da05791bc29..90aeb0ce4e1ead55327433257a38765024865bc4 100644 (file)
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -3107,6 +3107,7 @@ void ERR_load_SSL_strings(void);
 # define SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST             157
 # define SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST 233
 # define SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG    234
+# define SSL_R_TOO_MANY_WARN_ALERTS                       409
 # define SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER            235
 # define SSL_R_UNABLE_TO_DECODE_DH_CERTS                  236
 # define SSL_R_UNABLE_TO_DECODE_ECDH_CERTS                313
index e358031db41459d08afc43a8f60b71c37d8dff17..6df725f7d73afa50e1fbdef44be004384b32d271 100644 (file)
@@ -591,6 +591,8 @@ typedef struct {
  */
 # define SSL_EXT_FLAG_SENT       0x2
 
+# define MAX_WARN_ALERT_COUNT    5
+
 typedef struct {
     custom_ext_method *meths;
     size_t meths_count;
@@ -698,6 +700,8 @@ typedef struct cert_st {
     unsigned char *alpn_proposed;   /* server */
     unsigned int alpn_proposed_len;
     int alpn_sent;                  /* client */
+    /* Count of the number of consecutive warning alerts received */
+    unsigned int alert_count;
 } CERT;
 
 typedef struct sess_cert_st {