DTLS has to maintain timers to retransmit lost packets. This is done  
by setting a socket timeout and initiating the retransmission on  
return of EAGAIN of a read call. This has a serious drawback when the  
peer lost (or an attacker intercepted) a handshake message and keeps  
sending application data. The socket timeout and therefor the  
retransmission will never occur. This patch adds another timer that  
works parallel to the socket timer with the same timeout value, so  
that the retransmission can be done even when the peer keeps sending  
data.


--- crypto/bio/bio.h    2008-04-02 13:37:23.000000000 +0200
+++ crypto/bio/bio.h    2009-01-29 11:29:34.000000000 +0100
@@ -158,6 +158,7 @@

  #define BIO_CTRL_DGRAM_SET_PEER           44 /* Destination for the  
data */

+#define BIO_CTRL_DGRAM_SET_TIMEOUT        45

  /* modifiers */
  #define BIO_FP_READ           0x02

--- crypto/bio/bss_dgram.c      2008-09-15 07:45:36.000000000 +0200
+++ crypto/bio/bss_dgram.c      2009-01-29 11:31:11.000000000 +0100
@@ -104,6 +104,8 @@
        unsigned int connected;
        unsigned int _errno;
        unsigned int mtu;
+       struct timeval hstimeoutdiff;
+       struct timeval hstimeout;
        } bio_dgram_data;

  BIO_METHOD *BIO_s_datagram(void)
@@ -196,6 +198,22 @@
                                BIO_set_retry_read(b);
                                data->_errno = get_last_socket_error();
                                }
+                       memset(&(data->hstimeout), 0, sizeof(struct timeval));
+                       }
+               else
+                       {
+                       if (data->hstimeout.tv_sec > 0 || 
data->hstimeout.tv_usec > 0)
+                               {
+                               struct timeval curtime;
+                               gettimeofday(&curtime, NULL);
+                               if (curtime.tv_sec >= data->hstimeout.tv_sec &&
+                                       curtime.tv_usec >= 
data->hstimeout.tv_usec)
+                                       {
+                                       data->_errno = EAGAIN;
+                                       ret = -1;
+                                       memset(&(data->hstimeout), 0, 
sizeof(struct timeval));
+                                       }
+                               }
                        }
                }
        return(ret);
@@ -345,6 +363,23 @@

          memcpy(&(data->peer), to, sizeof(struct sockaddr));
          break;
+       case BIO_CTRL_DGRAM_SET_TIMEOUT:
+               if (num > 0)
+                       {
+                       gettimeofday(&(data->hstimeout), NULL);
+                       data->hstimeout.tv_sec += data->hstimeoutdiff.tv_sec;
+                       data->hstimeout.tv_usec += data->hstimeoutdiff.tv_usec;
+                       if (data->hstimeout.tv_usec >= 1000000)
+                               {
+                               data->hstimeout.tv_sec++;
+                               data->hstimeout.tv_usec -= 1000000;
+                               }
+                       }
+               else
+                       {
+                       memset(&(data->hstimeout), 0, sizeof(struct timeval));
+                       }
+               break;
  #if defined(SO_RCVTIMEO)
        case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT:
  #ifdef OPENSSL_SYS_WINDOWS
@@ -360,6 +395,7 @@
                        sizeof(struct timeval)) < 0)
                        { perror("setsockopt"); ret = -1; }
  #endif
+               memcpy(&(data->hstimeoutdiff), ptr, sizeof(struct timeval));
                break;
        case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT:
  #ifdef OPENSSL_SYS_WINDOWS

--- ssl/d1_clnt.c       2008-06-04 20:35:25.000000000 +0200
+++ ssl/d1_clnt.c       2009-01-29 11:29:34.000000000 +0100
@@ -229,6 +229,7 @@
                        /* every DTLS ClientHello resets Finished MAC */
                        ssl3_init_finished_mac(s);

+                       BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 
1, NULL);
                        ret=dtls1_client_hello(s);
                        if (ret <= 0) goto end;

@@ -254,6 +255,7 @@
                        if (ret <= 0) goto end;
                        else
                                {
+                               BIO_ctrl(SSL_get_rbio(s), 
BIO_CTRL_DGRAM_SET_TIMEOUT, 0, NULL);
                                if (s->hit)
                                        s->state=SSL3_ST_CR_FINISHED_A;
                                else
@@ -268,6 +270,7 @@
                        ret = dtls1_get_hello_verify(s);
                        if ( ret <= 0)
                                goto end;
+                       BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 
0, NULL);
                        if ( s->d1->send_cookie) /* start again, with a cookie 
*/
                                s->state=SSL3_ST_CW_CLNT_HELLO_A;
                        else
@@ -329,6 +332,7 @@
                case SSL3_ST_CW_CERT_B:
                case SSL3_ST_CW_CERT_C:
                case SSL3_ST_CW_CERT_D:
+                       BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 
1, NULL);
                        ret=dtls1_send_client_certificate(s);
                        if (ret <= 0) goto end;
                        s->state=SSL3_ST_CW_KEY_EXCH_A;
@@ -337,6 +341,7 @@

                case SSL3_ST_CW_KEY_EXCH_A:
                case SSL3_ST_CW_KEY_EXCH_B:
+                       BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 
1, NULL);
                        ret=dtls1_send_client_key_exchange(s);
                        if (ret <= 0) goto end;
                        l=s->s3->tmp.new_cipher->algorithms;
@@ -359,6 +364,7 @@

                case SSL3_ST_CW_CERT_VRFY_A:
                case SSL3_ST_CW_CERT_VRFY_B:
+                       BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 
1, NULL);
                        ret=dtls1_send_client_verify(s);
                        if (ret <= 0) goto end;
                        s->state=SSL3_ST_CW_CHANGE_A;
@@ -368,6 +374,7 @@

                case SSL3_ST_CW_CHANGE_A:
                case SSL3_ST_CW_CHANGE_B:
+                       BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 
1, NULL);
                        ret=dtls1_send_change_cipher_spec(s,
                                SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B);
                        if (ret <= 0) goto end;
@@ -402,6 +409,7 @@

                case SSL3_ST_CW_FINISHED_A:
                case SSL3_ST_CW_FINISHED_B:
+                       BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 
1, NULL);
                        ret=dtls1_send_finished(s,
                                SSL3_ST_CW_FINISHED_A,SSL3_ST_CW_FINISHED_B,
                                s->method->ssl3_enc->client_finished_label,
@@ -437,6 +445,7 @@
                        ret=ssl3_get_finished(s,SSL3_ST_CR_FINISHED_A,
                                SSL3_ST_CR_FINISHED_B);
                        if (ret <= 0) goto end;
+                       BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 
0, NULL);

                        if (s->hit)
                                s->state=SSL3_ST_CW_CHANGE_A;

--- ssl/d1_srvr.c       2008-09-14 16:02:01.000000000 +0200
+++ ssl/d1_srvr.c       2009-01-29 11:29:34.000000000 +0100
@@ -247,6 +247,7 @@
                case SSL3_ST_SW_HELLO_REQ_B:

                        s->shutdown=0;
+                       BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 
1, NULL);
                        ret=dtls1_send_hello_request(s);
                        if (ret <= 0) goto end;
                        s->s3->tmp.next_state=SSL3_ST_SW_HELLO_REQ_C;
@@ -267,6 +268,7 @@
                        s->shutdown=0;
                        ret=ssl3_get_client_hello(s);
                        if (ret <= 0) goto end;
+                       BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 
0, NULL);
                        s->new_session = 2;

                        if ( s->d1->send_cookie)
@@ -280,6 +282,7 @@
                case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A:
                case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B:

+                       BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 
1, NULL);
                        ret = dtls1_send_hello_verify_request(s);
                        if ( ret <= 0) goto end;
                        s->d1->send_cookie = 0;
@@ -293,6 +296,7 @@
                        
                case SSL3_ST_SW_SRVR_HELLO_A:
                case SSL3_ST_SW_SRVR_HELLO_B:
+                       BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 
1, NULL);
                        ret=dtls1_send_server_hello(s);
                        if (ret <= 0) goto end;

@@ -308,6 +312,7 @@
                        /* Check if it is anon DH */
                        if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL))
                                {
+                               BIO_ctrl(SSL_get_rbio(s), 
BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL);
                                ret=dtls1_send_server_certificate(s);
                                if (ret <= 0) goto end;
                                }
@@ -349,6 +354,7 @@
                                )
                            )
                                {
+                               BIO_ctrl(SSL_get_rbio(s), 
BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL);
                                ret=dtls1_send_server_key_exchange(s);
                                if (ret <= 0) goto end;
                                }
@@ -385,6 +391,7 @@
                        else
                                {
                                s->s3->tmp.cert_request=1;
+                               BIO_ctrl(SSL_get_rbio(s), 
BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL);
                                ret=dtls1_send_certificate_request(s);
                                if (ret <= 0) goto end;
  #ifndef NETSCAPE_HANG_BUG
@@ -399,6 +406,7 @@

                case SSL3_ST_SW_SRVR_DONE_A:
                case SSL3_ST_SW_SRVR_DONE_B:
+                       BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 
1, NULL);
                        ret=dtls1_send_server_done(s);
                        if (ret <= 0) goto end;
                        s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
@@ -426,6 +434,7 @@
                        ret = ssl3_check_client_hello(s);
                        if (ret <= 0)
                                goto end;
+                       BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 
0, NULL);
                        if (ret == 2)
                                s->state = SSL3_ST_SR_CLNT_HELLO_C;
                        else {
@@ -433,6 +442,7 @@
                                 * have not asked for it :-) */
                                ret=ssl3_get_client_certificate(s);
                                if (ret <= 0) goto end;
+                               BIO_ctrl(SSL_get_rbio(s), 
BIO_CTRL_DGRAM_SET_TIMEOUT, 0, NULL);
                                s->init_num=0;
                                s->state=SSL3_ST_SR_KEY_EXCH_A;
                        }
@@ -442,6 +452,7 @@
                case SSL3_ST_SR_KEY_EXCH_B:
                        ret=ssl3_get_client_key_exchange(s);
                        if (ret <= 0) goto end;
+                       BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 
0, NULL);
                        s->state=SSL3_ST_SR_CERT_VRFY_A;
                        s->init_num=0;

@@ -462,6 +473,7 @@
                        /* we should decide if we expected this one */
                        ret=ssl3_get_cert_verify(s);
                        if (ret <= 0) goto end;
+                       BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 
0, NULL);

                        s->state=SSL3_ST_SR_FINISHED_A;
                        s->init_num=0;
@@ -472,6 +484,7 @@
                        ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A,
                                SSL3_ST_SR_FINISHED_B);
                        if (ret <= 0) goto end;
+                       BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 
0, NULL);
                        if (s->hit)
                                s->state=SSL_ST_OK;
                        else


______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
Development Mailing List                       openssl-dev@openssl.org
Automated List Manager                           majord...@openssl.org

Reply via email to