When handshake messages can't be reassembled because a fragment got  
lost, the ChangeCipherSpec included in the same flight was still  
processed. The new mastersecret has not been calculated yet, so random  
memory is used causing the connection to fail. This patch drops every  
ChangeCipherSpec which arrives before all previous messages are  
processed. It doesn't have to be buffered because always the entire  
flight is repeated, so it will be sent again anyway. This patch also  
fixes wrong socket timing causing retransmissions to be sent later  
than necessary. Finally this patch also fixes a problem with stale  
retransmits of Finished messages of a previous handshake when a new  
one is initiated. It will be dropped instead of buffered and processed  
after the ChangeCipherSpec, if it arrives before the ServerHello, when  
it obviously can't belong to the current handshake. Otherwise the  
connection fails with unexpected message.

Thanks to Daniel Mentz for providing hints!



--- crypto/bio/bss_dgram.c      18 May 2009 16:11:58 -0000      1.7.2.12
+++ crypto/bio/bss_dgram.c      4 Jun 2009 19:59:10 -0000
@@ -220,9 +220,10 @@
                /* Adjust socket timeout if next handhake message timer
                 * will expire earlier.
                 */
-               if (data->socket_timeout.tv_sec < timeleft.tv_sec ||
+               if ((data->socket_timeout.tv_sec == 0 && data- 
 >socket_timeout.tv_usec == 0) ||
+                       (data->socket_timeout.tv_sec > timeleft.tv_sec) ||
                        (data->socket_timeout.tv_sec == timeleft.tv_sec &&
-                        data->socket_timeout.tv_usec <= timeleft.tv_usec))
+                        data->socket_timeout.tv_usec >= timeleft.tv_usec))
                        {
  #ifdef OPENSSL_SYS_WINDOWS
                        timeout = timeleft.tv_sec * 1000 + timeleft.tv_usec / 
1000;

--- ssl/d1_both.c       16 May 2009 16:22:11 -0000      1.14.2.9
+++ ssl/d1_both.c       4 Jun 2009 19:59:11 -0000
@@ -569,9 +569,13 @@
        item = pqueue_find(s->d1->buffered_messages, seq64be);
        
        /* Discard the message if sequence number was already there, is
-        * too far in the future or the fragment is already in the queue */
+        * too far in the future, already in the queue or if we received
+        * a FINISHED before the SERVER_HELLO, which then must be a stale
+        * retransmit.
+        */
        if (msg_hdr->seq <= s->d1->handshake_read_seq ||
-               msg_hdr->seq > s->d1->handshake_read_seq + 10 || item != NULL)
+               msg_hdr->seq > s->d1->handshake_read_seq + 10 || item != NULL ||
+               s->d1->handshake_read_seq == 0 && msg_hdr->type == 
SSL3_MT_FINISHED)
                {
                unsigned char devnull [256];


--- ssl/d1_clnt.c       31 May 2009 17:11:24 -0000      1.16.2.8
+++ ssl/d1_clnt.c       4 Jun 2009 19:59:12 -0000
@@ -442,7 +442,7 @@

                case SSL3_ST_CR_FINISHED_A:
                case SSL3_ST_CR_FINISHED_B:
-
+                       s->d1->change_cipher_spec_ok = 1;
                        ret=ssl3_get_finished(s,SSL3_ST_CR_FINISHED_A,
                                SSL3_ST_CR_FINISHED_B);
                        if (ret <= 0) goto end;

--- ssl/d1_pkt.c        16 May 2009 16:17:46 -0000      1.27.2.8
+++ ssl/d1_pkt.c        4 Jun 2009 19:59:12 -0000
@@ -1102,6 +1102,16 @@
                        s->msg_callback(0, s->version, 
SSL3_RT_CHANGE_CIPHER_SPEC,
                                rr->data, 1, s, s->msg_callback_arg);

+               /* We can't process a CCS now, because previous handshake
+                * messages are still missing, so just drop it.
+                */
+               if (!s->d1->change_cipher_spec_ok)
+                       {
+                       goto start;
+                       }
+
+               s->d1->change_cipher_spec_ok = 0;
+
                s->s3->change_cipher_spec=1;
                if (!ssl3_do_change_cipher_spec(s))
                        goto err;

--- ssl/d1_srvr.c       31 May 2009 17:11:24 -0000      1.20.2.5
+++ ssl/d1_srvr.c       4 Jun 2009 19:59:13 -0000
@@ -501,6 +501,7 @@
                        ret=ssl3_get_cert_verify(s);
                        if (ret <= 0) goto end;
                        dtls1_stop_timer(s);
+                       s->d1->change_cipher_spec_ok = 1;

                        s->state=SSL3_ST_SR_FINISHED_A;
                        s->init_num=0;
@@ -508,6 +509,7 @@

                case SSL3_ST_SR_FINISHED_A:
                case SSL3_ST_SR_FINISHED_B:
+                       s->d1->change_cipher_spec_ok = 1;
                        ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A,
                                SSL3_ST_SR_FINISHED_B);
                        if (ret <= 0) goto end;

--- ssl/dtls1.h 2 Jun 2009 11:23:30 -0000       1.12.2.9
+++ ssl/dtls1.h 4 Jun 2009 19:59:13 -0000
@@ -231,6 +231,7 @@
        unsigned int handshake_fragment_len;

        unsigned int retransmitting;
+       unsigned int change_cipher_spec_ok;

        } DTLS1_STATE;




Attachment: dtls-fragment-retransmission-bug-1.0.0.patch
Description: Binary data

Attachment: dtls-fragment-retransmission-bug-0.9.8.patch
Description: Binary data

Reply via email to