From: Dr. Stephen Henson Date: Tue, 14 Apr 2009 14:20:57 +0000 (+0000) Subject: PR: 1827 X-Git-Tag: OpenSSL_1_0_0-beta2~16 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=3c0ce01cea2b601c5e20683084687b5a1b9bf331;p=oweals%2Fopenssl.git PR: 1827 Submitted by: Robin Seggelmann Approved by: steve@openssl.org Updated patch for PR #1827 --- diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c index bd28b75e84..be47541440 100644 --- a/ssl/d1_lib.c +++ b/ssl/d1_lib.c @@ -98,6 +98,7 @@ int dtls1_new(SSL *s) d1->processed_rcds.q=pqueue_new(); d1->buffered_messages = pqueue_new(); d1->sent_messages=pqueue_new(); + d1->buffered_app_data.q=pqueue_new(); if ( s->server) { @@ -105,12 +106,13 @@ int dtls1_new(SSL *s) } if( ! d1->unprocessed_rcds.q || ! d1->processed_rcds.q - || ! d1->buffered_messages || ! d1->sent_messages) + || ! d1->buffered_messages || ! d1->sent_messages || ! d1->buffered_app_data.q) { if ( d1->unprocessed_rcds.q) pqueue_free(d1->unprocessed_rcds.q); if ( d1->processed_rcds.q) pqueue_free(d1->processed_rcds.q); if ( d1->buffered_messages) pqueue_free(d1->buffered_messages); if ( d1->sent_messages) pqueue_free(d1->sent_messages); + if ( d1->buffered_app_data.q) pqueue_free(d1->buffered_app_data.q); OPENSSL_free(d1); return (0); } @@ -159,6 +161,15 @@ void dtls1_free(SSL *s) } pqueue_free(s->d1->sent_messages); + while ( (item = pqueue_pop(s->d1->buffered_app_data.q)) != NULL) + { + frag = (hm_fragment *)item->data; + OPENSSL_free(frag->fragment); + OPENSSL_free(frag); + pitem_free(item); + } + pqueue_free(s->d1->buffered_app_data.q); + OPENSSL_free(s->d1); } diff --git a/ssl/d1_pkt.c b/ssl/d1_pkt.c index 8ce567dba4..2e9d5452f7 100644 --- a/ssl/d1_pkt.c +++ b/ssl/d1_pkt.c @@ -746,6 +746,23 @@ start: * s->s3->rrec.length, - number of bytes. */ rr = &(s->s3->rrec); + /* We are not handshaking and have no data yet, + * so process data buffered during the last handshake + * in advance, if any. + */ + if (s->state == SSL_ST_OK && rr->length == 0) + { + pitem *item; + item = pqueue_pop(s->d1->buffered_app_data.q); + if (item) + { + dtls1_copy_record(s, item); + + OPENSSL_free(item->data); + pitem_free(item); + } + } + /* get new packet if necessary */ if ((rr->length == 0) || (s->rstate == SSL_ST_READ_BODY)) { @@ -767,9 +784,14 @@ start: * reset by ssl3_get_finished */ && (rr->type != SSL3_RT_HANDSHAKE)) { - al=SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_DATA_BETWEEN_CCS_AND_FINISHED); - goto err; + /* We now have application data between CCS and Finished. + * Most likely the packets were reordered on their way, so + * buffer the application data for later processing rather + * than dropping the connection. + */ + dtls1_buffer_record(s, &(s->d1->buffered_app_data), 0); + rr->length = 0; + goto start; } /* If the other end has shut down, throw anything we read away @@ -839,15 +861,28 @@ start: dest = s->d1->alert_fragment; dest_len = &s->d1->alert_fragment_len; } - /* else it's a CCS message, or it's wrong */ - else if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC) - { - /* Not certain if this is the right error handling */ - al=SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_UNEXPECTED_RECORD); - goto f_err; - } + /* else it's a CCS message, or application data or wrong */ + else if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC) + { + /* Application data while renegotiating + * is allowed. Try again reading. + */ + if (rr->type == SSL3_RT_APPLICATION_DATA) + { + BIO *bio; + s->s3->in_read_app_data=2; + bio=SSL_get_rbio(s); + s->rwstate=SSL_READING; + BIO_clear_retry_flags(bio); + BIO_set_retry_read(bio); + return(-1); + } + /* Not certain if this is the right error handling */ + al=SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_UNEXPECTED_RECORD); + goto f_err; + } if (dest_maxlen > 0) { diff --git a/ssl/dtls1.h b/ssl/dtls1.h index a267ae4377..efc8523308 100644 --- a/ssl/dtls1.h +++ b/ssl/dtls1.h @@ -196,6 +196,13 @@ typedef struct dtls1_state_st /* Buffered (sent) handshake records */ pqueue sent_messages; + /* Buffered application records. + * Only for records between CCS and Finished + * to prevent either protocol violation or + * unnecessary message loss. + */ + record_pqueue buffered_app_data; + unsigned int mtu; /* max wire packet size */ struct hm_header_st w_msg_hdr;