summaryrefslogtreecommitdiffstats
path: root/ssl
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2009-04-15 15:27:03 +0000
committerDr. Stephen Henson <steve@openssl.org>2009-04-15 15:27:03 +0000
commite5fa864f62c096536d700d977a5eb924ad293304 (patch)
treef97991450654a74c8f8ace4ea11e88a1c055818f /ssl
parent22c98d4aad76f39ab19e5b63e1448c7d28ca7617 (diff)
Updates from 1.0.0-stable.
Diffstat (limited to 'ssl')
-rw-r--r--ssl/d1_both.c107
-rw-r--r--ssl/d1_clnt.c10
-rw-r--r--ssl/d1_lib.c13
-rw-r--r--ssl/d1_pkt.c72
-rw-r--r--ssl/d1_srvr.c14
-rw-r--r--ssl/dtls1.h24
-rw-r--r--ssl/ssl_locl.h2
7 files changed, 204 insertions, 38 deletions
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);