From e5fa864f62c096536d700d977a5eb924ad293304 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Wed, 15 Apr 2009 15:27:03 +0000 Subject: Updates from 1.0.0-stable. --- ssl/d1_both.c | 107 +++++++++++++++++++++++++++++++++++++++++++-------------- ssl/d1_clnt.c | 10 ++++++ ssl/d1_lib.c | 13 ++++++- ssl/d1_pkt.c | 72 +++++++++++++++++++++++++++++++------- ssl/d1_srvr.c | 14 ++++++++ ssl/dtls1.h | 24 +++++++++++++ ssl/ssl_locl.h | 2 ++ 7 files changed, 204 insertions(+), 38 deletions(-) (limited to 'ssl') diff --git a/ssl/d1_both.c b/ssl/d1_both.c index 87c8c9306f..9130983611 100644 --- a/ssl/d1_both.c +++ b/ssl/d1_both.c @@ -136,7 +136,6 @@ static unsigned char *dtls1_write_message_header(SSL *s, static void dtls1_set_message_header_int(SSL *s, unsigned char mt, unsigned long len, unsigned short seq_num, unsigned long frag_off, unsigned long frag_len); -static int dtls1_retransmit_buffered_messages(SSL *s); static long dtls1_get_message_fragment(SSL *s, int st1, int stn, long max, int *ok); @@ -574,30 +573,31 @@ dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok) } } - frag = dtls1_hm_fragment_new(frag_len); - if ( frag == NULL) - goto err; - - memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr)); - if (frag_len) { + frag = dtls1_hm_fragment_new(frag_len); + if ( frag == NULL) + goto err; + + memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr)); + /* read the body of the fragment (header has already been read */ i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE, frag->fragment,frag_len,0); if (i<=0 || (unsigned long)i!=frag_len) goto err; - } - memset(seq64be,0,sizeof(seq64be)); - seq64be[6] = (unsigned char)(msg_hdr->seq>>8); - seq64be[7] = (unsigned char)(msg_hdr->seq); + memset(seq64be,0,sizeof(seq64be)); + seq64be[6] = (unsigned char)(msg_hdr->seq>>8); + seq64be[7] = (unsigned char)(msg_hdr->seq); - item = pitem_new(seq64be, frag); - if ( item == NULL) - goto err; + item = pitem_new(seq64be, frag); + if ( item == NULL) + goto err; + + pqueue_insert(s->d1->buffered_messages, item); + } - pqueue_insert(s->d1->buffered_messages, item); return DTLS1_HM_FRAGMENT_RETRY; err: @@ -931,8 +931,21 @@ int dtls1_read_failed(SSL *s, int code) return dtls1_retransmit_buffered_messages(s) ; } +int +dtls1_get_queue_priority(unsigned short seq, int is_ccs) + { + /* The index of the retransmission queue actually is the message sequence number, + * since the queue only contains messages of a single handshake. However, the + * ChangeCipherSpec has no message sequence number and so using only the sequence + * will result in the CCS and Finished having the same index. To prevent this, + * the sequence number is multiplied by 2. In case of a CCS 1 is subtracted. + * This does not only differ CSS and Finished, it also maintains the order of the + * index (important for priority queues) and fits in the unsigned short variable. + */ + return seq * 2 - is_ccs; + } -static int +int dtls1_retransmit_buffered_messages(SSL *s) { pqueue sent = s->d1->sent_messages; @@ -946,8 +959,9 @@ dtls1_retransmit_buffered_messages(SSL *s) for ( item = pqueue_next(&iter); item != NULL; item = pqueue_next(&iter)) { frag = (hm_fragment *)item->data; - if ( dtls1_retransmit_message(s, frag->msg_header.seq, 0, &found) <= 0 && - found) + if ( dtls1_retransmit_message(s, + dtls1_get_queue_priority(frag->msg_header.seq, frag->msg_header.is_ccs), + 0, &found) <= 0 && found) { fprintf(stderr, "dtls1_retransmit_message() failed\n"); return -1; @@ -963,7 +977,6 @@ dtls1_buffer_message(SSL *s, int is_ccs) pitem *item; hm_fragment *frag; unsigned char seq64be[8]; - unsigned int epoch = s->d1->w_epoch; /* this function is called immediately after a message has * been serialized */ @@ -977,7 +990,6 @@ dtls1_buffer_message(SSL *s, int is_ccs) { OPENSSL_assert(s->d1->w_msg_hdr.msg_len + DTLS1_CCS_HEADER_LENGTH == (unsigned int)s->init_num); - epoch++; } else { @@ -992,11 +1004,18 @@ dtls1_buffer_message(SSL *s, int is_ccs) frag->msg_header.frag_len = s->d1->w_msg_hdr.msg_len; frag->msg_header.is_ccs = is_ccs; + /* save current state*/ + frag->msg_header.saved_retransmit_state.enc_write_ctx = s->enc_write_ctx; + frag->msg_header.saved_retransmit_state.write_hash = s->write_hash; + frag->msg_header.saved_retransmit_state.compress = s->compress; + frag->msg_header.saved_retransmit_state.session = s->session; + frag->msg_header.saved_retransmit_state.epoch = s->d1->w_epoch; + memset(seq64be,0,sizeof(seq64be)); - seq64be[0] = (unsigned char)(epoch>>8); - seq64be[1] = (unsigned char)(epoch); - seq64be[6] = (unsigned char)(frag->msg_header.seq>>8); - seq64be[7] = (unsigned char)(frag->msg_header.seq); + seq64be[6] = (unsigned char)(dtls1_get_queue_priority(frag->msg_header.seq, + frag->msg_header.is_ccs)>>8); + seq64be[7] = (unsigned char)(dtls1_get_queue_priority(frag->msg_header.seq, + frag->msg_header.is_ccs)); item = pitem_new(seq64be, frag); if ( item == NULL) @@ -1025,6 +1044,8 @@ dtls1_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off, hm_fragment *frag ; unsigned long header_length; unsigned char seq64be[8]; + struct dtls1_retransmit_state saved_state; + unsigned char save_write_sequence[8]; /* OPENSSL_assert(s->init_num == 0); @@ -1060,9 +1081,45 @@ dtls1_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off, frag->msg_header.msg_len, frag->msg_header.seq, 0, frag->msg_header.frag_len); + /* save current state */ + saved_state.enc_write_ctx = s->enc_write_ctx; + saved_state.write_hash = s->write_hash; + saved_state.compress = s->compress; + saved_state.session = s->session; + saved_state.epoch = s->d1->w_epoch; + saved_state.epoch = s->d1->w_epoch; + s->d1->retransmitting = 1; + + /* restore state in which the message was originally sent */ + s->enc_write_ctx = frag->msg_header.saved_retransmit_state.enc_write_ctx; + s->write_hash = frag->msg_header.saved_retransmit_state.write_hash; + s->compress = frag->msg_header.saved_retransmit_state.compress; + s->session = frag->msg_header.saved_retransmit_state.session; + s->d1->w_epoch = frag->msg_header.saved_retransmit_state.epoch; + + if (frag->msg_header.saved_retransmit_state.epoch == saved_state.epoch - 1) + { + memcpy(save_write_sequence, s->s3->write_sequence, sizeof(s->s3->write_sequence)); + memcpy(s->s3->write_sequence, s->d1->last_write_sequence, sizeof(s->s3->write_sequence)); + } + ret = dtls1_do_write(s, frag->msg_header.is_ccs ? - SSL3_RT_CHANGE_CIPHER_SPEC : SSL3_RT_HANDSHAKE); + SSL3_RT_CHANGE_CIPHER_SPEC : SSL3_RT_HANDSHAKE); + + /* restore current state */ + s->enc_write_ctx = saved_state.enc_write_ctx; + s->write_hash = saved_state.write_hash; + s->compress = saved_state.compress; + s->session = saved_state.session; + s->d1->w_epoch = saved_state.epoch; + + if (frag->msg_header.saved_retransmit_state.epoch == saved_state.epoch - 1) + { + memcpy(s->d1->last_write_sequence, s->s3->write_sequence, sizeof(s->s3->write_sequence)); + memcpy(s->s3->write_sequence, save_write_sequence, sizeof(s->s3->write_sequence)); + } + s->d1->retransmitting = 0; (void)BIO_flush(SSL_get_wbio(s)); diff --git a/ssl/d1_clnt.c b/ssl/d1_clnt.c index f569d4beac..c151264e56 100644 --- a/ssl/d1_clnt.c +++ b/ssl/d1_clnt.c @@ -229,6 +229,7 @@ int dtls1_connect(SSL *s) /* every DTLS ClientHello resets Finished MAC */ ssl3_init_finished_mac(s); + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL); ret=dtls1_client_hello(s); if (ret <= 0) goto end; @@ -254,6 +255,7 @@ int dtls1_connect(SSL *s) if (ret <= 0) goto end; else { + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 0, NULL); if (s->hit) s->state=SSL3_ST_CR_FINISHED_A; else @@ -268,6 +270,7 @@ int dtls1_connect(SSL *s) ret = dtls1_get_hello_verify(s); if ( ret <= 0) goto end; + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 0, NULL); if ( s->d1->send_cookie) /* start again, with a cookie */ s->state=SSL3_ST_CW_CLNT_HELLO_A; else @@ -329,6 +332,7 @@ int dtls1_connect(SSL *s) case SSL3_ST_CW_CERT_B: case SSL3_ST_CW_CERT_C: case SSL3_ST_CW_CERT_D: + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL); ret=dtls1_send_client_certificate(s); if (ret <= 0) goto end; s->state=SSL3_ST_CW_KEY_EXCH_A; @@ -337,6 +341,7 @@ int dtls1_connect(SSL *s) case SSL3_ST_CW_KEY_EXCH_A: case SSL3_ST_CW_KEY_EXCH_B: + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL); ret=dtls1_send_client_key_exchange(s); if (ret <= 0) goto end; /* EAY EAY EAY need to check for DH fix cert @@ -358,6 +363,7 @@ int dtls1_connect(SSL *s) case SSL3_ST_CW_CERT_VRFY_A: case SSL3_ST_CW_CERT_VRFY_B: + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL); ret=dtls1_send_client_verify(s); if (ret <= 0) goto end; s->state=SSL3_ST_CW_CHANGE_A; @@ -367,6 +373,7 @@ int dtls1_connect(SSL *s) case SSL3_ST_CW_CHANGE_A: case SSL3_ST_CW_CHANGE_B: + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL); ret=dtls1_send_change_cipher_spec(s, SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B); if (ret <= 0) goto end; @@ -401,6 +408,7 @@ int dtls1_connect(SSL *s) case SSL3_ST_CW_FINISHED_A: case SSL3_ST_CW_FINISHED_B: + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL); ret=dtls1_send_finished(s, SSL3_ST_CW_FINISHED_A,SSL3_ST_CW_FINISHED_B, s->method->ssl3_enc->client_finished_label, @@ -433,6 +441,7 @@ int dtls1_connect(SSL *s) ret=ssl3_get_finished(s,SSL3_ST_CR_FINISHED_A, SSL3_ST_CR_FINISHED_B); if (ret <= 0) goto end; + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 0, NULL); if (s->hit) s->state=SSL3_ST_CW_CHANGE_A; @@ -488,6 +497,7 @@ int dtls1_connect(SSL *s) /* done with handshaking */ s->d1->handshake_read_seq = 0; + s->d1->next_handshake_write_seq = 0; goto end; /* break; */ 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 dea63d694a..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) { @@ -985,7 +1020,9 @@ start: n2s(p, seq); n2l3(p, frag_off); - dtls1_retransmit_message(s, seq, frag_off, &found); + dtls1_retransmit_message(s, + dtls1_get_queue_priority(frag->msg_header.seq, 0), + frag_off, &found); if ( ! found && SSL_in_init(s)) { /* fprintf( stderr,"in init = %d\n", SSL_in_init(s)); */ @@ -1074,6 +1111,16 @@ start: goto start; } + /* If we are server, we may have a repeated FINISHED of the + * client here, then retransmit our CCS and FINISHED. + */ + if (msg_hdr.type == SSL3_MT_FINISHED) + { + dtls1_retransmit_buffered_messages(s); + rr->length = 0; + goto start; + } + if (((s->state&SSL_ST_MASK) == SSL_ST_OK) && !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)) { @@ -1728,6 +1775,7 @@ dtls1_reset_seq_numbers(SSL *s, int rw) else { seq = s->s3->write_sequence; + memcpy(s->d1->last_write_sequence, seq, sizeof(s->s3->write_sequence)); s->d1->w_epoch++; } diff --git a/ssl/d1_srvr.c b/ssl/d1_srvr.c index 1ded18df50..ebd35c7161 100644 --- a/ssl/d1_srvr.c +++ b/ssl/d1_srvr.c @@ -249,6 +249,7 @@ int dtls1_accept(SSL *s) case SSL3_ST_SW_HELLO_REQ_B: s->shutdown=0; + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL); ret=dtls1_send_hello_request(s); if (ret <= 0) goto end; s->s3->tmp.next_state=SSL3_ST_SW_HELLO_REQ_C; @@ -269,6 +270,7 @@ int dtls1_accept(SSL *s) s->shutdown=0; ret=ssl3_get_client_hello(s); if (ret <= 0) goto end; + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 0, NULL); s->new_session = 2; if (s->d1->send_cookie) @@ -282,6 +284,7 @@ int dtls1_accept(SSL *s) case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A: case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B: + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL); ret = dtls1_send_hello_verify_request(s); if ( ret <= 0) goto end; s->d1->send_cookie = 0; @@ -294,6 +297,7 @@ int dtls1_accept(SSL *s) case SSL3_ST_SW_SRVR_HELLO_A: case SSL3_ST_SW_SRVR_HELLO_B: + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL); ret=dtls1_send_server_hello(s); if (ret <= 0) goto end; @@ -309,6 +313,7 @@ int dtls1_accept(SSL *s) /* Check if it is anon DH */ if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)) { + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL); ret=dtls1_send_server_certificate(s); if (ret <= 0) goto end; } @@ -350,6 +355,7 @@ int dtls1_accept(SSL *s) ) ) { + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL); ret=dtls1_send_server_key_exchange(s); if (ret <= 0) goto end; } @@ -386,6 +392,7 @@ int dtls1_accept(SSL *s) else { s->s3->tmp.cert_request=1; + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL); ret=dtls1_send_certificate_request(s); if (ret <= 0) goto end; #ifndef NETSCAPE_HANG_BUG @@ -400,6 +407,7 @@ int dtls1_accept(SSL *s) case SSL3_ST_SW_SRVR_DONE_A: case SSL3_ST_SW_SRVR_DONE_B: + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL); ret=dtls1_send_server_done(s); if (ret <= 0) goto end; s->s3->tmp.next_state=SSL3_ST_SR_CERT_A; @@ -427,6 +435,7 @@ int dtls1_accept(SSL *s) ret = ssl3_check_client_hello(s); if (ret <= 0) goto end; + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 0, NULL); if (ret == 2) s->state = SSL3_ST_SR_CLNT_HELLO_C; else { @@ -434,6 +443,7 @@ int dtls1_accept(SSL *s) * have not asked for it :-) */ ret=ssl3_get_client_certificate(s); if (ret <= 0) goto end; + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 0, NULL); s->init_num=0; s->state=SSL3_ST_SR_KEY_EXCH_A; } @@ -443,6 +453,7 @@ int dtls1_accept(SSL *s) case SSL3_ST_SR_KEY_EXCH_B: ret=ssl3_get_client_key_exchange(s); if (ret <= 0) goto end; + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 0, NULL); s->state=SSL3_ST_SR_CERT_VRFY_A; s->init_num=0; @@ -463,6 +474,7 @@ int dtls1_accept(SSL *s) /* we should decide if we expected this one */ ret=ssl3_get_cert_verify(s); if (ret <= 0) goto end; + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 0, NULL); s->state=SSL3_ST_SR_FINISHED_A; s->init_num=0; @@ -473,6 +485,7 @@ int dtls1_accept(SSL *s) ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A, SSL3_ST_SR_FINISHED_B); if (ret <= 0) goto end; + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 0, NULL); if (s->hit) s->state=SSL_ST_OK; else @@ -555,6 +568,7 @@ int dtls1_accept(SSL *s) s->d1->handshake_read_seq = 0; /* next message is server hello */ s->d1->handshake_write_seq = 0; + s->d1->next_handshake_write_seq = 0; goto end; /* break; */ diff --git a/ssl/dtls1.h b/ssl/dtls1.h index 6548a98f03..cb8bd7cdfe 100644 --- a/ssl/dtls1.h +++ b/ssl/dtls1.h @@ -102,6 +102,19 @@ typedef struct dtls1_bitmap_st encoding */ } DTLS1_BITMAP; +struct dtls1_retransmit_state + { + EVP_CIPHER_CTX *enc_write_ctx; /* cryptographic state */ + EVP_MD_CTX *write_hash; /* used for mac generation */ +#ifndef OPENSSL_NO_COMP + COMP_CTX *compress; /* compression */ +#else + char *compress; +#endif + SSL_SESSION *session; + unsigned short epoch; + }; + struct hm_header_st { unsigned char type; @@ -110,6 +123,7 @@ struct hm_header_st unsigned long frag_off; unsigned long frag_len; unsigned int is_ccs; + struct dtls1_retransmit_state saved_retransmit_state; }; struct ccs_header_st @@ -169,6 +183,9 @@ typedef struct dtls1_state_st unsigned short handshake_read_seq; + /* save last sequence number for retransmissions */ + unsigned char last_write_sequence[8]; + /* Received handshake records (processed and unprocessed) */ record_pqueue unprocessed_rcds; record_pqueue processed_rcds; @@ -179,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; diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 9b6aadd950..dd9fa8780c 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -935,6 +935,8 @@ int dtls1_read_failed(SSL *s, int code); int dtls1_buffer_message(SSL *s, int ccs); int dtls1_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off, int *found); +int dtls1_get_queue_priority(unsigned short seq, int is_ccs); +int dtls1_retransmit_buffered_messages(SSL *s); void dtls1_clear_record_buffer(SSL *s); void dtls1_get_message_header(unsigned char *data, struct hm_header_st *msg_hdr); void dtls1_get_ccs_header(unsigned char *data, struct ccs_header_st *ccs_hdr); -- cgit v1.2.3