Blob Blame History Raw
diff -up openssl-1.0.1e/ssl/d1_pkt.c.dtls1-replay openssl-1.0.1e/ssl/d1_pkt.c
--- openssl-1.0.1e/ssl/d1_pkt.c.dtls1-replay	2016-09-20 16:29:36.767447143 +0200
+++ openssl-1.0.1e/ssl/d1_pkt.c	2016-09-20 16:44:56.654893514 +0200
@@ -178,7 +178,7 @@ static int dtls1_record_needs_buffering(
 #endif
 static int dtls1_buffer_record(SSL *s, record_pqueue *q,
 	unsigned char *priority);
-static int dtls1_process_record(SSL *s);
+static int dtls1_process_record(SSL *s, DTLS1_BITMAP *bitmap);
 
 /* copy buffered record into SSL structure */
 static int
@@ -304,32 +304,84 @@ static int
 dtls1_process_buffered_records(SSL *s)
     {
     pitem *item;
-    
+    SSL3_BUFFER *rb;
+    SSL3_RECORD *rr;
+    DTLS1_BITMAP *bitmap;
+    unsigned int is_next_epoch;
+    int replayok = 1;
+
     item = pqueue_peek(s->d1->unprocessed_rcds.q);
     if (item)
         {
         /* Check if epoch is current. */
         if (s->d1->unprocessed_rcds.epoch != s->d1->r_epoch)
-            return(1);  /* Nothing to do. */
-        
+            return 1;         /* Nothing to do. */
+
+        rr = &s->s3->rrec;
+        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);
-            if ( ! dtls1_process_record(s))
-                return(0);
-            if(dtls1_buffer_record(s, &(s->d1->processed_rcds),
-                s->s3->rrec.seq_num)<0)
-                return -1;
-            }
+            bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch);
+	    if (bitmap == NULL)
+		{
+                /*
+                 * Should not happen. This will only ever be NULL when the
+                 * current record is from a different epoch. But that cannot
+                 * be the case because we already checked the epoch above
+                 */
+                SSLerr(SSL_F_DTLS1_PROCESS_BUFFERED_RECORDS,
+                        ERR_R_INTERNAL_ERROR);
+                return 0;
+		}
+#ifndef OPENSSL_NO_SCTP
+	    /* Only do replay check if no SCTP bio */
+	    if (!BIO_dgram_is_sctp(SSL_get_rbio(s)))
+#endif
+		{
+                /*
+                 * Check whether this is a repeat, or aged record. We did this
+                 * check once already when we first received the record - but
+                 * we might have updated the window since then due to
+                 * records we subsequently processed.
+                 */
+                replayok = dtls1_record_replay_check(s, bitmap);
+		}
+
+            if (!replayok || !dtls1_process_record(s, bitmap))
+		{
+                /* dump this record */
+                rr->length = 0;
+                s->packet_length = 0;
+                continue;
+		}
+
+            if (dtls1_buffer_record(s, &(s->d1->processed_rcds),
+                                    s->s3->rrec.seq_num) < 0)
+                return 0;
         }
+    }
 
     /* sync epoch numbers once all the unprocessed records 
      * have been processed */
     s->d1->processed_rcds.epoch = s->d1->r_epoch;
     s->d1->unprocessed_rcds.epoch = s->d1->r_epoch + 1;
 
-    return(1);
+    return 1;
     }
 
 
@@ -379,7 +431,7 @@ dtls1_get_buffered_record(SSL *s)
 #endif
 
 static int
-dtls1_process_record(SSL *s)
+dtls1_process_record(SSL *s, DTLS1_BITMAP *bitmap)
 {
 	int i,al;
 	int enc_err;
@@ -535,6 +587,10 @@ printf("\n");
 
 	/* we have pulled in a full packet so zero things */
 	s->packet_length=0;
+
+	/* Mark receipt of record. */
+	dtls1_record_bitmap_update(s, bitmap);
+
 	return(1);
 
 f_err:
@@ -565,9 +621,10 @@ 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. */
-	if(dtls1_process_buffered_records(s)<0)
+	if(!dtls1_process_buffered_records(s))
 		return -1;
 
 	/* if we're renegotiating, then there may be buffered records */
@@ -575,7 +632,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)) 
@@ -707,20 +763,18 @@ again:
 			{
 			if(dtls1_buffer_record(s, &(s->d1->unprocessed_rcds), rr->seq_num)<0)
 				return -1;
-			dtls1_record_bitmap_update(s, bitmap);/* Mark receipt of record. */
 			}
 		rr->length = 0;
 		s->packet_length = 0;
 		goto again;
 		}
 
-	if (!dtls1_process_record(s))
+	if (!dtls1_process_record(s, bitmap))
 		{
 		rr->length = 0;
 		s->packet_length = 0;  /* dump this record */
 		goto again;   /* get another record */
 		}
-	dtls1_record_bitmap_update(s, bitmap);/* Mark receipt of record. */
 
 	return(1);
 
@@ -1811,8 +1865,13 @@ 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))
         {
diff -up openssl-1.0.1e/ssl/ssl_err.c.dtls1-replay openssl-1.0.1e/ssl/ssl_err.c
--- openssl-1.0.1e/ssl/ssl_err.c.dtls1-replay	2016-09-20 14:55:57.789311197 +0200
+++ openssl-1.0.1e/ssl/ssl_err.c	2016-09-20 16:45:49.827132881 +0200
@@ -1,6 +1,6 @@
 /* ssl/ssl_err.c */
 /* ====================================================================
- * Copyright (c) 1999-2011 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1999-2016 The OpenSSL Project.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -92,6 +92,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
 {ERR_FUNC(SSL_F_DTLS1_HEARTBEAT),	"DTLS1_HEARTBEAT"},
 {ERR_FUNC(SSL_F_DTLS1_OUTPUT_CERT_CHAIN),	"DTLS1_OUTPUT_CERT_CHAIN"},
 {ERR_FUNC(SSL_F_DTLS1_PREPROCESS_FRAGMENT),	"DTLS1_PREPROCESS_FRAGMENT"},
+{ERR_FUNC(SSL_F_DTLS1_PROCESS_BUFFERED_RECORDS),	"DTLS1_PROCESS_BUFFERED_RECORDS"},
 {ERR_FUNC(SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE),	"DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE"},
 {ERR_FUNC(SSL_F_DTLS1_PROCESS_RECORD),	"DTLS1_PROCESS_RECORD"},
 {ERR_FUNC(SSL_F_DTLS1_READ_BYTES),	"DTLS1_READ_BYTES"},
diff -up openssl-1.0.1e/ssl/ssl.h.dtls1-replay openssl-1.0.1e/ssl/ssl.h
--- openssl-1.0.1e/ssl/ssl.h.dtls1-replay	2016-09-20 16:29:36.768447167 +0200
+++ openssl-1.0.1e/ssl/ssl.h	2016-09-20 16:30:42.981991082 +0200
@@ -2023,6 +2023,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_F_DTLS1_HEARTBEAT				 305
 #define SSL_F_DTLS1_OUTPUT_CERT_CHAIN			 255
 #define SSL_F_DTLS1_PREPROCESS_FRAGMENT			 288
+#define SSL_F_DTLS1_PROCESS_BUFFERED_RECORDS		 424
 #define SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE		 256
 #define SSL_F_DTLS1_PROCESS_RECORD			 257
 #define SSL_F_DTLS1_READ_BYTES				 258