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