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