diff options
Diffstat (limited to 'ssl/statem/statem_dtls.c')
-rw-r--r-- | ssl/statem/statem_dtls.c | 231 |
1 files changed, 156 insertions, 75 deletions
diff --git a/ssl/statem/statem_dtls.c b/ssl/statem/statem_dtls.c index 8fe6cea72359..040c23035c99 100644 --- a/ssl/statem/statem_dtls.c +++ b/ssl/statem/statem_dtls.c @@ -1,7 +1,7 @@ /* * Copyright 2005-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html @@ -59,14 +59,14 @@ static hm_fragment *dtls1_hm_fragment_new(size_t frag_len, int reassembly) unsigned char *buf = NULL; unsigned char *bitmask = NULL; - if ((frag = OPENSSL_malloc(sizeof(*frag))) == NULL) { - SSLerr(SSL_F_DTLS1_HM_FRAGMENT_NEW, ERR_R_MALLOC_FAILURE); + if ((frag = OPENSSL_zalloc(sizeof(*frag))) == NULL) { + ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE); return NULL; } if (frag_len) { if ((buf = OPENSSL_malloc(frag_len)) == NULL) { - SSLerr(SSL_F_DTLS1_HM_FRAGMENT_NEW, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE); OPENSSL_free(frag); return NULL; } @@ -79,7 +79,7 @@ static hm_fragment *dtls1_hm_fragment_new(size_t frag_len, int reassembly) if (reassembly) { bitmask = OPENSSL_zalloc(RSMBLY_BITMASK_SIZE(frag_len)); if (bitmask == NULL) { - SSLerr(SSL_F_DTLS1_HM_FRAGMENT_NEW, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE); OPENSSL_free(buf); OPENSSL_free(frag); return NULL; @@ -95,11 +95,7 @@ void dtls1_hm_fragment_free(hm_fragment *frag) { if (!frag) return; - if (frag->msg_header.is_ccs) { - EVP_CIPHER_CTX_free(frag->msg_header. - saved_retransmit_state.enc_write_ctx); - EVP_MD_CTX_free(frag->msg_header.saved_retransmit_state.write_hash); - } + OPENSSL_free(frag->fragment); OPENSSL_free(frag->reassembly); OPENSSL_free(frag); @@ -132,17 +128,17 @@ int dtls1_do_write(SSL *s, int type) if (s->write_hash) { if (s->enc_write_ctx - && (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(s->enc_write_ctx)) & + && (EVP_CIPHER_get_flags(EVP_CIPHER_CTX_get0_cipher(s->enc_write_ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER) != 0) mac_size = 0; else - mac_size = EVP_MD_CTX_size(s->write_hash); + mac_size = EVP_MD_CTX_get_size(s->write_hash); } else mac_size = 0; if (s->enc_write_ctx && - (EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_CBC_MODE)) - blocksize = 2 * EVP_CIPHER_CTX_block_size(s->enc_write_ctx); + (EVP_CIPHER_CTX_get_mode(s->enc_write_ctx) == EVP_CIPH_CBC_MODE)) + blocksize = 2 * EVP_CIPHER_CTX_get_block_size(s->enc_write_ctx); else blocksize = 0; @@ -328,7 +324,7 @@ int dtls1_do_write(SSL *s, int type) return 0; } -int dtls_get_message(SSL *s, int *mt, size_t *len) +int dtls_get_message(SSL *s, int *mt) { struct hm_header_st *msg_hdr; unsigned char *p; @@ -349,10 +345,9 @@ int dtls_get_message(SSL *s, int *mt, size_t *len) return 0; } - *mt = s->s3->tmp.message_type; + *mt = s->s3.tmp.message_type; p = (unsigned char *)s->init_buf->data; - *len = s->init_num; if (*mt == SSL3_MT_CHANGE_CIPHER_SPEC) { if (s->msg_callback) { @@ -373,32 +368,54 @@ int dtls_get_message(SSL *s, int *mt, size_t *len) s2n(msg_hdr->seq, p); l2n3(0, p); l2n3(msg_len, p); - if (s->version != DTLS1_BAD_VER) { - p -= DTLS1_HM_HEADER_LENGTH; - msg_len += DTLS1_HM_HEADER_LENGTH; - } + memset(msg_hdr, 0, sizeof(*msg_hdr)); + + s->d1->handshake_read_seq++; + + s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH; + + return 1; +} + +/* + * Actually we already have the message body - but this is an opportunity for + * DTLS to do any further processing it wants at the same point that TLS would + * be asked for the message body. + */ +int dtls_get_message_body(SSL *s, size_t *len) +{ + unsigned char *msg = (unsigned char *)s->init_buf->data; + size_t msg_len = s->init_num + DTLS1_HM_HEADER_LENGTH; + + if (s->s3.tmp.message_type == SSL3_MT_CHANGE_CIPHER_SPEC) { + /* Nothing to be done */ + goto end; + } /* * If receiving Finished, record MAC of prior handshake messages for * Finished verification. */ - if (*mt == SSL3_MT_FINISHED && !ssl3_take_mac(s)) { + if (*(s->init_buf->data) == SSL3_MT_FINISHED && !ssl3_take_mac(s)) { /* SSLfatal() already called */ return 0; } - if (!ssl3_finish_mac(s, p, msg_len)) + if (s->version == DTLS1_BAD_VER) { + msg += DTLS1_HM_HEADER_LENGTH; + msg_len -= DTLS1_HM_HEADER_LENGTH; + } + + if (!ssl3_finish_mac(s, msg, msg_len)) return 0; + if (s->msg_callback) s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, - p, msg_len, s, s->msg_callback_arg); - - memset(msg_hdr, 0, sizeof(*msg_hdr)); - - s->d1->handshake_read_seq++; - - s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH; + s->init_buf->data, s->init_num + DTLS1_HM_HEADER_LENGTH, + s, s->msg_callback_arg); + end: + *len = s->init_num; return 1; } @@ -426,8 +443,7 @@ static int dtls1_preprocess_fragment(SSL *s, struct hm_header_st *msg_hdr) /* sanity checking */ if ((frag_off + frag_len) > msg_len || msg_len > dtls1_max_handshake_message_len(s)) { - SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_DTLS1_PREPROCESS_FRAGMENT, - SSL_R_EXCESSIVE_MESSAGE_SIZE); + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_EXCESSIVE_MESSAGE_SIZE); return 0; } @@ -437,14 +453,13 @@ static int dtls1_preprocess_fragment(SSL *s, struct hm_header_st *msg_hdr) * 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, SSL_F_DTLS1_PREPROCESS_FRAGMENT, - ERR_R_BUF_LIB); + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_BUF_LIB); return 0; } - s->s3->tmp.message_size = msg_len; + 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->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) { @@ -452,8 +467,7 @@ static int dtls1_preprocess_fragment(SSL *s, struct hm_header_st *msg_hdr) * 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_F_DTLS1_PREPROCESS_FRAGMENT, - SSL_R_EXCESSIVE_MESSAGE_SIZE); + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_EXCESSIVE_MESSAGE_SIZE); return 0; } @@ -473,23 +487,64 @@ static int dtls1_retrieve_buffered_fragment(SSL *s, size_t *len) * (2) update s->init_num */ pitem *item; + piterator iter; hm_fragment *frag; int ret; + int chretran = 0; + iter = pqueue_iterator(s->d1->buffered_messages); do { - item = pqueue_peek(s->d1->buffered_messages); + item = pqueue_next(&iter); if (item == NULL) return 0; frag = (hm_fragment *)item->data; if (frag->msg_header.seq < s->d1->handshake_read_seq) { - /* This is a stale message that has been buffered so clear it */ - pqueue_pop(s->d1->buffered_messages); - dtls1_hm_fragment_free(frag); - pitem_free(item); - item = NULL; - frag = NULL; + pitem *next; + hm_fragment *nextfrag; + + if (!s->server + || frag->msg_header.seq != 0 + || s->d1->handshake_read_seq != 1 + || s->statem.hand_state != DTLS_ST_SW_HELLO_VERIFY_REQUEST) { + /* + * This is a stale message that has been buffered so clear it. + * It is safe to pop this message from the queue even though + * we have an active iterator + */ + pqueue_pop(s->d1->buffered_messages); + dtls1_hm_fragment_free(frag); + pitem_free(item); + item = NULL; + frag = NULL; + } else { + /* + * We have fragments for a ClientHello without a cookie, + * even though we have sent a HelloVerifyRequest. It is possible + * that the HelloVerifyRequest got lost and this is a + * retransmission of the original ClientHello + */ + next = pqueue_next(&iter); + if (next != NULL) { + nextfrag = (hm_fragment *)next->data; + if (nextfrag->msg_header.seq == s->d1->handshake_read_seq) { + /* + * We have fragments for both a ClientHello without + * cookie and one with. Ditch the one without. + */ + pqueue_pop(s->d1->buffered_messages); + dtls1_hm_fragment_free(frag); + pitem_free(item); + item = next; + frag = nextfrag; + } else { + chretran = 1; + } + } else { + chretran = 1; + } + } } } while (item == NULL); @@ -497,7 +552,7 @@ static int dtls1_retrieve_buffered_fragment(SSL *s, size_t *len) if (frag->reassembly != NULL) return 0; - if (s->d1->handshake_read_seq == frag->msg_header.seq) { + 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); @@ -515,6 +570,16 @@ static int dtls1_retrieve_buffered_fragment(SSL *s, size_t *len) pitem_free(item); if (ret) { + if (chretran) { + /* + * We got a new ClientHello with a message sequence of 0. + * Reset the read/write sequences back to the beginning. + * We process it like this is the first time we've seen a + * ClientHello from the client. + */ + s->d1->handshake_read_seq = 0; + s->d1->next_handshake_write_seq = 0; + } *len = frag_len; return 1; } @@ -741,6 +806,7 @@ static int dtls_get_reassembled_message(SSL *s, int *errtype, size_t *len) int i, ret, recvd_type; struct hm_header_st msg_hdr; size_t readbytes; + int chretran = 0; *errtype = 0; @@ -768,7 +834,6 @@ static int dtls_get_reassembled_message(SSL *s, int *errtype, size_t *len) if (recvd_type == SSL3_RT_CHANGE_CIPHER_SPEC) { if (wire[0] != SSL3_MT_CCS) { SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, - SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, SSL_R_BAD_CHANGE_CIPHER_SPEC); goto f_err; } @@ -776,16 +841,15 @@ static int dtls_get_reassembled_message(SSL *s, int *errtype, size_t *len) memcpy(s->init_buf->data, wire, readbytes); s->init_num = readbytes - 1; s->init_msg = s->init_buf->data + 1; - s->s3->tmp.message_type = SSL3_MT_CHANGE_CIPHER_SPEC; - s->s3->tmp.message_size = readbytes - 1; + s->s3.tmp.message_type = SSL3_MT_CHANGE_CIPHER_SPEC; + s->s3.tmp.message_size = readbytes - 1; *len = readbytes - 1; return 1; } /* Handshake fails if message header is incomplete */ if (readbytes != DTLS1_HM_HEADER_LENGTH) { - SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, - SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, SSL_R_UNEXPECTED_MESSAGE); + SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_UNEXPECTED_MESSAGE); goto f_err; } @@ -801,8 +865,7 @@ static int dtls_get_reassembled_message(SSL *s, int *errtype, size_t *len) * Fragments must not span records. */ if (frag_len > RECORD_LAYER_get_rrec_length(&s->rlayer)) { - SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, - SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, SSL_R_BAD_LENGTH); + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_LENGTH); goto f_err; } @@ -813,8 +876,20 @@ static int dtls_get_reassembled_message(SSL *s, int *errtype, size_t *len) * although we're still expecting seq 0 (ClientHello) */ if (msg_hdr.seq != s->d1->handshake_read_seq) { - *errtype = dtls1_process_out_of_seq_message(s, &msg_hdr); - return 0; + if (!s->server + || msg_hdr.seq != 0 + || s->d1->handshake_read_seq != 1 + || wire[0] != 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; + } + /* + * We received a ClientHello and sent back a HelloVerifyRequest. We + * now seem to have received a retransmitted initial ClientHello. That + * is allowed (possibly our HelloVerifyRequest got lost). + */ + chretran = 1; } if (frag_len && frag_len < mlen) { @@ -841,9 +916,7 @@ static int dtls_get_reassembled_message(SSL *s, int *errtype, size_t *len) goto redo; } else { /* Incorrectly formatted Hello request */ - SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, - SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, - SSL_R_UNEXPECTED_MESSAGE); + SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_UNEXPECTED_MESSAGE); goto f_err; } } @@ -878,11 +951,21 @@ static int dtls_get_reassembled_message(SSL *s, int *errtype, size_t *len) * to fail */ if (readbytes != frag_len) { - SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, - SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, SSL_R_BAD_LENGTH); + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_LENGTH); goto f_err; } + if (chretran) { + /* + * We got a new ClientHello with a message sequence of 0. + * Reset the read/write sequences back to the beginning. + * We process it like this is the first time we've seen a ClientHello + * from the client. + */ + s->d1->handshake_read_seq = 0; + s->d1->next_handshake_write_seq = 0; + } + /* * Note that s->init_num is *not* used as current offset in * s->init_buf->data, but as a counter summing up fragments' lengths: as @@ -902,7 +985,7 @@ static int dtls_get_reassembled_message(SSL *s, int *errtype, size_t *len) * for these 2 messages, we need to * ssl->enc_read_ctx re-init * ssl->rlayer.read_sequence zero - * ssl->s3->read_mac_secret re-init + * ssl->s3.read_mac_secret re-init * ssl->session->read_sym_enc assign * ssl->session->read_compression assign * ssl->session->read_hash assign @@ -913,9 +996,7 @@ int dtls_construct_change_cipher_spec(SSL *s, WPACKET *pkt) s->d1->next_handshake_write_seq++; if (!WPACKET_put_bytes_u16(pkt, s->d1->handshake_write_seq)) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, - SSL_F_DTLS_CONSTRUCT_CHANGE_CIPHER_SPEC, - ERR_R_INTERNAL_ERROR); + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return 0; } } @@ -936,8 +1017,7 @@ WORK_STATE dtls_wait_for_dry(SSL *s) /* read app data until dry event */ ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s)); if (ret < 0) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DTLS_WAIT_FOR_DRY, - ERR_R_INTERNAL_ERROR); + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return WORK_ERROR; } @@ -950,12 +1030,11 @@ WORK_STATE dtls_wait_for_dry(SSL *s) */ if (dtls_get_reassembled_message(s, &errtype, &len)) { /* The call succeeded! This should never happen */ - SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_DTLS_WAIT_FOR_DRY, - SSL_R_UNEXPECTED_MESSAGE); + SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_UNEXPECTED_MESSAGE); return WORK_ERROR; } - s->s3->in_read_app_data = 2; + s->s3.in_read_app_data = 2; s->rwstate = SSL_READING; BIO_clear_retry_flags(SSL_get_rbio(s)); BIO_set_retry_read(SSL_get_rbio(s)); @@ -968,8 +1047,7 @@ WORK_STATE dtls_wait_for_dry(SSL *s) int dtls1_read_failed(SSL *s, int code) { if (code > 0) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, - SSL_F_DTLS1_READ_FAILED, ERR_R_INTERNAL_ERROR); + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return 0; } @@ -1051,12 +1129,16 @@ int dtls1_buffer_message(SSL *s, int is_ccs) 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)) + == (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_HEADER_LENGTH == (unsigned int)s->init_num)) { + dtls1_hm_fragment_free(frag); return 0; + } } frag->msg_header.msg_len = s->d1->w_msg_hdr.msg_len; @@ -1111,8 +1193,7 @@ int dtls1_retransmit_message(SSL *s, unsigned short seq, int *found) item = pqueue_find(s->d1->sent_messages, seq64be); if (item == NULL) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DTLS1_RETRANSMIT_MESSAGE, - ERR_R_INTERNAL_ERROR); + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); *found = 0; return 0; } |