Fix DTLS buffered message DoS attack
[openssl.git] / ssl / d1_lib.c
index a20f30a5c21d2b414f23f7816867db138cbe433b..0ada7edf7709fee3e5851c0f2db286bac74239f5 100644 (file)
@@ -114,6 +114,12 @@ int dtls1_new(SSL *s)
 }
 
 static void dtls1_clear_queues(SSL *s)
+{
+    dtls1_clear_received_buffer(s);
+    dtls1_clear_sent_buffer(s);
+}
+
+void dtls1_clear_received_buffer(SSL *s)
 {
     pitem *item = NULL;
     hm_fragment *frag = NULL;
@@ -123,6 +129,12 @@ static void dtls1_clear_queues(SSL *s)
         dtls1_hm_fragment_free(frag);
         pitem_free(item);
     }
+}
+
+void dtls1_clear_sent_buffer(SSL *s)
+{
+    pitem *item = NULL;
+    hm_fragment *frag = NULL;
 
     while ((item = pqueue_pop(s->d1->sent_messages)) != NULL) {
         frag = (hm_fragment *)item->data;
@@ -131,6 +143,7 @@ static void dtls1_clear_queues(SSL *s)
     }
 }
 
+
 void dtls1_free(SSL *s)
 {
     DTLS_RECORD_LAYER_free(&s->rlayer);
@@ -179,10 +192,13 @@ void dtls1_clear(SSL *s)
     }
 
     ssl3_clear(s);
-    if (s->options & SSL_OP_CISCO_ANYCONNECT)
-        s->client_version = s->version = DTLS1_BAD_VER;
-    else if (s->method->version == DTLS_ANY_VERSION)
+
+    if (s->method->version == DTLS_ANY_VERSION)
         s->version = DTLS_MAX_VERSION;
+#ifndef OPENSSL_NO_DTLS1_METHOD
+    else if (s->options & SSL_OP_CISCO_ANYCONNECT)
+        s->client_version = s->version = DTLS1_BAD_VER;
+#endif
     else
         s->version = s->method->version;
 }
@@ -322,7 +338,7 @@ void dtls1_stop_timer(SSL *s)
     BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
              &(s->d1->next_timeout));
     /* Clear retransmission buffer */
-    dtls1_clear_record_buffer(s);
+    dtls1_clear_sent_buffer(s);
 }
 
 int dtls1_check_timeout_num(SSL *s)
@@ -335,8 +351,7 @@ int dtls1_check_timeout_num(SSL *s)
     if (s->d1->timeout.num_alerts > 2
         && !(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) {
         mtu =
-            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_GET_FALLBACK_MTU, 0,
-                     NULL);
+            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_GET_FALLBACK_MTU, 0, NULL);
         if (mtu < s->d1->mtu)
             s->d1->mtu = mtu;
     }
@@ -388,10 +403,13 @@ static void get_current_time(struct timeval *t)
 
     GetSystemTime(&st);
     SystemTimeToFileTime(&st, &now.ft);
+    /* re-bias to 1/1/1970 */
 # ifdef  __MINGW32__
     now.ul -= 116444736000000000ULL;
 # else
-    now.ul -= 116444736000000000UI64; /* re-bias to 1/1/1970 */
+    /* *INDENT-OFF* */
+    now.ul -= 116444736000000000UI64;
+    /* *INDENT-ON* */
 # endif
     t->tv_sec = (long)(now.ul / 10000000);
     t->tv_usec = ((int)(now.ul % 10000000)) / 10;
@@ -405,7 +423,6 @@ static void get_current_time(struct timeval *t)
 #endif
 }
 
-
 #define LISTEN_SUCCESS              2
 #define LISTEN_SEND_VERIFY_REQUEST  1
 
@@ -433,7 +450,7 @@ int DTLSv1_listen(SSL *s, BIO_ADDR *client)
     rbio = SSL_get_rbio(s);
     wbio = SSL_get_wbio(s);
 
-    if(!rbio || !wbio) {
+    if (!rbio || !wbio) {
         SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_BIO_NOT_SET);
         return -1;
     }
@@ -487,7 +504,7 @@ int DTLSv1_listen(SSL *s, BIO_ADDR *client)
         n = BIO_read(rbio, buf, SSL3_RT_MAX_PLAIN_LENGTH);
 
         if (n <= 0) {
-            if(BIO_should_retry(rbio)) {
+            if (BIO_should_retry(rbio)) {
                 /* Non-blocking IO */
                 goto end;
             }
@@ -528,7 +545,7 @@ int DTLSv1_listen(SSL *s, BIO_ADDR *client)
             goto end;
         }
 
-        if (rectype != SSL3_RT_HANDSHAKE)  {
+        if (rectype != SSL3_RT_HANDSHAKE) {
             SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_UNEXPECTED_MESSAGE);
             goto end;
         }
@@ -581,7 +598,7 @@ int DTLSv1_listen(SSL *s, BIO_ADDR *client)
         }
 
         /* Message sequence number can only be 0 or 1 */
-        if(msgseq > 2) {
+        if (msgseq > 2) {
             SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_INVALID_SEQUENCE_NUMBER);
             goto end;
         }
@@ -741,7 +758,6 @@ int DTLSv1_listen(SSL *s, BIO_ADDR *client)
                 s->msg_callback(1, 0, SSL3_RT_HEADER, buf,
                                 DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg);
 
-
             if ((tmpclient = BIO_ADDR_new()) == NULL) {
                 SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_MALLOC_FAILURE);
                 goto end;
@@ -752,14 +768,14 @@ int DTLSv1_listen(SSL *s, BIO_ADDR *client)
              * maybe they're not. We ignore errors here - some BIOs do not
              * support this.
              */
-            if(BIO_dgram_get_peer(rbio, tmpclient) > 0) {
+            if (BIO_dgram_get_peer(rbio, tmpclient) > 0) {
                 (void)BIO_dgram_set_peer(wbio, tmpclient);
             }
             BIO_ADDR_free(tmpclient);
             tmpclient = NULL;
 
             if (BIO_write(wbio, buf, reclen) < (int)reclen) {
-                if(BIO_should_retry(wbio)) {
+                if (BIO_should_retry(wbio)) {
                     /*
                      * Non-blocking IO...but we're stateless, so we're just
                      * going to drop this packet.
@@ -770,7 +786,7 @@ int DTLSv1_listen(SSL *s, BIO_ADDR *client)
             }
 
             if (BIO_flush(wbio) <= 0) {
-                if(BIO_should_retry(wbio)) {
+                if (BIO_should_retry(wbio)) {
                     /*
                      * Non-blocking IO...but we're stateless, so we're just
                      * going to drop this packet.
@@ -802,13 +818,15 @@ int DTLSv1_listen(SSL *s, BIO_ADDR *client)
      */
     ossl_statem_set_hello_verify_done(s);
 
-    /* Some BIOs may not support this. If we fail we clear the client address */
+    /*
+     * Some BIOs may not support this. If we fail we clear the client address
+     */
     if (BIO_dgram_get_peer(rbio, client) <= 0)
         BIO_ADDR_clear(client);
 
     ret = 1;
     clearpkt = 0;
-end:
+ end:
     BIO_ADDR_free(tmpclient);
     BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 0, NULL);
     if (clearpkt) {
@@ -839,12 +857,12 @@ static int dtls1_handshake_write(SSL *s)
 
 #ifndef OPENSSL_NO_HEARTBEATS
 
-#define HEARTBEAT_SIZE(payload, padding) ( \
+# define HEARTBEAT_SIZE(payload, padding) ( \
     1 /* heartbeat type */ + \
     2 /* heartbeat length */ + \
     (payload) + (padding))
 
-#define HEARTBEAT_SIZE_STD(payload) HEARTBEAT_SIZE(payload, 16)
+# define HEARTBEAT_SIZE_STD(payload) HEARTBEAT_SIZE(payload, 16)
 
 int dtls1_process_heartbeat(SSL *s, unsigned char *p, unsigned int length)
 {
@@ -984,8 +1002,7 @@ int dtls1_heartbeat(SSL *s)
     if (ret >= 0) {
         if (s->msg_callback)
             s->msg_callback(1, s->version, DTLS1_RT_HEARTBEAT,
-                            buf, size,
-                            s, s->msg_callback_arg);
+                            buf, size, s, s->msg_callback_arg);
 
         dtls1_start_timer(s);
         s->tlsext_hb_pending = 1;