diff options
author | Frederik Wedel-Heinen <frederik.wedel-heinen@dencrypt.dk> | 2024-06-11 10:51:38 +0200 |
---|---|---|
committer | Matt Caswell <matt@openssl.org> | 2024-07-10 16:15:51 +0100 |
commit | d85ea406479f972ee5b9e832d360543604435200 (patch) | |
tree | ba580ca66fc5ab5dc04569d829e5c2b976718e34 | |
parent | d4af398d56098fb7e5a5d7a72ee0c4642dfbbe13 (diff) | |
download | openssl-feature/dtls-1.3.zip openssl-feature/dtls-1.3.tar.gz openssl-feature/dtls-1.3.tar.bz2 |
Refactor handshake msg header parsing etc.feature/dtls-1.3
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/24607)
-rw-r--r-- | include/internal/common.h | 4 | ||||
-rw-r--r-- | ssl/d1_lib.c | 31 | ||||
-rw-r--r-- | ssl/record/rec_layer_d1.c | 8 | ||||
-rw-r--r-- | ssl/ssl_local.h | 42 | ||||
-rw-r--r-- | ssl/statem/statem_dtls.c | 423 | ||||
-rw-r--r-- | util/indent.pro | 2 |
6 files changed, 232 insertions, 278 deletions
diff --git a/include/internal/common.h b/include/internal/common.h index 2d26194..e6e9627 100644 --- a/include/internal/common.h +++ b/include/internal/common.h @@ -180,10 +180,6 @@ __owur static ossl_inline int ossl_assert_int(int expr, const char *exprstr, (((unsigned long)((c)[1]))<< 8)| \ (((unsigned long)((c)[2])) )),(c)+=3) -# define l2n3(l,c) (((c)[0]=(unsigned char)(((l)>>16)&0xff), \ - (c)[1]=(unsigned char)(((l)>> 8)&0xff), \ - (c)[2]=(unsigned char)(((l) )&0xff)),(c)+=3) - #define l3n2(c,l) (l =((uint64_t)(*((c)++)))<<16, \ l|=((uint64_t)(*((c)++)))<< 8, \ l|=((uint64_t)(*((c)++)))) diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c index ebc6420..a5b7155 100644 --- a/ssl/d1_lib.c +++ b/ssl/d1_lib.c @@ -94,7 +94,7 @@ int dtls1_new(SSL *ssl) return 0; } - d1->buffered_messages = pqueue_new(); + d1->rcvd_messages = pqueue_new(); d1->sent_messages = pqueue_new(); if (s->server) { @@ -105,8 +105,8 @@ int dtls1_new(SSL *ssl) d1->mtu = 0; d1->hello_verify_request = SSL_HVR_NONE; - if (d1->buffered_messages == NULL || d1->sent_messages == NULL) { - pqueue_free(d1->buffered_messages); + if (d1->rcvd_messages == NULL || d1->sent_messages == NULL) { + pqueue_free(d1->rcvd_messages); pqueue_free(d1->sent_messages); OPENSSL_free(d1); ssl3_free(ssl); @@ -132,7 +132,7 @@ void dtls1_clear_received_buffer(SSL_CONNECTION *s) pitem *item = NULL; hm_fragment *frag = NULL; - while ((item = pqueue_pop(s->d1->buffered_messages)) != NULL) { + while ((item = pqueue_pop(s->d1->rcvd_messages)) != NULL) { frag = (hm_fragment *)item->data; dtls1_hm_fragment_free(frag); pitem_free(item); @@ -142,22 +142,21 @@ void dtls1_clear_received_buffer(SSL_CONNECTION *s) void dtls1_clear_sent_buffer(SSL_CONNECTION *s) { pitem *item = NULL; - hm_fragment *frag = NULL; while ((item = pqueue_pop(s->d1->sent_messages)) != NULL) { - frag = (hm_fragment *)item->data; + dtls_sent_msg *sent_msg = (dtls_sent_msg *)item->data; - if (frag->msg_header.is_ccs - && frag->msg_header.saved_retransmit_state.wrlmethod != NULL - && s->rlayer.wrl != frag->msg_header.saved_retransmit_state.wrl) { + if (sent_msg->record_type == SSL3_RT_CHANGE_CIPHER_SPEC + && sent_msg->saved_retransmit_state.wrlmethod != NULL + && s->rlayer.wrl != sent_msg->saved_retransmit_state.wrl) { /* * If we're freeing the CCS then we're done with the old wrl and it * can bee freed */ - frag->msg_header.saved_retransmit_state.wrlmethod->free(frag->msg_header.saved_retransmit_state.wrl); + sent_msg->saved_retransmit_state.wrlmethod->free(sent_msg->saved_retransmit_state.wrl); } - dtls1_hm_fragment_free(frag); + dtls1_sent_msg_free(sent_msg); pitem_free(item); } } @@ -172,7 +171,7 @@ void dtls1_free(SSL *ssl) if (s->d1 != NULL) { dtls1_clear_queues(s); - pqueue_free(s->d1->buffered_messages); + pqueue_free(s->d1->rcvd_messages); pqueue_free(s->d1->sent_messages); } @@ -186,7 +185,7 @@ void dtls1_free(SSL *ssl) int dtls1_clear(SSL *ssl) { - pqueue *buffered_messages; + pqueue *rcvd_messages; pqueue *sent_messages; size_t mtu; size_t link_mtu; @@ -201,7 +200,7 @@ int dtls1_clear(SSL *ssl) if (s->d1) { DTLS_timer_cb timer_cb = s->d1->timer_cb; - buffered_messages = s->d1->buffered_messages; + rcvd_messages = s->d1->rcvd_messages; sent_messages = s->d1->sent_messages; mtu = s->d1->mtu; link_mtu = s->d1->link_mtu; @@ -222,7 +221,7 @@ int dtls1_clear(SSL *ssl) s->d1->link_mtu = link_mtu; } - s->d1->buffered_messages = buffered_messages; + s->d1->rcvd_messages = rcvd_messages; s->d1->sent_messages = sent_messages; } @@ -423,7 +422,7 @@ int dtls1_handle_timeout(SSL_CONNECTION *s) dtls1_start_timer(s); /* Calls SSLfatal() if required */ - return dtls1_retransmit_buffered_messages(s); + return dtls1_retransmit_sent_messages(s); } #define LISTEN_SUCCESS 2 diff --git a/ssl/record/rec_layer_d1.c b/ssl/record/rec_layer_d1.c index 480d0d9..932db8d 100644 --- a/ssl/record/rec_layer_d1.c +++ b/ssl/record/rec_layer_d1.c @@ -490,7 +490,7 @@ int dtls1_read_bytes(SSL *s, uint8_t type, uint8_t *recvd_type, * Unexpected handshake message (Client Hello, or protocol violation) */ if (rr->type == SSL3_RT_HANDSHAKE && !ossl_statem_get_in_handshake(sc)) { - struct hm_header_st msg_hdr; + unsigned char msg_type; /* * This may just be a stale retransmit. Also sanity check that we have @@ -503,19 +503,19 @@ int dtls1_read_bytes(SSL *s, uint8_t type, uint8_t *recvd_type, goto start; } - dtls1_get_message_header(rr->data, &msg_hdr); + msg_type = *rr->data; /* * 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) { + if (msg_type == SSL3_MT_FINISHED) { if (dtls1_check_timeout_num(sc) < 0) { /* SSLfatal) already called */ return -1; } - if (dtls1_retransmit_buffered_messages(sc) <= 0) { + if (dtls1_retransmit_sent_messages(sc) <= 0) { /* Fail if we encountered a fatal error */ if (ossl_statem_in_error(sc)) return -1; diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index 433b761..c197044 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -1924,12 +1924,6 @@ typedef struct sigalg_lookup_st { /* Max MTU overhead we know about so far is 40 for IPv6 + 8 for UDP */ # define DTLS1_MAX_MTU_OVERHEAD 48 -/* - * Flag used in message reuse to indicate the buffer contains the record - * header as well as the handshake message header. - */ -# define DTLS1_SKIP_RECORD_HEADER 2 - struct dtls1_retransmit_state { const OSSL_RECORD_METHOD *wrlmethod; OSSL_RECORD_LAYER *wrl; @@ -1941,8 +1935,6 @@ struct hm_header_st { unsigned short seq; size_t frag_off; size_t frag_len; - unsigned int is_ccs; - struct dtls1_retransmit_state saved_retransmit_state; }; typedef struct hm_fragment_st { @@ -1974,6 +1966,19 @@ pitem *pqueue_iterator(pqueue *pq); pitem *pqueue_next(piterator *iter); size_t pqueue_size(pqueue *pq); +typedef struct dtls_msg_info_st { + unsigned char msg_type; + size_t msg_body_len; + unsigned short msg_seq; +} dtls_msg_info; + +typedef struct dtls_sent_msg_st { + dtls_msg_info msg_info; + int record_type; + unsigned char *msg_buf; + struct dtls1_retransmit_state saved_retransmit_state; +} dtls_sent_msg; + typedef struct dtls1_state_st { unsigned char cookie[DTLS1_COOKIE_LENGTH]; size_t cookie_len; @@ -1982,16 +1987,16 @@ typedef struct dtls1_state_st { unsigned short handshake_write_seq; unsigned short next_handshake_write_seq; unsigned short handshake_read_seq; - /* Buffered handshake messages */ - pqueue *buffered_messages; + /* Buffered received handshake messages */ + pqueue *rcvd_messages; /* Buffered (sent) handshake records */ pqueue *sent_messages; /* Flag to indicate current HelloVerifyRequest status */ enum {SSL_HVR_NONE = 0, SSL_HVR_RECEIVED} hello_verify_request; size_t link_mtu; /* max on-the-wire DTLS packet size */ size_t mtu; /* max DTLS packet size */ - struct hm_header_st w_msg_hdr; - struct hm_header_st r_msg_hdr; + dtls_msg_info w_msg; + unsigned short r_msg_seq; /* Number of alerts received so far */ unsigned int timeout_num_alerts; /* @@ -2703,25 +2708,19 @@ __owur int ssl_get_min_max_version(const SSL_CONNECTION *s, int *min_version, int *max_version, int *real_max); __owur OSSL_TIME tls1_default_timeout(void); -__owur int dtls1_do_write(SSL_CONNECTION *s, uint8_t type); -void dtls1_set_message_header(SSL_CONNECTION *s, - unsigned char mt, - size_t len, - size_t frag_off, size_t frag_len); +__owur int dtls1_do_write(SSL_CONNECTION *s, uint8_t recordtype); int dtls1_write_app_data_bytes(SSL *s, uint8_t type, const void *buf_, size_t len, size_t *written); __owur int dtls1_read_failed(SSL_CONNECTION *s, int code); -__owur int dtls1_buffer_message(SSL_CONNECTION *s, int ccs); +__owur int dtls1_buffer_sent_message(SSL_CONNECTION *s, int record_type); __owur int dtls1_retransmit_message(SSL_CONNECTION *s, unsigned short seq, int *found); __owur int dtls1_get_queue_priority(unsigned short seq, int is_ccs); -int dtls1_retransmit_buffered_messages(SSL_CONNECTION *s); +int dtls1_retransmit_sent_messages(SSL_CONNECTION *s); void dtls1_clear_received_buffer(SSL_CONNECTION *s); void dtls1_clear_sent_buffer(SSL_CONNECTION *s); -void dtls1_get_message_header(const unsigned char *data, - struct hm_header_st *msg_hdr); __owur OSSL_TIME dtls1_default_timeout(void); __owur int dtls1_get_timeout(const SSL_CONNECTION *s, OSSL_TIME *timeleft); __owur int dtls1_check_timeout_num(SSL_CONNECTION *s); @@ -2733,6 +2732,7 @@ __owur int dtls_raw_hello_verify_request(WPACKET *pkt, unsigned char *cookie, size_t cookie_len); __owur size_t dtls1_min_mtu(SSL_CONNECTION *s); void dtls1_hm_fragment_free(hm_fragment *frag); +void dtls1_sent_msg_free(dtls_sent_msg *msg); __owur int dtls1_query_mtu(SSL_CONNECTION *s); __owur int tls1_new(SSL *s); diff --git a/ssl/statem/statem_dtls.c b/ssl/statem/statem_dtls.c index 61051c3..b51a15b 100644 --- a/ssl/statem/statem_dtls.c +++ b/ssl/statem/statem_dtls.c @@ -44,55 +44,59 @@ static const unsigned char bitmask_start_values[] = static const unsigned char bitmask_end_values[] = { 0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f }; -static void dtls1_set_message_header_int(SSL_CONNECTION *s, unsigned char mt, - size_t len, - unsigned short seq_num, - size_t frag_off, - size_t frag_len); static int dtls_get_reassembled_message(SSL_CONNECTION *s, int *errtype, size_t *len); +static dtls_sent_msg *dtls1_sent_msg_new(size_t msg_len) +{ + dtls_sent_msg *msg = OPENSSL_malloc(sizeof(*msg) + msg_len); + + if (msg == NULL) + return NULL; + + memset(msg, 0, sizeof(*msg)); + + /* zero length msg gets msg->msg_buf == NULL */ + if (msg_len > 0) + msg->msg_buf = (unsigned char *)(msg + 1); + + return msg; +} + +void dtls1_sent_msg_free(dtls_sent_msg *msg) +{ + OPENSSL_free(msg); +} + static hm_fragment *dtls1_hm_fragment_new(size_t frag_len, int reassembly) { - hm_fragment *frag = NULL; - unsigned char *buf = NULL; - unsigned char *bitmask = NULL; + const size_t bitmask_len = (reassembly ? RSMBLY_BITMASK_SIZE(frag_len) : 0); + hm_fragment *frag = OPENSSL_malloc(sizeof(*frag) + frag_len + bitmask_len); - if ((frag = OPENSSL_zalloc(sizeof(*frag))) == NULL) + if (frag == NULL) return NULL; - if (frag_len) { - if ((buf = OPENSSL_malloc(frag_len)) == NULL) { - OPENSSL_free(frag); - return NULL; - } - } + memset(frag, 0, sizeof(*frag)); /* zero length fragment gets zero frag->fragment */ - frag->fragment = buf; + if (frag_len > 0) + frag->fragment = (unsigned char *)(frag + 1); /* Initialize reassembly bitmask if necessary */ - if (reassembly) { - bitmask = OPENSSL_zalloc(RSMBLY_BITMASK_SIZE(frag_len)); - if (bitmask == NULL) { - OPENSSL_free(buf); - OPENSSL_free(frag); - return NULL; - } - } + if (bitmask_len > 0) { + if (frag->fragment == NULL) + frag->reassembly = (unsigned char *)(frag + 1); + else + frag->reassembly = frag->fragment + frag_len; - frag->reassembly = bitmask; + memset(frag->reassembly, 0, bitmask_len); + } return frag; } void dtls1_hm_fragment_free(hm_fragment *frag) { - if (!frag) - return; - - OPENSSL_free(frag->fragment); - OPENSSL_free(frag->reassembly); OPENSSL_free(frag); } @@ -134,7 +138,7 @@ static int dtls1_write_hm_header(unsigned char *msgheaderstart, * |-- header3 --||-- fragment3 --| * ......... */ -int dtls1_do_write(SSL_CONNECTION *s, uint8_t type) +int dtls1_do_write(SSL_CONNECTION *s, uint8_t recordtype) { int ret; size_t written; @@ -143,13 +147,13 @@ int dtls1_do_write(SSL_CONNECTION *s, uint8_t type) size_t len, overhead, used_len, msg_len = 0; SSL *ssl = SSL_CONNECTION_GET_SSL(s); unsigned char *data = (unsigned char *)s->init_buf->data; - unsigned short msg_seq = s->d1->w_msg_hdr.seq; + unsigned short msg_seq = s->d1->w_msg.msg_seq; unsigned char msg_type = 0; - if (type == SSL3_RT_HANDSHAKE) { + if (recordtype == SSL3_RT_HANDSHAKE) { msg_type = *data++; l3n2(data, msg_len); - } else if (ossl_assert(type == SSL3_RT_CHANGE_CIPHER_SPEC)) { + } else if (ossl_assert(recordtype == SSL3_RT_CHANGE_CIPHER_SPEC)) { msg_type = SSL3_MT_CCS; msg_len = 0; /* SSL3_RT_CHANGE_CIPHER_SPEC */ } else { @@ -164,7 +168,7 @@ int dtls1_do_write(SSL_CONNECTION *s, uint8_t type) /* should have something reasonable now */ return -1; - if (s->init_off == 0 && type == SSL3_RT_HANDSHAKE) { + if (s->init_off == 0 && recordtype == SSL3_RT_HANDSHAKE) { if (!ossl_assert(s->init_num == msg_len + DTLS1_HM_HEADER_LENGTH)) return -1; } @@ -177,7 +181,7 @@ int dtls1_do_write(SSL_CONNECTION *s, uint8_t type) while (s->init_num > 0) { unsigned char *msgstart; - if (type == SSL3_RT_HANDSHAKE && s->init_off > 0) { + if (recordtype == SSL3_RT_HANDSHAKE && s->init_off > 0) { /* * We must be writing a fragment other than the first one * and this is the first attempt at writing out this fragment @@ -234,7 +238,7 @@ int dtls1_do_write(SSL_CONNECTION *s, uint8_t type) msgstart = (unsigned char *)&s->init_buf->data[s->init_off]; - if (type == SSL3_RT_HANDSHAKE) { + if (recordtype == SSL3_RT_HANDSHAKE) { const size_t fragoff = s->init_off; const size_t fraglen = len - DTLS1_HM_HEADER_LENGTH; @@ -248,7 +252,7 @@ int dtls1_do_write(SSL_CONNECTION *s, uint8_t type) return -1; } - ret = dtls1_write_bytes(s, type, msgstart, len, &written); + ret = dtls1_write_bytes(s, recordtype, msgstart, len, &written); if (ret <= 0) { /* @@ -284,7 +288,7 @@ int dtls1_do_write(SSL_CONNECTION *s, uint8_t type) assert(s->s3.tmp.new_compression != NULL || BIO_wpending(s->wbio) <= (int)s->d1->mtu); - if (type == SSL3_RT_HANDSHAKE && !s->d1->retransmitting) { + if (recordtype == SSL3_RT_HANDSHAKE && !s->d1->retransmitting) { /* * should not be done for 'Hello Request's, but in that case * we'll ignore the result anyway @@ -322,7 +326,7 @@ int dtls1_do_write(SSL_CONNECTION *s, uint8_t type) if (written == s->init_num) { if (s->msg_callback) - s->msg_callback(1, s->version, type, s->init_buf->data, + s->msg_callback(1, s->version, recordtype, s->init_buf->data, s->init_off + s->init_num, ssl, s->msg_callback_arg); @@ -341,14 +345,11 @@ int dtls1_do_write(SSL_CONNECTION *s, uint8_t type) int dtls_get_message(SSL_CONNECTION *s, int *mt) { - struct hm_header_st *msg_hdr; - unsigned char *p; - size_t msg_len; + unsigned char *rec_data; size_t tmplen; int errtype; - msg_hdr = &s->d1->r_msg_hdr; - memset(msg_hdr, 0, sizeof(*msg_hdr)); + s->d1->r_msg_seq = 0; again: if (!dtls_get_reassembled_message(s, &errtype, &tmplen)) { @@ -362,12 +363,12 @@ int dtls_get_message(SSL_CONNECTION *s, int *mt) *mt = s->s3.tmp.message_type; - p = (unsigned char *)s->init_buf->data; + rec_data = (unsigned char *)s->init_buf->data; if (*mt == SSL3_MT_CHANGE_CIPHER_SPEC) { if (s->msg_callback) { s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC, - p, 1, SSL_CONNECTION_GET_SSL(s), + rec_data, 1, SSL_CONNECTION_GET_SSL(s), s->msg_callback_arg); } /* @@ -376,16 +377,11 @@ int dtls_get_message(SSL_CONNECTION *s, int *mt) return 1; } - msg_len = msg_hdr->msg_len; - /* reconstruct message header */ - *(p++) = msg_hdr->type; - l2n3(msg_len, p); - s2n(msg_hdr->seq, p); - l2n3(0, p); - l2n3(msg_len, p); + dtls1_write_hm_header(rec_data, s->s3.tmp.message_type, s->s3.tmp.message_size, + s->d1->r_msg_seq, 0, s->s3.tmp.message_size); - memset(msg_hdr, 0, sizeof(*msg_hdr)); + s->d1->r_msg_seq = 0; s->d1->handshake_read_seq++; @@ -449,7 +445,7 @@ static size_t dtls1_max_handshake_message_len(const SSL_CONNECTION *s) } static int dtls1_preprocess_fragment(SSL_CONNECTION *s, - struct hm_header_st *msg_hdr) + const struct hm_header_st * const msg_hdr) { size_t frag_off, frag_len, msg_len; @@ -464,30 +460,19 @@ static int dtls1_preprocess_fragment(SSL_CONNECTION *s, return 0; } - if (s->d1->r_msg_hdr.frag_off == 0) { /* first fragment */ - /* - * msg_len is limited to 2^24, but is effectively checked against - * dtls_max_handshake_message_len(s) above - */ - if (!BUF_MEM_grow_clean(s->init_buf, msg_len + DTLS1_HM_HEADER_LENGTH)) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_BUF_LIB); - return 0; - } - - s->s3.tmp.message_size = msg_len; - s->d1->r_msg_hdr.msg_len = msg_len; - s->s3.tmp.message_type = msg_hdr->type; - s->d1->r_msg_hdr.type = msg_hdr->type; - s->d1->r_msg_hdr.seq = msg_hdr->seq; - } else if (msg_len != s->d1->r_msg_hdr.msg_len) { - /* - * They must be playing with us! BTW, failure to enforce upper limit - * would open possibility for buffer overrun. - */ - SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_EXCESSIVE_MESSAGE_SIZE); + /* + * msg_len is limited to 2^24, but is effectively checked against + * dtls_max_handshake_message_len(s) above + */ + if (!BUF_MEM_grow_clean(s->init_buf, msg_len + DTLS1_HM_HEADER_LENGTH)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_BUF_LIB); return 0; } + s->s3.tmp.message_size = msg_len; + s->s3.tmp.message_type = msg_hdr->type; + s->d1->r_msg_seq = msg_hdr->seq; + return 1; } @@ -509,7 +494,7 @@ static int dtls1_retrieve_buffered_fragment(SSL_CONNECTION *s, size_t *len) int ret; int chretran = 0; - iter = pqueue_iterator(s->d1->buffered_messages); + iter = pqueue_iterator(s->d1->rcvd_messages); do { item = pqueue_next(&iter); if (item == NULL) @@ -530,7 +515,7 @@ static int dtls1_retrieve_buffered_fragment(SSL_CONNECTION *s, size_t *len) * It is safe to pop this message from the queue even though * we have an active iterator */ - pqueue_pop(s->d1->buffered_messages); + pqueue_pop(s->d1->rcvd_messages); dtls1_hm_fragment_free(frag); pitem_free(item); item = NULL; @@ -550,7 +535,7 @@ static int dtls1_retrieve_buffered_fragment(SSL_CONNECTION *s, size_t *len) * We have fragments for both a ClientHello without * cookie and one with. Ditch the one without. */ - pqueue_pop(s->d1->buffered_messages); + pqueue_pop(s->d1->rcvd_messages); dtls1_hm_fragment_free(frag); pitem_free(item); item = next; @@ -571,7 +556,7 @@ static int dtls1_retrieve_buffered_fragment(SSL_CONNECTION *s, size_t *len) if (s->d1->handshake_read_seq == frag->msg_header.seq || chretran) { size_t frag_len = frag->msg_header.frag_len; - pqueue_pop(s->d1->buffered_messages); + pqueue_pop(s->d1->rcvd_messages); /* Calls SSLfatal() as required */ ret = dtls1_preprocess_fragment(s, &frag->msg_header); @@ -632,7 +617,7 @@ static int dtls1_reassemble_fragment(SSL_CONNECTION *s, memset(seq64be, 0, sizeof(seq64be)); seq64be[6] = (unsigned char)(msg_hdr->seq >> 8); seq64be[7] = (unsigned char)msg_hdr->seq; - item = pqueue_find(s->d1->buffered_messages, seq64be); + item = pqueue_find(s->d1->rcvd_messages, seq64be); if (item == NULL) { frag = dtls1_hm_fragment_new(msg_hdr->msg_len, 1); @@ -676,8 +661,6 @@ static int dtls1_reassemble_fragment(SSL_CONNECTION *s, frag->fragment + msg_hdr->frag_off, frag_len, 0, &readbytes); if (i <= 0 || readbytes != frag_len) - i = -1; - if (i <= 0) goto err; RSMBLY_BITMASK_MARK(frag->reassembly, (long)msg_hdr->frag_off, @@ -688,19 +671,15 @@ static int dtls1_reassemble_fragment(SSL_CONNECTION *s, RSMBLY_BITMASK_IS_COMPLETE(frag->reassembly, (long)msg_hdr->msg_len, is_complete); - if (is_complete) { - OPENSSL_free(frag->reassembly); + if (is_complete) frag->reassembly = NULL; - } if (item == NULL) { item = pitem_new(seq64be, frag); - if (item == NULL) { - i = -1; + if (item == NULL) goto err; - } - item = pqueue_insert(s->d1->buffered_messages, item); + item = pqueue_insert(s->d1->rcvd_messages, item); /* * pqueue_insert fails iff a duplicate item is inserted. However, * |item| cannot be a duplicate. If it were, |pqueue_find|, above, @@ -737,7 +716,7 @@ static int dtls1_process_out_of_seq_message(SSL_CONNECTION *s, memset(seq64be, 0, sizeof(seq64be)); seq64be[6] = (unsigned char)(msg_hdr->seq >> 8); seq64be[7] = (unsigned char)msg_hdr->seq; - item = pqueue_find(s->d1->buffered_messages, seq64be); + item = pqueue_find(s->d1->rcvd_messages, seq64be); /* * If we already have an entry and this one is a fragment, don't discard @@ -787,9 +766,7 @@ static int dtls1_process_out_of_seq_message(SSL_CONNECTION *s, i = ssl->method->ssl_read_bytes(ssl, SSL3_RT_HANDSHAKE, NULL, frag->fragment, frag_len, 0, &readbytes); - if (i<=0 || readbytes != frag_len) - i = -1; - if (i <= 0) + if (i <= 0 || readbytes != frag_len) goto err; } @@ -797,7 +774,7 @@ static int dtls1_process_out_of_seq_message(SSL_CONNECTION *s, if (item == NULL) goto err; - item = pqueue_insert(s->d1->buffered_messages, item); + item = pqueue_insert(s->d1->rcvd_messages, item); /* * pqueue_insert fails iff a duplicate item is inserted. However, * |item| cannot be a duplicate. If it were, |pqueue_find|, above, @@ -818,10 +795,36 @@ static int dtls1_process_out_of_seq_message(SSL_CONNECTION *s, return 0; } +static int dtls1_read_hm_header(unsigned char *msgheaderstart, + struct hm_header_st *msg_hdr) +{ + unsigned long msg_len, frag_off, frag_len; + unsigned int msg_seq, msg_type; + PACKET msgheader; + + if (!PACKET_buf_init(&msgheader, msgheaderstart, DTLS1_HM_HEADER_LENGTH) + || !PACKET_get_1(&msgheader, &msg_type) + || !PACKET_get_net_3(&msgheader, &msg_len) + || !PACKET_get_net_2(&msgheader, &msg_seq) + || !PACKET_get_net_3(&msgheader, &frag_off) + || !PACKET_get_net_3(&msgheader, &frag_len) + || PACKET_remaining(&msgheader) != 0) { + return 0; + } + + /* We just checked that values did not exceed max size so cast must be alright */ + msg_hdr->type = (unsigned char)msg_type; + msg_hdr->msg_len = (size_t)msg_len; + msg_hdr->seq = (unsigned short)msg_seq; + msg_hdr->frag_off = (size_t)frag_off; + msg_hdr->frag_len = (size_t)frag_len; + + return 1; +} + static int dtls_get_reassembled_message(SSL_CONNECTION *s, int *errtype, size_t *len) { - size_t mlen, frag_off, frag_len; int i, ret; uint8_t recvd_type; struct hm_header_st msg_hdr; @@ -836,14 +839,14 @@ static int dtls_get_reassembled_message(SSL_CONNECTION *s, int *errtype, redo: /* see if we have the required fragment already */ - ret = dtls1_retrieve_buffered_fragment(s, &frag_len); + ret = dtls1_retrieve_buffered_fragment(s, &msg_hdr.frag_len); if (ret < 0) { /* SSLfatal() already called */ return 0; } if (ret > 0) { - s->init_num = frag_len; - *len = frag_len; + s->init_num = msg_hdr.frag_len; + *len = msg_hdr.frag_len; return 1; } @@ -877,17 +880,16 @@ static int dtls_get_reassembled_message(SSL_CONNECTION *s, int *errtype, } /* parse the message fragment header */ - dtls1_get_message_header(p, &msg_hdr); - - mlen = msg_hdr.msg_len; - frag_off = msg_hdr.frag_off; - frag_len = msg_hdr.frag_len; + if (!dtls1_read_hm_header(p, &msg_hdr)) { + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_LENGTH); + goto f_err; + } /* * We must have at least frag_len bytes left in the record to be read. * Fragments must not span records. */ - if (frag_len > s->rlayer.tlsrecs[s->rlayer.curr_rec].length) { + if (msg_hdr.frag_len > s->rlayer.tlsrecs[s->rlayer.curr_rec].length) { SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_LENGTH); goto f_err; } @@ -902,7 +904,7 @@ static int dtls_get_reassembled_message(SSL_CONNECTION *s, int *errtype, if (!s->server || msg_hdr.seq != 0 || s->d1->handshake_read_seq != 1 - || p[0] != SSL3_MT_CLIENT_HELLO + || msg_hdr.type != SSL3_MT_CLIENT_HELLO || s->statem.hand_state != DTLS_ST_SW_HELLO_VERIFY_REQUEST) { *errtype = dtls1_process_out_of_seq_message(s, &msg_hdr); return 0; @@ -915,21 +917,20 @@ static int dtls_get_reassembled_message(SSL_CONNECTION *s, int *errtype, chretran = 1; } - if (frag_len && frag_len < mlen) { + if (msg_hdr.frag_len > 0 && msg_hdr.frag_len < msg_hdr.msg_len) { *errtype = dtls1_reassemble_fragment(s, &msg_hdr); return 0; } if (!s->server - && s->d1->r_msg_hdr.frag_off == 0 && s->statem.hand_state != TLS_ST_OK - && p[0] == SSL3_MT_HELLO_REQUEST) { + && msg_hdr.type == SSL3_MT_HELLO_REQUEST) { /* * The server may always send 'Hello Request' messages -- we are * doing a handshake anyway now, so ignore them if their format is * correct. Does not count for 'Finished' MAC. */ - if (p[1] == 0 && p[2] == 0 && p[3] == 0) { + if (msg_hdr.msg_len == 0) { if (s->msg_callback) s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, p, DTLS1_HM_HEADER_LENGTH, ssl, @@ -937,8 +938,8 @@ static int dtls_get_reassembled_message(SSL_CONNECTION *s, int *errtype, s->init_num = 0; goto redo; - } else { /* Incorrectly formatted Hello request */ - + } else { + /* Incorrectly formatted Hello request */ SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_UNEXPECTED_MESSAGE); goto f_err; } @@ -949,11 +950,11 @@ static int dtls_get_reassembled_message(SSL_CONNECTION *s, int *errtype, goto f_err; } - if (frag_len > 0) { - p += DTLS1_HM_HEADER_LENGTH; + if (msg_hdr.frag_len > 0) { + p += DTLS1_HM_HEADER_LENGTH + msg_hdr.frag_off; i = ssl->method->ssl_read_bytes(ssl, SSL3_RT_HANDSHAKE, NULL, - &p[frag_off], frag_len, 0, &readbytes); + p, msg_hdr.frag_len, 0, &readbytes); /* * This shouldn't ever fail due to NBIO because we already checked @@ -972,7 +973,7 @@ static int dtls_get_reassembled_message(SSL_CONNECTION *s, int *errtype, * XDTLS: an incorrectly formatted fragment should cause the handshake * to fail */ - if (readbytes != frag_len) { + if (readbytes != msg_hdr.frag_len) { SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_LENGTH); goto f_err; } @@ -994,7 +995,7 @@ static int dtls_get_reassembled_message(SSL_CONNECTION *s, int *errtype, * soon as they sum up to handshake packet length, we assume we have got * all the fragments. */ - *len = s->init_num = frag_len; + *len = s->init_num = msg_hdr.frag_len; return 1; f_err: @@ -1091,7 +1092,7 @@ int dtls1_read_failed(SSL_CONNECTION *s, int code) return dtls1_handle_timeout(s); } -int dtls1_get_queue_priority(unsigned short seq, int is_ccs) +int dtls1_get_queue_priority(unsigned short seq, int record_type) { /* * The index of the retransmission queue actually is the message sequence @@ -1103,36 +1104,37 @@ int dtls1_get_queue_priority(unsigned short seq, int is_ccs) * 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; + int lsb = (record_type == SSL3_RT_CHANGE_CIPHER_SPEC); + + return seq * 2 - lsb; } -int dtls1_retransmit_buffered_messages(SSL_CONNECTION *s) +int dtls1_retransmit_sent_messages(SSL_CONNECTION *s) { - pqueue *sent = s->d1->sent_messages; - piterator iter; + piterator iter = pqueue_iterator(s->d1->sent_messages); pitem *item; - hm_fragment *frag; int found = 0; - iter = pqueue_iterator(sent); - for (item = pqueue_next(&iter); item != NULL; item = pqueue_next(&iter)) { - frag = (hm_fragment *)item->data; - if (dtls1_retransmit_message(s, (unsigned short) - dtls1_get_queue_priority - (frag->msg_header.seq, - frag->msg_header.is_ccs), &found) <= 0) + int prio; + dtls_sent_msg *sent_msg = (dtls_sent_msg *)item->data; + + prio = dtls1_get_queue_priority(sent_msg->msg_info.msg_seq, sent_msg->record_type); + + if (dtls1_retransmit_message(s, (unsigned short)prio, &found) <= 0) return -1; } return 1; } -int dtls1_buffer_message(SSL_CONNECTION *s, int is_ccs) +int dtls1_buffer_sent_message(SSL_CONNECTION *s, int record_type) { pitem *item; - hm_fragment *frag; + dtls_sent_msg *sent_msg; unsigned char seq64be[8]; + size_t headerlen; + int prio; /* * this function is called immediately after a message has been @@ -1141,54 +1143,40 @@ int dtls1_buffer_message(SSL_CONNECTION *s, int is_ccs) if (!ossl_assert(s->init_off == 0)) return 0; - frag = dtls1_hm_fragment_new(s->init_num, 0); - if (frag == NULL) + sent_msg = dtls1_sent_msg_new(s->init_num); + if (sent_msg == NULL) return 0; - memcpy(frag->fragment, s->init_buf->data, s->init_num); + memcpy(sent_msg->msg_buf, s->init_buf->data, s->init_num); - if (is_ccs) { + if (record_type == SSL3_RT_CHANGE_CIPHER_SPEC) /* For DTLS1_BAD_VER the header length is non-standard */ - if (!ossl_assert(s->d1->w_msg_hdr.msg_len + - ((s->version == - DTLS1_BAD_VER) ? 3 : DTLS1_CCS_HEADER_LENGTH) - == (unsigned int)s->init_num)) { - dtls1_hm_fragment_free(frag); - return 0; - } - } else { - if (!ossl_assert(s->d1->w_msg_hdr.msg_len + - DTLS1_HM_HEADER_LENGTH == (unsigned int)s->init_num)) { - dtls1_hm_fragment_free(frag); - return 0; - } + headerlen = (s->version == DTLS1_BAD_VER) ? 3 : DTLS1_CCS_HEADER_LENGTH; + else + headerlen = DTLS1_HM_HEADER_LENGTH; + + if (!ossl_assert(s->d1->w_msg.msg_body_len + headerlen == s->init_num)) { + dtls1_sent_msg_free(sent_msg); + return 0; } - frag->msg_header.msg_len = s->d1->w_msg_hdr.msg_len; - frag->msg_header.seq = s->d1->w_msg_hdr.seq; - frag->msg_header.type = s->d1->w_msg_hdr.type; - frag->msg_header.frag_off = 0; - frag->msg_header.frag_len = s->d1->w_msg_hdr.msg_len; - frag->msg_header.is_ccs = is_ccs; + sent_msg->msg_info.msg_body_len = s->d1->w_msg.msg_body_len; + sent_msg->msg_info.msg_seq = s->d1->w_msg.msg_seq; + sent_msg->msg_info.msg_type = s->d1->w_msg.msg_type; + sent_msg->record_type = record_type; /* save current state */ - frag->msg_header.saved_retransmit_state.wrlmethod = s->rlayer.wrlmethod; - frag->msg_header.saved_retransmit_state.wrl = s->rlayer.wrl; - + sent_msg->saved_retransmit_state.wrlmethod = s->rlayer.wrlmethod; + sent_msg->saved_retransmit_state.wrl = s->rlayer.wrl; + prio = dtls1_get_queue_priority(sent_msg->msg_info.msg_seq, sent_msg->record_type); memset(seq64be, 0, sizeof(seq64be)); - 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); + seq64be[6] = (unsigned char)(prio >> 8); + seq64be[7] = (unsigned char)prio; + + item = pitem_new(seq64be, sent_msg); if (item == NULL) { - dtls1_hm_fragment_free(frag); + dtls1_sent_msg_free(sent_msg); return 0; } @@ -1201,7 +1189,7 @@ int dtls1_retransmit_message(SSL_CONNECTION *s, unsigned short seq, int *found) int ret; /* XDTLS: for now assuming that read/writes are blocking */ pitem *item; - hm_fragment *frag; + dtls_sent_msg *sent_msg; unsigned long header_length; unsigned char seq64be[8]; struct dtls1_retransmit_state saved_state; @@ -1219,21 +1207,20 @@ int dtls1_retransmit_message(SSL_CONNECTION *s, unsigned short seq, int *found) } *found = 1; - frag = (hm_fragment *)item->data; + sent_msg = (dtls_sent_msg *)item->data; - if (frag->msg_header.is_ccs) + if (sent_msg->record_type == SSL3_RT_CHANGE_CIPHER_SPEC) header_length = DTLS1_CCS_HEADER_LENGTH; else header_length = DTLS1_HM_HEADER_LENGTH; - memcpy(s->init_buf->data, frag->fragment, - frag->msg_header.msg_len + header_length); - s->init_num = frag->msg_header.msg_len + header_length; + memcpy(s->init_buf->data, sent_msg->msg_buf, + sent_msg->msg_info.msg_body_len + header_length); + s->init_num = sent_msg->msg_info.msg_body_len + header_length; - dtls1_set_message_header_int(s, frag->msg_header.type, - frag->msg_header.msg_len, - frag->msg_header.seq, 0, - frag->msg_header.frag_len); + s->d1->w_msg.msg_type = sent_msg->msg_info.msg_type; + s->d1->w_msg.msg_body_len = sent_msg->msg_info.msg_body_len; + s->d1->w_msg.msg_seq = sent_msg->msg_info.msg_seq; /* save current state */ saved_state.wrlmethod = s->rlayer.wrlmethod; @@ -1242,8 +1229,8 @@ int dtls1_retransmit_message(SSL_CONNECTION *s, unsigned short seq, int *found) s->d1->retransmitting = 1; /* restore state in which the message was originally sent */ - s->rlayer.wrlmethod = frag->msg_header.saved_retransmit_state.wrlmethod; - s->rlayer.wrl = frag->msg_header.saved_retransmit_state.wrl; + s->rlayer.wrlmethod = sent_msg->saved_retransmit_state.wrlmethod; + s->rlayer.wrl = sent_msg->saved_retransmit_state.wrl; /* * The old wrl may be still pointing at an old BIO. Update it to what we're @@ -1251,8 +1238,7 @@ int dtls1_retransmit_message(SSL_CONNECTION *s, unsigned short seq, int *found) */ s->rlayer.wrlmethod->set1_bio(s->rlayer.wrl, s->wbio); - ret = dtls1_do_write(s, frag->msg_header.is_ccs ? - SSL3_RT_CHANGE_CIPHER_SPEC : SSL3_RT_HANDSHAKE); + ret = dtls1_do_write(s, sent_msg->record_type); /* restore current state */ s->rlayer.wrlmethod = saved_state.wrlmethod; @@ -1264,58 +1250,26 @@ int dtls1_retransmit_message(SSL_CONNECTION *s, unsigned short seq, int *found) return ret; } -void dtls1_set_message_header(SSL_CONNECTION *s, - unsigned char mt, size_t len, - size_t frag_off, size_t frag_len) -{ - if (frag_off == 0) { - s->d1->handshake_write_seq = s->d1->next_handshake_write_seq; - s->d1->next_handshake_write_seq++; - } - - dtls1_set_message_header_int(s, mt, len, s->d1->handshake_write_seq, - frag_off, frag_len); -} - -/* don't actually do the writing, wait till the MTU has been retrieved */ -static void -dtls1_set_message_header_int(SSL_CONNECTION *s, unsigned char mt, - size_t len, unsigned short seq_num, - size_t frag_off, size_t frag_len) -{ - struct hm_header_st *msg_hdr = &s->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; -} - -void dtls1_get_message_header(const unsigned char *data, struct - hm_header_st *msg_hdr) -{ - memset(msg_hdr, 0, sizeof(*msg_hdr)); - msg_hdr->type = *(data++); - n2l3(data, msg_hdr->msg_len); - - n2s(data, msg_hdr->seq); - n2l3(data, msg_hdr->frag_off); - n2l3(data, msg_hdr->frag_len); -} - int dtls1_set_handshake_header(SSL_CONNECTION *s, WPACKET *pkt, int htype) { if (htype == SSL3_MT_CHANGE_CIPHER_SPEC) { s->d1->handshake_write_seq = s->d1->next_handshake_write_seq; - dtls1_set_message_header_int(s, SSL3_MT_CCS, 0, - s->d1->handshake_write_seq, 0, 0); + + s->d1->w_msg.msg_type = SSL3_MT_CCS; + s->d1->w_msg.msg_body_len = 0; + s->d1->w_msg.msg_seq = s->d1->handshake_write_seq; + if (!WPACKET_put_bytes_u8(pkt, SSL3_MT_CCS)) return 0; } else { size_t subpacket_offset = DTLS1_HM_HEADER_LENGTH - SSL3_HM_HEADER_LENGTH; - dtls1_set_message_header(s, htype, 0, 0, 0); + s->d1->handshake_write_seq = s->d1->next_handshake_write_seq; + s->d1->next_handshake_write_seq++; + + s->d1->w_msg.msg_type = htype; + s->d1->w_msg.msg_body_len = 0; + s->d1->w_msg.msg_seq = s->d1->handshake_write_seq; /* Set the content type and 3 bytes for the message len */ if (!WPACKET_put_bytes_u8(pkt, htype) @@ -1333,23 +1287,26 @@ int dtls1_set_handshake_header(SSL_CONNECTION *s, WPACKET *pkt, int htype) int dtls1_close_construct_packet(SSL_CONNECTION *s, WPACKET *pkt, int htype) { size_t msglen; + int record_type; + + /* Convert from possible dummy message type */ + record_type = (htype == SSL3_MT_CHANGE_CIPHER_SPEC) ? SSL3_RT_CHANGE_CIPHER_SPEC + : SSL3_RT_HANDSHAKE; if ((htype != SSL3_MT_CHANGE_CIPHER_SPEC && !WPACKET_close(pkt)) || !WPACKET_get_length(pkt, &msglen) || msglen > INT_MAX) return 0; - if (htype != SSL3_MT_CHANGE_CIPHER_SPEC) { - s->d1->w_msg_hdr.msg_len = msglen - DTLS1_HM_HEADER_LENGTH; - s->d1->w_msg_hdr.frag_len = msglen - DTLS1_HM_HEADER_LENGTH; - } + if (htype != SSL3_MT_CHANGE_CIPHER_SPEC) + s->d1->w_msg.msg_body_len = msglen - DTLS1_HM_HEADER_LENGTH; + s->init_num = msglen; s->init_off = 0; if (htype != DTLS1_MT_HELLO_VERIFY_REQUEST) { /* Buffer the message to handle re-xmits */ - if (!dtls1_buffer_message(s, htype == SSL3_MT_CHANGE_CIPHER_SPEC - ? 1 : 0)) + if (!dtls1_buffer_sent_message(s, record_type)) return 0; } diff --git a/util/indent.pro b/util/indent.pro index bc626e4..dfe7b6a 100644 --- a/util/indent.pro +++ b/util/indent.pro @@ -600,6 +600,8 @@ -T clock_t -T custom_ext_methods -T hm_fragment +-T dtls_msg_info +-T dtls_sent_msg -T ssl_ctx_st -T ssl_flag_tbl -T ssl_st |