The current DTLS implementation always generates an SSL_R_UNEXPECTED_RECORD error if application data is received while handshaking. This is ok for the first handshake, but not necessary for renegotiations. Furthermore it's likely that the connection fails just because of unordered UDP packets. The DTLS specification does not mention this issue, but there is no reason not to accept belated application data while renegotiating, as long as the key material has not changed yet. With this patch the implementation will leave the handshake routine, return the application data and generate the error SSL_ERROR_WANT_READ, so that the application reads again to continue handshaking.
--- ssl/dtls1.h 2008-09-13 20:25:36.000000000 +0200 +++ ssl/dtls1.h 2009-01-27 10:39:42.000000000 +0100 @@ -178,6 +178,9 @@ /* Buffered (sent) handshake records */ pqueue sent_messages; + /* Buffered application records */ + record_pqueue buffered_app_data; + unsigned int mtu; /* max wire packet size */ struct hm_header_st w_msg_hdr; --- ssl/d1_lib.c 2008-10-13 08:43:05.000000000 +0200 +++ ssl/d1_lib.c 2009-01-14 10:20:23.000000000 +0100 @@ -114,6 +114,7 @@ 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) { @@ -121,12 +122,13 @@ } 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); } @@ -175,6 +177,15 @@ } 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); + pq_64bit_free(&(s->d1->bitmap.map)); pq_64bit_free(&(s->d1->bitmap.max_seq_num)); --- ssl/d1_pkt.c 2008-10-13 08:43:06.000000000 +0200 +++ ssl/d1_pkt.c 2009-01-27 10:35:38.000000000 +0100 @@ -703,6 +703,23 @@ * 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)) { @@ -724,9 +741,14 @@ * 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 @@ -796,15 +818,28 @@ 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) { ______________________________________________________________________ OpenSSL Project http://www.openssl.org Development Mailing List openssl-dev@openssl.org Automated List Manager majord...@openssl.org