PR: 1950
authorDr. Stephen Henson <steve@openssl.org>
Fri, 5 Jun 2009 14:46:49 +0000 (14:46 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Fri, 5 Jun 2009 14:46:49 +0000 (14:46 +0000)
Submitted by: Robin Seggelmann <seggelmann@fh-muenster.de>
Reviewed by: steve@openssl.org

DTLS fragment retransmission bug.

crypto/bio/bss_dgram.c
ssl/d1_both.c
ssl/d1_clnt.c
ssl/d1_pkt.c
ssl/d1_srvr.c
ssl/dtls1.h

index 2e1a6fac33d90596f1f812a0684c745b8f4d2c1e..027cdf943b7973b174f93b8325e48294dff0785f 100644 (file)
@@ -217,12 +217,19 @@ static void dgram_adjust_rcv_timeout(BIO *b)
                        timeleft.tv_usec += 1000000;
                        }
 
+               if (timeleft.tv_sec < 0)
+                       {
+                       timeleft.tv_sec = 0;
+                       timeleft.tv_usec = 1;
+                       }
+
                /* 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;
index ebc03482f0238b81b6385f2394caa3d39726d6fd..7039d05f0e21862bee5ec980d7a08c34ac4bb57a 100644 (file)
@@ -569,9 +569,13 @@ dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok)
        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];
 
index 2364ad2f8d148a23c6957df2c8b1e28dbea5fa84..a4a438ac7978f8fc7de358416724d34a71555f5e 100644 (file)
@@ -442,7 +442,7 @@ int dtls1_connect(SSL *s)
 
                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;
index a89edbc7a7179d6bda11ea284ce9938e581149d3..394daf6258be194483a293a01f23ebdf593f1c53 100644 (file)
@@ -1102,6 +1102,16 @@ start:
                        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;
index 6d6363f04fd2c4f92e9d72efd85b3e165628e765..ac09b45ef186d6b868cdeeca3dab09677cd29af4 100644 (file)
@@ -497,6 +497,7 @@ int dtls1_accept(SSL *s)
                case SSL3_ST_SR_CERT_VRFY_A:
                case SSL3_ST_SR_CERT_VRFY_B:
 
+                       s->d1->change_cipher_spec_ok = 1;
                        /* we should decide if we expected this one */
                        ret=ssl3_get_cert_verify(s);
                        if (ret <= 0) goto end;
@@ -508,6 +509,7 @@ int dtls1_accept(SSL *s)
 
                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;
index 2fe0405011f9d293f2c99efbfe6bb454130c44ae..73af56d45c14a022ee9ee40912f6828f671c4be5 100644 (file)
@@ -231,6 +231,7 @@ typedef struct dtls1_state_st
        unsigned int handshake_fragment_len;
 
        unsigned int retransmitting;
+       unsigned int change_cipher_spec_ok;
 
        } DTLS1_STATE;