diff options
author | David Benjamin <davidben@google.com> | 2016-06-18 02:12:54 +0300 |
---|---|---|
committer | Adam Langley <agl@google.com> | 2016-06-27 23:10:12 +0300 |
commit | 29a83c5a0c9a71670ddfeef6a2a68b666338e9ff (patch) | |
tree | 26e0c461fcf05c44d8a1f43906bf651517c5b0bd /ssl/d1_both.c | |
parent | f182ee1bba5811b28aeb4e205afaa17ae938a9b7 (diff) |
Rewrite DTLS outgoing message buffering.
Now that retransitting is a lot less stateful, a lot of surrounding code can
lose statefulness too. Rather than this overcomplicated pqueue structure,
hardcode that a handshake flight is capped at 7 messages (actually, DTLS can
only get up to 6 because we don't support NPN or Channel ID in DTLS) and used a
fixed size array.
This also resolves several TODOs.
Change-Id: I2b54c3441577a75ad5ca411d872b807d69aa08eb
Reviewed-on: https://boringssl-review.googlesource.com/8435
Reviewed-by: Adam Langley <agl@google.com>
Diffstat (limited to 'ssl/d1_both.c')
-rw-r--r-- | ssl/d1_both.c | 167 |
1 files changed, 52 insertions, 115 deletions
diff --git a/ssl/d1_both.c b/ssl/d1_both.c index d98b5df7..6b2a0193 100644 --- a/ssl/d1_both.c +++ b/ssl/d1_both.c @@ -139,11 +139,7 @@ static const unsigned int kMinMTU = 256 - 28; * the underlying BIO supplies one. */ static const unsigned int kDefaultMTU = 1500 - 28; -/* kMaxHandshakeBuffer is the maximum number of handshake messages ahead of the - * current one to buffer. */ -static const unsigned int kHandshakeBufferSize = 10; - -static hm_fragment *dtls1_hm_fragment_new(size_t frag_len, int reassembly) { +static hm_fragment *dtls1_hm_fragment_new(size_t frag_len) { hm_fragment *frag = OPENSSL_malloc(sizeof(hm_fragment)); if (frag == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); @@ -160,20 +156,18 @@ static hm_fragment *dtls1_hm_fragment_new(size_t frag_len, int reassembly) { goto err; } - if (reassembly) { - /* Initialize reassembly bitmask. */ - if (frag_len + 7 < frag_len) { - OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); - goto err; - } - size_t bitmask_len = (frag_len + 7) / 8; - frag->reassembly = OPENSSL_malloc(bitmask_len); - if (frag->reassembly == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - memset(frag->reassembly, 0, bitmask_len); + /* Initialize reassembly bitmask. */ + if (frag_len + 7 < frag_len) { + OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); + goto err; } + size_t bitmask_len = (frag_len + 7) / 8; + frag->reassembly = OPENSSL_malloc(bitmask_len); + if (frag->reassembly == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + memset(frag->reassembly, 0, bitmask_len); } return frag; @@ -440,8 +434,7 @@ static hm_fragment *dtls1_get_buffered_message( hm_fragment *frag; if (item == NULL) { /* This is the first fragment from this message. */ - frag = dtls1_hm_fragment_new(msg_hdr->msg_len, - 1 /* reassembly buffer needed */); + frag = dtls1_hm_fragment_new(msg_hdr->msg_len); if (frag == NULL) { return NULL; } @@ -532,7 +525,7 @@ start: if (msg_hdr.seq < ssl->d1->handshake_read_seq || msg_hdr.seq > - (unsigned)ssl->d1->handshake_read_seq + kHandshakeBufferSize) { + (unsigned)ssl->d1->handshake_read_seq + SSL_MAX_HANDSHAKE_FLIGHT) { /* Ignore fragments from the past, or ones too far in the future. */ continue; } @@ -661,39 +654,25 @@ err: return -1; } -static uint16_t dtls1_get_queue_priority(uint16_t seq, int is_ccs) { - assert(seq * 2 >= seq); - - /* 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 dtls1_retransmit_message(SSL *ssl, hm_fragment *frag) { +static int dtls1_retransmit_message(SSL *ssl, + const DTLS_OUTGOING_MESSAGE *msg) { /* DTLS renegotiation is unsupported, so only epochs 0 (NULL cipher) and 1 * (negotiated cipher) exist. */ assert(ssl->d1->w_epoch == 0 || ssl->d1->w_epoch == 1); - assert(frag->msg_header.epoch <= ssl->d1->w_epoch); + assert(msg->epoch <= ssl->d1->w_epoch); enum dtls1_use_epoch_t use_epoch = dtls1_use_current_epoch; - if (ssl->d1->w_epoch == 1 && frag->msg_header.epoch == 0) { + if (ssl->d1->w_epoch == 1 && msg->epoch == 0) { use_epoch = dtls1_use_previous_epoch; } /* TODO(davidben): This cannot handle non-blocking writes. */ int ret; - if (frag->msg_header.is_ccs) { + if (msg->is_ccs) { ret = dtls1_write_change_cipher_spec(ssl, use_epoch); } else { size_t offset = 0; - ret = dtls1_do_handshake_write( - ssl, &offset, frag->fragment, offset, - frag->msg_header.msg_len + DTLS1_HM_HEADER_LENGTH, use_epoch); + ret = dtls1_do_handshake_write(ssl, &offset, msg->data, offset, msg->len, + use_epoch); } return ret; @@ -709,11 +688,9 @@ int dtls1_retransmit_buffered_messages(SSL *ssl) { assert(ssl_is_wbio_buffered(ssl)); int ret = -1; - piterator iter = pqueue_iterator(ssl->d1->sent_messages); - pitem *item; - for (item = pqueue_next(&iter); item != NULL; item = pqueue_next(&iter)) { - hm_fragment *frag = (hm_fragment *)item->data; - if (dtls1_retransmit_message(ssl, frag) <= 0) { + size_t i; + for (i = 0; i < ssl->d1->outgoing_messages_len; i++) { + if (dtls1_retransmit_message(ssl, &ssl->d1->outgoing_messages[i]) <= 0) { goto err; } } @@ -732,66 +709,41 @@ err: } /* dtls1_buffer_change_cipher_spec adds a ChangeCipherSpec to the current - * handshake flight, ordered just before the handshake message numbered - * |seq|. */ -static int dtls1_buffer_change_cipher_spec(SSL *ssl, uint16_t seq) { - hm_fragment *frag = dtls1_hm_fragment_new(0 /* frag_len */, - 0 /* no reassembly */); - if (frag == NULL) { + * handshake flight. */ +static int dtls1_buffer_change_cipher_spec(SSL *ssl) { + if (ssl->d1->outgoing_messages_len >= SSL_MAX_HANDSHAKE_FLIGHT) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return 0; } - frag->msg_header.is_ccs = 1; - frag->msg_header.epoch = ssl->d1->w_epoch; - uint16_t priority = dtls1_get_queue_priority(seq, 1 /* is_ccs */); - uint8_t seq64be[8]; - memset(seq64be, 0, sizeof(seq64be)); - seq64be[6] = (uint8_t)(priority >> 8); - seq64be[7] = (uint8_t)priority; + DTLS_OUTGOING_MESSAGE *msg = + &ssl->d1->outgoing_messages[ssl->d1->outgoing_messages_len]; + msg->data = NULL; + msg->len = 0; + msg->epoch = ssl->d1->w_epoch; + msg->is_ccs = 1; - pitem *item = pitem_new(seq64be, frag); - if (item == NULL) { - dtls1_hm_fragment_free(frag); - return 0; - } - - pqueue_insert(ssl->d1->sent_messages, item); + ssl->d1->outgoing_messages_len++; return 1; } int dtls1_buffer_message(SSL *ssl) { - hm_fragment *frag = dtls1_hm_fragment_new(ssl->init_num, 0); - if (!frag) { + if (ssl->d1->outgoing_messages_len >= SSL_MAX_HANDSHAKE_FLIGHT) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return 0; } - memcpy(frag->fragment, ssl->init_buf->data, ssl->init_num); - - assert(ssl->d1->w_msg_hdr.msg_len + DTLS1_HM_HEADER_LENGTH == - (unsigned int)ssl->init_num); - - frag->msg_header.msg_len = ssl->d1->w_msg_hdr.msg_len; - frag->msg_header.seq = ssl->d1->w_msg_hdr.seq; - frag->msg_header.type = ssl->d1->w_msg_hdr.type; - frag->msg_header.frag_off = 0; - frag->msg_header.frag_len = ssl->d1->w_msg_hdr.msg_len; - frag->msg_header.is_ccs = 0; - frag->msg_header.epoch = ssl->d1->w_epoch; - - uint16_t priority = dtls1_get_queue_priority(frag->msg_header.seq, - 0 /* handshake */); - uint8_t seq64be[8]; - memset(seq64be, 0, sizeof(seq64be)); - seq64be[6] = (uint8_t)(priority >> 8); - seq64be[7] = (uint8_t)priority; - - pitem *item = pitem_new(seq64be, frag); - if (item == NULL) { - dtls1_hm_fragment_free(frag); + DTLS_OUTGOING_MESSAGE *msg = + &ssl->d1->outgoing_messages[ssl->d1->outgoing_messages_len]; + msg->data = BUF_memdup(ssl->init_buf->data, ssl->init_num); + if (msg->data == NULL) { return 0; } + msg->len = ssl->init_num; + msg->epoch = ssl->d1->w_epoch; + msg->is_ccs = 0; - pqueue_insert(ssl->d1->sent_messages, item); + ssl->d1->outgoing_messages_len++; return 1; } @@ -799,35 +751,20 @@ int dtls1_send_change_cipher_spec(SSL *ssl, int a, int b) { if (ssl->state == a) { /* Buffer the message to handle retransmits. */ ssl->d1->handshake_write_seq = ssl->d1->next_handshake_write_seq; - dtls1_buffer_change_cipher_spec(ssl, ssl->d1->handshake_write_seq); + dtls1_buffer_change_cipher_spec(ssl); ssl->state = b; } return dtls1_write_change_cipher_spec(ssl, dtls1_use_current_epoch); } -/* call this function when the buffered messages are no longer needed */ -void dtls1_clear_record_buffer(SSL *ssl) { - pitem *item; - - for (item = pqueue_pop(ssl->d1->sent_messages); item != NULL; - item = pqueue_pop(ssl->d1->sent_messages)) { - dtls1_hm_fragment_free((hm_fragment *)item->data); - pitem_free(item); +void dtls_clear_outgoing_messages(SSL *ssl) { + size_t i; + for (i = 0; i < ssl->d1->outgoing_messages_len; i++) { + OPENSSL_free(ssl->d1->outgoing_messages[i].data); + ssl->d1->outgoing_messages[i].data = NULL; } -} - -/* don't actually do the writing, wait till the MTU has been retrieved */ -void dtls1_set_message_header(SSL *ssl, uint8_t mt, unsigned long len, - unsigned short seq_num, unsigned long frag_off, - unsigned long frag_len) { - struct hm_header_st *msg_hdr = &ssl->d1->w_msg_hdr; - - msg_hdr->type = mt; - msg_hdr->msg_len = len; - msg_hdr->seq = seq_num; - msg_hdr->frag_off = frag_off; - msg_hdr->frag_len = frag_len; + ssl->d1->outgoing_messages_len = 0; } unsigned int dtls1_min_mtu(void) { |