Fix DTLS unprocessed records bug
[openssl.git] / ssl / d1_pkt.c
index fe30ec7d004235d74145d38af12cfde3fb0e2ffd..1fb119da512d1919ef5c10889f4327193e0acbec 100644 (file)
@@ -319,6 +319,7 @@ static int dtls1_retrieve_buffered_record(SSL *s, record_pqueue *queue)
 static int dtls1_process_buffered_records(SSL *s)
 {
     pitem *item;
+    SSL3_BUFFER *rb;
 
     item = pqueue_peek(s->d1->unprocessed_rcds.q);
     if (item) {
@@ -326,6 +327,19 @@ static int dtls1_process_buffered_records(SSL *s)
         if (s->d1->unprocessed_rcds.epoch != s->d1->r_epoch)
             return (1);         /* Nothing to do. */
 
+        rb = &s->s3->rbuf;
+
+        if (rb->left > 0) {
+            /*
+             * We've still got data from the current packet to read. There could
+             * be a record from the new epoch in it - so don't overwrite it
+             * with the unprocessed records yet (we'll do it when we've
+             * finished reading the current packet).
+             */
+            return 1;
+        }
+
+
         /* Process all the records. */
         while (pqueue_peek(s->d1->unprocessed_rcds.q)) {
             dtls1_get_unprocessed_record(s);
@@ -581,6 +595,7 @@ int dtls1_get_record(SSL *s)
 
     rr = &(s->s3->rrec);
 
+ again:
     /*
      * The epoch may have changed.  If so, process all the pending records.
      * This is a non-blocking operation.
@@ -593,7 +608,6 @@ int dtls1_get_record(SSL *s)
         return 1;
 
     /* get something from the wire */
- again:
     /* check if we have the header */
     if ((s->rstate != SSL_ST_READ_BODY) ||
         (s->packet_length < DTLS1_RT_HEADER_LENGTH)) {
@@ -1830,8 +1844,13 @@ static DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr,
     if (rr->epoch == s->d1->r_epoch)
         return &s->d1->bitmap;
 
-    /* Only HM and ALERT messages can be from the next epoch */
+    /*
+     * Only HM and ALERT messages can be from the next epoch and only if we
+     * have already processed all of the unprocessed records from the last
+     * epoch
+     */
     else if (rr->epoch == (unsigned long)(s->d1->r_epoch + 1) &&
+             s->d1->unprocessed_rcds.epoch != s->d1->r_epoch &&
              (rr->type == SSL3_RT_HANDSHAKE || rr->type == SSL3_RT_ALERT)) {
         *is_next_epoch = 1;
         return &s->d1->next_bitmap;