From eddb067e2ce82bc2ea104b3ab5286fe334c0525d Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 2 Jun 2022 16:29:04 +0100 Subject: [PATCH] Move some DTLS read code into the read record layer Reviewed-by: Hugo Landau Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/18132) --- ssl/d1_lib.c | 1 + ssl/record/build.info | 2 +- ssl/record/methods/build.info | 2 +- ssl/record/methods/dtls_meth.c | 826 +++++++++++++++++++++++++++ ssl/record/methods/ktls_meth.c | 1 + ssl/record/methods/recmethod_local.h | 16 + ssl/record/methods/ssl3_meth.c | 1 + ssl/record/methods/tls13_meth.c | 1 + ssl/record/methods/tls1_meth.c | 1 + ssl/record/methods/tls_common.c | 91 +-- ssl/record/methods/tlsany_meth.c | 1 + ssl/record/rec_layer_d1.c | 412 ++++--------- ssl/record/rec_layer_s3.c | 96 ++-- ssl/record/record.h | 16 +- ssl/record/record_local.h | 14 +- ssl/record/ssl3_record.c | 427 -------------- ssl/ssl_lib.c | 4 +- ssl/statem/statem_dtls.c | 2 +- test/sslapitest.c | 22 +- 19 files changed, 1027 insertions(+), 909 deletions(-) create mode 100644 ssl/record/methods/dtls_meth.c diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c index dac7abd8a60..904a19a28ad 100644 --- a/ssl/d1_lib.c +++ b/ssl/d1_lib.c @@ -848,6 +848,7 @@ int DTLSv1_listen(SSL *ssl, BIO_ADDR *client) BIO_ADDR_clear(client); /* Buffer the record in the processed_rcds queue */ + /* TODO(RECLAYER): This is nasty and reaches inside the record layer. FIXME */ if (!dtls_buffer_listen_record(s, reclen, seq, align)) return -1; diff --git a/ssl/record/build.info b/ssl/record/build.info index 3786669b008..15a4f8b386d 100644 --- a/ssl/record/build.info +++ b/ssl/record/build.info @@ -12,7 +12,7 @@ ENDIF SOURCE[../../libssl]=\ rec_layer_s3.c rec_layer_d1.c ssl3_buffer.c ssl3_record.c \ - dtls1_bitmap.c ssl3_record_tls13.c + ssl3_record_tls13.c # For shared builds we need to include the sources needed in providers # (tls_pad.c) in libssl as well. diff --git a/ssl/record/methods/build.info b/ssl/record/methods/build.info index 2faecb138be..064bcaf177a 100644 --- a/ssl/record/methods/build.info +++ b/ssl/record/methods/build.info @@ -5,7 +5,7 @@ ENDIF SOURCE[../../../libssl]=\ tls_common.c ssl3_meth.c tls1_meth.c tls13_meth.c tlsany_meth.c \ - $KTLSSRC + dtls_meth.c $KTLSSRC # For shared builds we need to include the sources needed in providers # (ssl3_cbc.c) in libssl as well. diff --git a/ssl/record/methods/dtls_meth.c b/ssl/record/methods/dtls_meth.c new file mode 100644 index 00000000000..3c6274664d6 --- /dev/null +++ b/ssl/record/methods/dtls_meth.c @@ -0,0 +1,826 @@ +/* + * Copyright 2018-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * 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 + */ + +#include "../../ssl_local.h" +#include "../record_local.h" +#include "recmethod_local.h" + +/* mod 128 saturating subtract of two 64-bit values in big-endian order */ +static int satsub64be(const unsigned char *v1, const unsigned char *v2) +{ + int64_t ret; + uint64_t l1, l2; + + n2l8(v1, l1); + n2l8(v2, l2); + + ret = l1 - l2; + + /* We do not permit wrap-around */ + if (l1 > l2 && ret < 0) + return 128; + else if (l2 > l1 && ret > 0) + return -128; + + if (ret > 128) + return 128; + else if (ret < -128) + return -128; + else + return (int)ret; +} + +static int dtls1_record_replay_check(SSL_CONNECTION *s, DTLS1_BITMAP *bitmap) +{ + int cmp; + unsigned int shift; + const unsigned char *seq = s->rlayer.read_sequence; + OSSL_RECORD_LAYER *rl = (OSSL_RECORD_LAYER *)s->rrl; + + cmp = satsub64be(seq, bitmap->max_seq_num); + if (cmp > 0) { + SSL3_RECORD_set_seq_num(&rl->rrec[0], seq); + return 1; /* this record in new */ + } + shift = -cmp; + if (shift >= sizeof(bitmap->map) * 8) + return 0; /* stale, outside the window */ + else if (bitmap->map & (1UL << shift)) + return 0; /* record previously received */ + + SSL3_RECORD_set_seq_num(&rl->rrec[0], seq); + return 1; +} + +static void dtls1_record_bitmap_update(SSL_CONNECTION *s, DTLS1_BITMAP *bitmap) +{ + int cmp; + unsigned int shift; + const unsigned char *seq = RECORD_LAYER_get_read_sequence(&s->rlayer); + + cmp = satsub64be(seq, bitmap->max_seq_num); + if (cmp > 0) { + shift = cmp; + if (shift < sizeof(bitmap->map) * 8) + bitmap->map <<= shift, bitmap->map |= 1UL; + else + bitmap->map = 1UL; + memcpy(bitmap->max_seq_num, seq, SEQ_NUM_SIZE); + } else { + shift = -cmp; + if (shift < sizeof(bitmap->map) * 8) + bitmap->map |= 1UL << shift; + } +} + +static DTLS1_BITMAP *dtls1_get_bitmap(SSL_CONNECTION *s, SSL3_RECORD *rr, + unsigned int *is_next_epoch) +{ + OSSL_RECORD_LAYER *rl = s->rrl; + *is_next_epoch = 0; + + /* In current epoch, accept HM, CCS, DATA, & ALERT */ + if (rr->epoch == s->rlayer.d->r_epoch) + return &s->rlayer.d->bitmap; + + /* + * Only HM and ALERT messages can be from the next epoch and only if we + * have already processed all of the unprocessed records from the last + * epoch + */ + else if (rr->epoch == (unsigned long)(s->rlayer.d->r_epoch + 1) && + rl->unprocessed_rcds.epoch != s->rlayer.d->r_epoch && + (rr->type == SSL3_RT_HANDSHAKE || rr->type == SSL3_RT_ALERT)) { + *is_next_epoch = 1; + return &s->rlayer.d->next_bitmap; + } + + return NULL; +} + +static int dtls1_process_record(SSL_CONNECTION *s, DTLS1_BITMAP *bitmap) +{ + int i; + int enc_err; + SSL_SESSION *sess; + SSL3_RECORD *rr; + int imac_size; + size_t mac_size = 0; + unsigned char md[EVP_MAX_MD_SIZE]; + size_t max_plain_length = SSL3_RT_MAX_PLAIN_LENGTH; + SSL_MAC_BUF macbuf = { NULL, 0 }; + int ret = 0; + OSSL_RECORD_LAYER *rl = (OSSL_RECORD_LAYER *)s->rrl; + SSL *ssl = SSL_CONNECTION_GET_SSL(s); + + rr = &rl->rrec[0]; + sess = s->session; + + /* + * At this point, s->rlayer.packet_length == SSL3_RT_HEADER_LNGTH + rr->length, + * and we have that many bytes in s->rlayer.packet + */ + rr->input = &(s->rrlmethod->get0_packet(s->rrl)[DTLS1_RT_HEADER_LENGTH]); + + /* + * ok, we can now read from 's->rlayer.packet' data into 'rr'. rr->input + * points at rr->length bytes, which need to be copied into rr->data by + * either the decryption or by the decompression. When the data is 'copied' + * into the rr->data buffer, rr->input will be pointed at the new buffer + */ + + /* + * We now have - encrypted [ MAC [ compressed [ plain ] ] ] rr->length + * bytes of encrypted compressed stuff. + */ + + /* check is not needed I believe */ + if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) { + SSLfatal(s, SSL_AD_RECORD_OVERFLOW, SSL_R_ENCRYPTED_LENGTH_TOO_LONG); + return 0; + } + + /* decrypt in place in 'rr->input' */ + rr->data = rr->input; + rr->orig_len = rr->length; + + if (s->read_hash != NULL) { + const EVP_MD *tmpmd = EVP_MD_CTX_get0_md(s->read_hash); + + if (tmpmd != NULL) { + imac_size = EVP_MD_get_size(tmpmd); + if (!ossl_assert(imac_size >= 0 && imac_size <= EVP_MAX_MD_SIZE)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB); + return 0; + } + mac_size = (size_t)imac_size; + } + } + + if (SSL_READ_ETM(s) && s->read_hash) { + unsigned char *mac; + + if (rr->orig_len < mac_size) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_TOO_SHORT); + return 0; + } + rr->length -= mac_size; + mac = rr->data + rr->length; + i = ssl->method->ssl3_enc->mac(s, rr, md, 0 /* not send */ ); + if (i == 0 || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0) { + SSLfatal(s, SSL_AD_BAD_RECORD_MAC, + SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); + return 0; + } + /* + * We've handled the mac now - there is no MAC inside the encrypted + * record + */ + mac_size = 0; + } + + /* + * Set a mark around the packet decryption attempt. This is DTLS, so + * bad packets are just ignored, and we don't want to leave stray + * errors in the queue from processing bogus junk that we ignored. + */ + ERR_set_mark(); + enc_err = ssl->method->ssl3_enc->enc(s, rr, 1, 0, &macbuf, mac_size); + + /*- + * enc_err is: + * 0: if the record is publicly invalid, or an internal error, or AEAD + * decryption failed, or ETM decryption failed. + * 1: Success or MTE decryption failed (MAC will be randomised) + */ + if (enc_err == 0) { + ERR_pop_to_mark(); + if (ossl_statem_in_error(s)) { + /* SSLfatal() got called */ + goto end; + } + /* For DTLS we simply ignore bad packets. */ + rr->length = 0; + s->rrlmethod->reset_packet_length(s->rrl); + goto end; + } + ERR_clear_last_mark(); + OSSL_TRACE_BEGIN(TLS) { + BIO_printf(trc_out, "dec %zd\n", rr->length); + BIO_dump_indent(trc_out, rr->data, rr->length, 4); + } OSSL_TRACE_END(TLS); + + /* r->length is now the compressed data plus mac */ + if ((sess != NULL) + && !SSL_READ_ETM(s) + && (s->enc_read_ctx != NULL) + && (EVP_MD_CTX_get0_md(s->read_hash) != NULL)) { + /* s->read_hash != NULL => mac_size != -1 */ + + i = ssl->method->ssl3_enc->mac(s, rr, md, 0 /* not send */ ); + if (i == 0 || macbuf.mac == NULL + || CRYPTO_memcmp(md, macbuf.mac, mac_size) != 0) + enc_err = 0; + if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH + mac_size) + enc_err = 0; + } + + if (enc_err == 0) { + /* decryption failed, silently discard message */ + rr->length = 0; + s->rrlmethod->reset_packet_length(s->rrl); + goto end; + } + + /* r->length is now just compressed */ + if (s->expand != NULL) { + if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH) { + SSLfatal(s, SSL_AD_RECORD_OVERFLOW, + SSL_R_COMPRESSED_LENGTH_TOO_LONG); + goto end; + } + if (!ssl3_do_uncompress(s, rr)) { + SSLfatal(s, SSL_AD_DECOMPRESSION_FAILURE, SSL_R_BAD_DECOMPRESSION); + goto end; + } + } + + /* use current Max Fragment Length setting if applicable */ + if (s->session != NULL && USE_MAX_FRAGMENT_LENGTH_EXT(s->session)) + max_plain_length = GET_MAX_FRAGMENT_LENGTH(s->session); + + /* send overflow if the plaintext is too long now it has passed MAC */ + if (rr->length > max_plain_length) { + SSLfatal(s, SSL_AD_RECORD_OVERFLOW, SSL_R_DATA_LENGTH_TOO_LONG); + goto end; + } + + rr->off = 0; + /*- + * So at this point the following is true + * ssl->s3.rrec.type is the type of record + * ssl->s3.rrec.length == number of bytes in record + * ssl->s3.rrec.off == offset to first valid byte + * ssl->s3.rrec.data == where to take bytes from, increment + * after use :-). + */ + + /* we have pulled in a full packet so zero things */ + s->rrlmethod->reset_packet_length(s->rrl); + + /* Mark receipt of record. */ + dtls1_record_bitmap_update(s, bitmap); + + ret = 1; + end: + if (macbuf.alloced) + OPENSSL_free(macbuf.mac); + return ret; +} + +static int dtls_rlayer_buffer_record(SSL_CONNECTION *s, record_pqueue *queue, + unsigned char *priority) +{ + DTLS_RLAYER_RECORD_DATA *rdata; + pitem *item; + OSSL_RECORD_LAYER *rl = (OSSL_RECORD_LAYER *)s->rrl; + + /* Limit the size of the queue to prevent DOS attacks */ + if (pqueue_size(queue->q) >= 100) + return 0; + + rdata = OPENSSL_malloc(sizeof(*rdata)); + item = pitem_new(priority, rdata); + if (rdata == NULL || item == NULL) { + OPENSSL_free(rdata); + pitem_free(item); + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return -1; + } + + rdata->packet = s->rrlmethod->get0_packet(s->rrl); + rdata->packet_length = s->rrlmethod->get_packet_length(s->rrl); + memcpy(&(rdata->rbuf), s->rrlmethod->get0_rbuf(s->rrl), sizeof(SSL3_BUFFER)); + memcpy(&(rdata->rrec), &rl->rrec[0], sizeof(SSL3_RECORD)); + + item->data = rdata; + + s->rrlmethod->set0_packet(s->rrl, NULL, 0); + memset(s->rrlmethod->get0_rbuf(s->rrl), 0, sizeof(SSL3_BUFFER)); + memset(&rl->rrec[0], 0, sizeof(rl->rrec[0])); + + if (!ssl3_setup_buffers(s)) { + /* SSLfatal() already called */ + OPENSSL_free(rdata->rbuf.buf); + OPENSSL_free(rdata); + pitem_free(item); + return -1; + } + + if (pqueue_insert(queue->q, item) == NULL) { + /* Must be a duplicate so ignore it */ + OPENSSL_free(rdata->rbuf.buf); + OPENSSL_free(rdata); + pitem_free(item); + } + + return 1; +} + +/* copy buffered record into SSL structure */ +static int dtls_copy_rlayer_record(OSSL_RECORD_LAYER *rl, pitem *item) +{ + DTLS_RLAYER_RECORD_DATA *rdata; + SSL_CONNECTION *s = (SSL_CONNECTION *)rl->cbarg; + + rdata = (DTLS_RLAYER_RECORD_DATA *)item->data; + + SSL3_BUFFER_release(s->rrlmethod->get0_rbuf(s->rrl)); + + s->rrlmethod->set0_packet(s->rrl, rdata->packet, rdata->packet_length); + memcpy(s->rrlmethod->get0_rbuf(s->rrl), &(rdata->rbuf), sizeof(SSL3_BUFFER)); + memcpy(&rl->rrec[0], &(rdata->rrec), sizeof(SSL3_RECORD)); + + /* Set proper sequence number for mac calculation */ + memcpy(&(s->rlayer.read_sequence[2]), &(rdata->packet[5]), 6); + + return 1; +} + +static int dtls_retrieve_rlayer_buffered_record(OSSL_RECORD_LAYER *rl, + record_pqueue *queue) +{ + pitem *item; + + item = pqueue_pop(queue->q); + if (item) { + dtls_copy_rlayer_record(rl, item); + + OPENSSL_free(item->data); + pitem_free(item); + + return 1; + } + + return 0; +} + +static int dtls_process_rlayer_buffered_records(SSL_CONNECTION *s) +{ + pitem *item; + SSL3_BUFFER *rb; + SSL3_RECORD *rr; + DTLS1_BITMAP *bitmap; + unsigned int is_next_epoch; + int replayok = 1; + OSSL_RECORD_LAYER *rl = s->rrl; + + item = pqueue_peek(rl->unprocessed_rcds.q); + if (item) { + /* Check if epoch is current. */ + if (rl->unprocessed_rcds.epoch != s->rlayer.d->r_epoch) + return 1; /* Nothing to do. */ + + rr = rl->rrec; + + rb = s->rrlmethod->get0_rbuf(s->rrl); + + if (SSL3_BUFFER_get_left(rb) > 0) { + /* + * We've still got data from the current packet to read. There could + * be a record from the new epoch in it - so don't overwrite it + * with the unprocessed records yet (we'll do it when we've + * finished reading the current packet). + */ + return 1; + } + + /* Process all the records. */ + while (pqueue_peek(rl->unprocessed_rcds.q)) { + dtls_retrieve_rlayer_buffered_record(rl, &(rl->unprocessed_rcds)); + bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch); + if (bitmap == NULL) { + /* + * Should not happen. This will only ever be NULL when the + * current record is from a different epoch. But that cannot + * be the case because we already checked the epoch above + */ + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } +#ifndef OPENSSL_NO_SCTP + /* Only do replay check if no SCTP bio */ + if (!BIO_dgram_is_sctp(SSL_get_rbio(s))) +#endif + { + /* + * Check whether this is a repeat, or aged record. We did this + * check once already when we first received the record - but + * we might have updated the window since then due to + * records we subsequently processed. + */ + replayok = dtls1_record_replay_check(s, bitmap); + } + + if (!replayok || !dtls1_process_record(s, bitmap)) { + if (ossl_statem_in_error(s)) { + /* dtls1_process_record called SSLfatal() */ + return 0; + } + /* dump this record */ + rr->length = 0; + s->rrlmethod->reset_packet_length(s->rrl); + continue; + } + + if (dtls_rlayer_buffer_record(s, &(rl->processed_rcds), + SSL3_RECORD_get_seq_num(&rl->rrec[0])) < 0) { + /* SSLfatal() already called */ + return 0; + } + } + } + + /* + * sync epoch numbers once all the unprocessed records have been + * processed + */ + rl->processed_rcds.epoch = s->rlayer.d->r_epoch; + rl->unprocessed_rcds.epoch = s->rlayer.d->r_epoch + 1; + + return 1; +} + +int dtls_buffer_listen_record(SSL_CONNECTION *s, size_t len, unsigned char *seq, size_t off) +{ + SSL3_RECORD *rr; + OSSL_RECORD_LAYER *rl = s->rrl; + + rr = &rl->rrec[0]; + memset(rr, 0, sizeof(SSL3_RECORD)); + + rr->length = len; + rr->type = SSL3_RT_HANDSHAKE; + memcpy(rr->seq_num, seq, sizeof(rr->seq_num)); + rr->off = off; + + s->rrlmethod->set0_packet(s->rrl, s->rrlmethod->get0_rbuf(s->rrl)->buf, + DTLS1_RT_HEADER_LENGTH + len); + rr->data = s->rrlmethod->get0_packet(s->rrl) + DTLS1_RT_HEADER_LENGTH; + + if (dtls_rlayer_buffer_record(s, &(rl->processed_rcds), + SSL3_RECORD_get_seq_num(rr)) <= 0) { + /* SSLfatal() already called */ + return 0; + } + + return 1; +} + +/*- + * Call this to get a new input record. + * It will return <= 0 if more data is needed, normally due to an error + * or non-blocking IO. + * When it finishes, one packet has been decoded and can be found in + * ssl->s3.rrec.type - is the type of record + * ssl->s3.rrec.data - data + * ssl->s3.rrec.length - number of bytes + */ +/* used only by dtls1_read_bytes */ +static int dtls_get_more_records(OSSL_RECORD_LAYER *rl) +{ + int ssl_major, ssl_minor; + int rret; + size_t more, n; + SSL3_RECORD *rr; + unsigned char *p = NULL; + unsigned short version; + DTLS1_BITMAP *bitmap; + unsigned int is_next_epoch; + /* TODO(RECLAYER): Remove me */ + SSL_CONNECTION *s = (SSL_CONNECTION *)rl->cbarg; + SSL *ssl = SSL_CONNECTION_GET_SSL(s); + + rl->num_recs = 0; + rl->curr_rec = 0; + rl->num_released = 0; + + rr = rl->rrec; + + again: + /* + * The epoch may have changed. If so, process all the pending records. + * This is a non-blocking operation. + */ + if (!dtls_process_rlayer_buffered_records(s)) { + /* SSLfatal() already called */ + return OSSL_RECORD_RETURN_FATAL; + } + + /* if we're renegotiating, then there may be buffered records */ + if (dtls_retrieve_rlayer_buffered_record(rl, &rl->processed_rcds)) { + rl->num_recs = 1; + return OSSL_RECORD_RETURN_SUCCESS; + } + + /* get something from the wire */ + + /* check if we have the header */ + if ((RECORD_LAYER_get_rstate(&s->rlayer) != SSL_ST_READ_BODY) || + (s->rrlmethod->get_packet_length(s->rrl) < DTLS1_RT_HEADER_LENGTH)) { + rret = s->rrlmethod->read_n(s->rrl, DTLS1_RT_HEADER_LENGTH, + SSL3_BUFFER_get_len(s->rrlmethod->get0_rbuf(s->rrl)), + 0, 1, &n); + /* read timeout is handled by dtls1_read_bytes */ + if (rret < OSSL_RECORD_RETURN_SUCCESS) { + /* SSLfatal() already called if appropriate */ + return rret; /* error or non-blocking */ + } + + /* this packet contained a partial record, dump it */ + if (s->rrlmethod->get_packet_length(s->rrl) != DTLS1_RT_HEADER_LENGTH) { + s->rrlmethod->reset_packet_length(s->rrl); + goto again; + } + + RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_BODY); + + p = s->rrlmethod->get0_packet(s->rrl); + + if (s->msg_callback) + s->msg_callback(0, 0, SSL3_RT_HEADER, p, DTLS1_RT_HEADER_LENGTH, + ssl, s->msg_callback_arg); + + /* Pull apart the header into the DTLS1_RECORD */ + rr->type = *(p++); + ssl_major = *(p++); + ssl_minor = *(p++); + version = (ssl_major << 8) | ssl_minor; + + /* sequence number is 64 bits, with top 2 bytes = epoch */ + n2s(p, rr->epoch); + + memcpy(&(RECORD_LAYER_get_read_sequence(&s->rlayer)[2]), p, 6); + p += 6; + + n2s(p, rr->length); + rr->read = 0; + + /* + * Lets check the version. We tolerate alerts that don't have the exact + * version number (e.g. because of protocol version errors) + */ + if (!s->first_packet && rr->type != SSL3_RT_ALERT) { + if (version != s->version) { + /* unexpected version, silently discard */ + rr->length = 0; + rr->read = 1; + s->rrlmethod->reset_packet_length(s->rrl); + goto again; + } + } + + if ((version & 0xff00) != (s->version & 0xff00)) { + /* wrong version, silently discard record */ + rr->length = 0; + rr->read = 1; + s->rrlmethod->reset_packet_length(s->rrl); + goto again; + } + + if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) { + /* record too long, silently discard it */ + rr->length = 0; + rr->read = 1; + s->rrlmethod->reset_packet_length(s->rrl); + goto again; + } + + /* If received packet overflows own-client Max Fragment Length setting */ + if (s->session != NULL && USE_MAX_FRAGMENT_LENGTH_EXT(s->session) + && rr->length > GET_MAX_FRAGMENT_LENGTH(s->session) + SSL3_RT_MAX_ENCRYPTED_OVERHEAD) { + /* record too long, silently discard it */ + rr->length = 0; + rr->read = 1; + s->rrlmethod->reset_packet_length(s->rrl); + goto again; + } + + /* now s->rlayer.rstate == SSL_ST_READ_BODY */ + } + + /* s->rlayer.rstate == SSL_ST_READ_BODY, get and decode the data */ + + if (rr->length > + s->rrlmethod->get_packet_length(s->rrl) - DTLS1_RT_HEADER_LENGTH) { + /* now s->rlayer.packet_length == DTLS1_RT_HEADER_LENGTH */ + more = rr->length; + rret = s->rrlmethod->read_n(s->rrl, more, more, 1, 1, &n); + /* this packet contained a partial record, dump it */ + if (rret < OSSL_RECORD_RETURN_SUCCESS || n != more) { + if (ossl_statem_in_error(s)) { + /* read_n() called SSLfatal() */ + return OSSL_RECORD_RETURN_FATAL; + } + rr->length = 0; + rr->read = 1; + s->rrlmethod->reset_packet_length(s->rrl); + goto again; + } + + /* + * now n == rr->length, and s->rlayer.packet_length == + * DTLS1_RT_HEADER_LENGTH + rr->length + */ + } + /* set state for later operations */ + RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_HEADER); + + /* match epochs. NULL means the packet is dropped on the floor */ + bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch); + if (bitmap == NULL) { + rr->length = 0; + s->rrlmethod->reset_packet_length(s->rrl); /* dump this record */ + goto again; /* get another record */ + } +#ifndef OPENSSL_NO_SCTP + /* Only do replay check if no SCTP bio */ + if (!BIO_dgram_is_sctp(SSL_get_rbio(s))) { +#endif + /* Check whether this is a repeat, or aged record. */ + if (!dtls1_record_replay_check(s, bitmap)) { + rr->length = 0; + rr->read = 1; + s->rrlmethod->reset_packet_length(s->rrl); /* dump this record */ + goto again; /* get another record */ + } +#ifndef OPENSSL_NO_SCTP + } +#endif + + /* just read a 0 length packet */ + if (rr->length == 0) { + rr->read = 1; + goto again; + } + + /* + * If this record is from the next epoch (either HM or ALERT), and a + * handshake is currently in progress, buffer it since it cannot be + * processed at this time. + */ + if (is_next_epoch) { + if ((SSL_in_init(ssl) || ossl_statem_get_in_handshake(s))) { + if (dtls_rlayer_buffer_record (s, + &(rl->unprocessed_rcds), + rr->seq_num) < 0) { + /* SSLfatal() already called */ + return OSSL_RECORD_RETURN_FATAL; + } + } + rr->length = 0; + rr->read = 1; + s->rrlmethod->reset_packet_length(s->rrl); + goto again; + } + + if (!dtls1_process_record(s, bitmap)) { + if (ossl_statem_in_error(s)) { + /* dtls1_process_record() called SSLfatal */ + return OSSL_RECORD_RETURN_FATAL; + } + rr->length = 0; + rr->read = 1; + s->rrlmethod->reset_packet_length(s->rrl); /* dump this record */ + goto again; /* get another record */ + } + + rl->num_recs = 1; + return OSSL_RECORD_RETURN_SUCCESS; + +} + +static int dtls_set_protocol_version(OSSL_RECORD_LAYER *rl, int version) +{ + rl->version = version; + return 1; +} + +static struct record_functions_st dtls_funcs = { + NULL, + NULL, + dtls_get_more_records, + NULL, + NULL, + dtls_set_protocol_version, + NULL +}; + +static int dtls_free(OSSL_RECORD_LAYER *rl) +{ + pitem *item; + DTLS_RLAYER_RECORD_DATA *rdata; + + if (rl->unprocessed_rcds.q == NULL) { + while ((item = pqueue_pop(rl->unprocessed_rcds.q)) != NULL) { + rdata = (DTLS_RLAYER_RECORD_DATA *)item->data; + OPENSSL_free(rdata->rbuf.buf); + OPENSSL_free(item->data); + pitem_free(item); + } + pqueue_free(rl->unprocessed_rcds.q); + } + + if (rl->processed_rcds.q == NULL) { + while ((item = pqueue_pop(rl->processed_rcds.q)) != NULL) { + rdata = (DTLS_RLAYER_RECORD_DATA *)item->data; + OPENSSL_free(rdata->rbuf.buf); + OPENSSL_free(item->data); + pitem_free(item); + } + pqueue_free(rl->processed_rcds.q); + } + + return tls_free(rl); +} + +static int +dtls_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers, + int role, int direction, int level, unsigned char *key, + size_t keylen, unsigned char *iv, size_t ivlen, + unsigned char *mackey, size_t mackeylen, + const EVP_CIPHER *ciph, size_t taglen, + /* TODO(RECLAYER): This probably should not be an int */ + int mactype, + const EVP_MD *md, const SSL_COMP *comp, BIO *prev, + BIO *transport, BIO *next, BIO_ADDR *local, BIO_ADDR *peer, + const OSSL_PARAM *settings, const OSSL_PARAM *options, + const OSSL_DISPATCH *fns, void *cbarg, + OSSL_RECORD_LAYER **retrl) +{ + int ret; + + + ret = tls_int_new_record_layer(libctx, propq, vers, role, direction, level, + key, keylen, iv, ivlen, mackey, mackeylen, + ciph, taglen, mactype, md, comp, prev, + transport, next, local, peer, settings, + options, fns, cbarg, retrl); + + if (ret != OSSL_RECORD_RETURN_SUCCESS) + return ret; + + (*retrl)->unprocessed_rcds.q = pqueue_new(); + (*retrl)->processed_rcds.q = pqueue_new(); + if ((*retrl)->unprocessed_rcds.q == NULL || (*retrl)->processed_rcds.q == NULL) { + dtls_free(*retrl); + *retrl = NULL; + RLAYERfatal(*retrl, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE); + return OSSL_RECORD_RETURN_FATAL; + } + + (*retrl)->isdtls = 1; + (*retrl)->funcs = &dtls_funcs; + + return OSSL_RECORD_RETURN_SUCCESS; +} + +const OSSL_RECORD_METHOD ossl_dtls_record_method = { + dtls_new_record_layer, + dtls_free, + tls_reset, + tls_unprocessed_read_pending, + tls_processed_read_pending, + tls_app_data_pending, + tls_write_pending, + tls_get_max_record_len, + tls_get_max_records, + tls_write_records, + tls_retry_write_records, + tls_read_record, + tls_release_record, + tls_get_alert_code, + tls_set1_bio, + tls_set_protocol_version, + NULL, + tls_set_first_handshake, + tls_set_max_pipelines, + + /* + * TODO(RECLAYER): Remove these. These function pointers are temporary hacks + * during the record layer refactoring. They need to be removed before the + * refactor is complete. + */ + tls_default_read_n, + tls_get0_rbuf, + tls_get0_packet, + tls_set0_packet, + tls_get_packet_length, + tls_reset_packet_length +}; diff --git a/ssl/record/methods/ktls_meth.c b/ssl/record/methods/ktls_meth.c index 465795e5781..460501c9d38 100644 --- a/ssl/record/methods/ktls_meth.c +++ b/ssl/record/methods/ktls_meth.c @@ -473,6 +473,7 @@ static int ktls_post_process_record(OSSL_RECORD_LAYER *rl, SSL3_RECORD *rec) static struct record_functions_st ossl_ktls_funcs = { ktls_set_crypto_state, ktls_read_n, + tls_get_more_records, ktls_cipher, NULL, tls_default_set_protocol_version, diff --git a/ssl/record/methods/recmethod_local.h b/ssl/record/methods/recmethod_local.h index 1aa7f9b3eb5..01590626a75 100644 --- a/ssl/record/methods/recmethod_local.h +++ b/ssl/record/methods/recmethod_local.h @@ -34,6 +34,9 @@ struct record_functions_st int (*read_n)(OSSL_RECORD_LAYER *rl, size_t n, size_t max, int extend, int clearold, size_t *readbytes); + + int (*get_more_records)(OSSL_RECORD_LAYER *rl); + /* * Returns: * 0: if the record is publicly invalid, or an internal error, or AEAD @@ -169,6 +172,10 @@ struct ossl_record_layer_st size_t taglen; + /* DTLS eceived handshake records (processed and unprocessed) */ + record_pqueue unprocessed_rcds; + record_pqueue processed_rcds; + /* Callbacks */ void *cbarg; OSSL_FUNC_rlayer_skip_early_data_fn *skip_early_data; @@ -181,6 +188,14 @@ struct ossl_record_layer_st struct record_functions_st *funcs; }; +typedef struct dtls_rlayer_record_data_st { + unsigned char *packet; + size_t packet_length; + SSL3_BUFFER rbuf; + SSL3_RECORD rrec; +} DTLS_RLAYER_RECORD_DATA; + + extern struct record_functions_st ssl_3_0_funcs; extern struct record_functions_st tls_1_funcs; extern struct record_functions_st tls_1_3_funcs; @@ -216,6 +231,7 @@ __owur int ssl3_cbc_digest_record(const EVP_MD *md, int tls_default_read_n(OSSL_RECORD_LAYER *rl, size_t n, size_t max, int extend, int clearold, size_t *readbytes); +int tls_get_more_records(OSSL_RECORD_LAYER *rl); int tls_default_set_protocol_version(OSSL_RECORD_LAYER *rl, int version); int tls_default_validate_record_header(OSSL_RECORD_LAYER *rl, SSL3_RECORD *re); diff --git a/ssl/record/methods/ssl3_meth.c b/ssl/record/methods/ssl3_meth.c index 6d8fa14c16f..c8062679a2b 100644 --- a/ssl/record/methods/ssl3_meth.c +++ b/ssl/record/methods/ssl3_meth.c @@ -299,6 +299,7 @@ static int ssl3_mac(OSSL_RECORD_LAYER *rl, SSL3_RECORD *rec, unsigned char *md, struct record_functions_st ssl_3_0_funcs = { ssl3_set_crypto_state, tls_default_read_n, + tls_get_more_records, ssl3_cipher, ssl3_mac, tls_default_set_protocol_version, diff --git a/ssl/record/methods/tls13_meth.c b/ssl/record/methods/tls13_meth.c index 799df982378..0ef499ce410 100644 --- a/ssl/record/methods/tls13_meth.c +++ b/ssl/record/methods/tls13_meth.c @@ -241,6 +241,7 @@ static int tls13_post_process_record(OSSL_RECORD_LAYER *rl, SSL3_RECORD *rec) struct record_functions_st tls_1_3_funcs = { tls13_set_crypto_state, tls_default_read_n, + tls_get_more_records, tls13_cipher, NULL, tls_default_set_protocol_version, diff --git a/ssl/record/methods/tls1_meth.c b/ssl/record/methods/tls1_meth.c index bb15e4b1dda..8268d004fc1 100644 --- a/ssl/record/methods/tls1_meth.c +++ b/ssl/record/methods/tls1_meth.c @@ -545,6 +545,7 @@ static int tls1_mac(OSSL_RECORD_LAYER *rl, SSL3_RECORD *rec, unsigned char *md, struct record_functions_st tls_1_funcs = { tls1_set_crypto_state, tls_default_read_n, + tls_get_more_records, tls1_cipher, tls1_mac, tls_default_set_protocol_version, diff --git a/ssl/record/methods/tls_common.c b/ssl/record/methods/tls_common.c index 0f5aa4951cc..c3198b23b04 100644 --- a/ssl/record/methods/tls_common.c +++ b/ssl/record/methods/tls_common.c @@ -425,7 +425,7 @@ static int rlayer_early_data_count_ok(OSSL_RECORD_LAYER *rl, size_t length, * SSL3_RT_APPLICATION_DATA. The number of records returned will always be <= * |max_pipelines| */ -static int tls_get_more_records(OSSL_RECORD_LAYER *rl) +int tls_get_more_records(OSSL_RECORD_LAYER *rl) { int enc_err, rret; int i; @@ -975,7 +975,7 @@ int tls_read_record(OSSL_RECORD_LAYER *rl, void **rechandle, int *rversion, return OSSL_RECORD_RETURN_FATAL; } - ret = tls_get_more_records(rl); + ret = rl->funcs->get_more_records(rl); if (ret != OSSL_RECORD_RETURN_SUCCESS) return ret; @@ -990,8 +990,12 @@ int tls_read_record(OSSL_RECORD_LAYER *rl, void **rechandle, int *rversion, *rechandle = rec; *rversion = rec->rec_version; *type = rec->type; - *data = rec->data; + *data = rec->data + rec->off; *datalen = rec->length; + if (rl->isdtls) { + *epoch = (uint16_t)rec->epoch; + memcpy(seq_num, rec->seq_num, sizeof(rec->seq_num)); + } return OSSL_RECORD_RETURN_SUCCESS; } @@ -1209,53 +1213,6 @@ tls_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers, return ret; } -/* TODO(RECLAYER): Temporary funcs */ -static int dtls_set_protocol_version(OSSL_RECORD_LAYER *rl, int version) -{ - rl->version = version; - return 1; -} -static struct record_functions_st dtls_funcs = { - NULL, - NULL, - NULL, - NULL, - dtls_set_protocol_version, - NULL -}; - -static int -dtls_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers, - int role, int direction, int level, unsigned char *key, - size_t keylen, unsigned char *iv, size_t ivlen, - unsigned char *mackey, size_t mackeylen, - const EVP_CIPHER *ciph, size_t taglen, - /* TODO(RECLAYER): This probably should not be an int */ - int mactype, - const EVP_MD *md, const SSL_COMP *comp, BIO *prev, - BIO *transport, BIO *next, BIO_ADDR *local, BIO_ADDR *peer, - const OSSL_PARAM *settings, const OSSL_PARAM *options, - const OSSL_DISPATCH *fns, void *cbarg, - OSSL_RECORD_LAYER **retrl) -{ - int ret; - - - ret = tls_int_new_record_layer(libctx, propq, vers, role, direction, level, - key, keylen, iv, ivlen, mackey, mackeylen, - ciph, taglen, mactype, md, comp, prev, - transport, next, local, peer, settings, - options, fns, cbarg, retrl); - - if (ret != OSSL_RECORD_RETURN_SUCCESS) - return ret; - - (*retrl)->isdtls = 1; - (*retrl)->funcs = &dtls_funcs; - - return OSSL_RECORD_RETURN_SUCCESS; -} - static void tls_int_free(OSSL_RECORD_LAYER *rl) { /* TODO(RECLAYER): Cleanse sensitive fields */ @@ -1445,37 +1402,3 @@ const OSSL_RECORD_METHOD ossl_tls_record_method = { tls_get_packet_length, tls_reset_packet_length }; - -const OSSL_RECORD_METHOD ossl_dtls_record_method = { - dtls_new_record_layer, - tls_free, - tls_reset, - tls_unprocessed_read_pending, - tls_processed_read_pending, - tls_app_data_pending, - tls_write_pending, - tls_get_max_record_len, - tls_get_max_records, - tls_write_records, - tls_retry_write_records, - tls_read_record, - tls_release_record, - tls_get_alert_code, - tls_set1_bio, - tls_set_protocol_version, - NULL, - tls_set_first_handshake, - tls_set_max_pipelines, - - /* - * TODO(RECLAYER): Remove these. These function pointers are temporary hacks - * during the record layer refactoring. They need to be removed before the - * refactor is complete. - */ - tls_default_read_n, - tls_get0_rbuf, - tls_get0_packet, - tls_set0_packet, - tls_get_packet_length, - tls_reset_packet_length -}; diff --git a/ssl/record/methods/tlsany_meth.c b/ssl/record/methods/tlsany_meth.c index c0df9759e85..1953b7fed05 100644 --- a/ssl/record/methods/tlsany_meth.c +++ b/ssl/record/methods/tlsany_meth.c @@ -144,6 +144,7 @@ static int tls_any_set_protocol_version(OSSL_RECORD_LAYER *rl, int vers) struct record_functions_st tls_any_funcs = { tls_any_set_crypto_state, tls_default_read_n, + tls_get_more_records, tls_any_cipher, NULL, tls_any_set_protocol_version, diff --git a/ssl/record/rec_layer_d1.c b/ssl/record/rec_layer_d1.c index dd78921948f..9e41d382974 100644 --- a/ssl/record/rec_layer_d1.c +++ b/ssl/record/rec_layer_d1.c @@ -27,15 +27,9 @@ int DTLS_RECORD_LAYER_new(RECORD_LAYER *rl) rl->d = d; - d->unprocessed_rcds.q = pqueue_new(); - d->processed_rcds.q = pqueue_new(); d->buffered_app_data.q = pqueue_new(); - if (d->unprocessed_rcds.q == NULL || d->processed_rcds.q == NULL - || d->buffered_app_data.q == NULL) { - pqueue_free(d->unprocessed_rcds.q); - pqueue_free(d->processed_rcds.q); - pqueue_free(d->buffered_app_data.q); + if (d->buffered_app_data.q == NULL) { OPENSSL_free(d); rl->d = NULL; return 0; @@ -50,8 +44,6 @@ void DTLS_RECORD_LAYER_free(RECORD_LAYER *rl) return; DTLS_RECORD_LAYER_clear(rl); - pqueue_free(rl->d->unprocessed_rcds.q); - pqueue_free(rl->d->processed_rcds.q); pqueue_free(rl->d->buffered_app_data.q); OPENSSL_free(rl->d); rl->d = NULL; @@ -61,44 +53,22 @@ void DTLS_RECORD_LAYER_clear(RECORD_LAYER *rl) { DTLS_RECORD_LAYER *d; pitem *item = NULL; - DTLS1_RECORD_DATA *rdata; - pqueue *unprocessed_rcds; - pqueue *processed_rcds; + TLS_RECORD *rec; pqueue *buffered_app_data; d = rl->d; - while ((item = pqueue_pop(d->unprocessed_rcds.q)) != NULL) { - rdata = (DTLS1_RECORD_DATA *)item->data; - OPENSSL_free(rdata->rbuf.buf); - OPENSSL_free(item->data); - pitem_free(item); - } - - while ((item = pqueue_pop(d->processed_rcds.q)) != NULL) { - rdata = (DTLS1_RECORD_DATA *)item->data; - if (rl->s->options & SSL_OP_CLEANSE_PLAINTEXT) - OPENSSL_cleanse(rdata->rbuf.buf, rdata->rbuf.len); - OPENSSL_free(rdata->rbuf.buf); - OPENSSL_free(item->data); - pitem_free(item); - } - while ((item = pqueue_pop(d->buffered_app_data.q)) != NULL) { - rdata = (DTLS1_RECORD_DATA *)item->data; + rec = (TLS_RECORD *)item->data; if (rl->s->options & SSL_OP_CLEANSE_PLAINTEXT) - OPENSSL_cleanse(rdata->rbuf.buf, rdata->rbuf.len); - OPENSSL_free(rdata->rbuf.buf); + OPENSSL_cleanse(rec->data, rec->length); + OPENSSL_free(rec->data); OPENSSL_free(item->data); pitem_free(item); } - unprocessed_rcds = d->unprocessed_rcds.q; - processed_rcds = d->processed_rcds.q; buffered_app_data = d->buffered_app_data.q; memset(d, 0, sizeof(*d)); - d->unprocessed_rcds.q = unprocessed_rcds; - d->processed_rcds.q = processed_rcds; d->buffered_app_data.q = buffered_app_data; } @@ -123,40 +93,22 @@ void DTLS_RECORD_LAYER_set_write_sequence(RECORD_LAYER *rl, unsigned char *seq) memcpy(rl->write_sequence, seq, SEQ_NUM_SIZE); } -/* copy buffered record into SSL structure */ -static int dtls1_copy_record(SSL_CONNECTION *s, pitem *item) +int dtls_buffer_record(SSL_CONNECTION *s, TLS_RECORD *rec) { - DTLS1_RECORD_DATA *rdata; - - rdata = (DTLS1_RECORD_DATA *)item->data; - - SSL3_BUFFER_release(s->rrlmethod->get0_rbuf(s->rrl)); - - s->rrlmethod->set0_packet(s->rrl, rdata->packet, rdata->packet_length); - memcpy(s->rrlmethod->get0_rbuf(s->rrl), &(rdata->rbuf), sizeof(SSL3_BUFFER)); - memcpy(&s->rlayer.rrec, &(rdata->rrec), sizeof(SSL3_RECORD)); - - /* Set proper sequence number for mac calculation */ - memcpy(&(s->rlayer.read_sequence[2]), &(rdata->packet[5]), 6); - - return 1; -} - -int dtls1_buffer_record(SSL_CONNECTION *s, record_pqueue *queue, - unsigned char *priority) -{ - DTLS1_RECORD_DATA *rdata; + TLS_RECORD *rdata; pitem *item; -#ifndef OPENSSL_NO_SCTP - SSL *ssl = SSL_CONNECTION_GET_SSL(s); -#endif + record_pqueue *queue = &(s->rlayer.d->buffered_app_data); /* Limit the size of the queue to prevent DOS attacks */ if (pqueue_size(queue->q) >= 100) return 0; + /* We don't buffer partially read records */ + if (!ossl_assert(rec->off == 0)) + return -1; + rdata = OPENSSL_malloc(sizeof(*rdata)); - item = pitem_new(priority, rdata); + item = pitem_new(rec->seq_num, rdata); if (rdata == NULL || item == NULL) { OPENSSL_free(rdata); pitem_free(item); @@ -164,10 +116,24 @@ int dtls1_buffer_record(SSL_CONNECTION *s, record_pqueue *queue, return -1; } - rdata->packet = s->rrlmethod->get0_packet(s->rrl); - rdata->packet_length = s->rrlmethod->get_packet_length(s->rrl); - memcpy(&(rdata->rbuf), s->rrlmethod->get0_rbuf(s->rrl), sizeof(SSL3_BUFFER)); - memcpy(&(rdata->rrec), &s->rlayer.rrec, sizeof(SSL3_RECORD)); + *rdata = *rec; + /* + * We will release the record from the record layer soon, so we take a copy + * now. Copying data isn't good - but this should be infrequent so we + * accept it here. + */ + rdata->data = OPENSSL_memdup(rec->data, rec->length); + if (rdata->data == NULL) { + OPENSSL_free(rdata); + pitem_free(item); + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE); + return -1; + } + /* + * We use a NULL rechandle to indicate that the data field has been + * allocated by us. + */ + rdata->rechandle = NULL; item->data = rdata; @@ -181,21 +147,9 @@ int dtls1_buffer_record(SSL_CONNECTION *s, record_pqueue *queue, } #endif - s->rrlmethod->set0_packet(s->rrl, NULL, 0); - memset(s->rrlmethod->get0_rbuf(s->rrl), 0, sizeof(SSL3_BUFFER)); - memset(&s->rlayer.rrec, 0, sizeof(s->rlayer.rrec)); - - if (!ssl3_setup_buffers(s)) { - /* SSLfatal() already called */ - OPENSSL_free(rdata->rbuf.buf); - OPENSSL_free(rdata); - pitem_free(item); - return -1; - } - if (pqueue_insert(queue->q, item) == NULL) { /* Must be a duplicate so ignore it */ - OPENSSL_free(rdata->rbuf.buf); + OPENSSL_free(rdata->data); OPENSSL_free(rdata); pitem_free(item); } @@ -203,114 +157,39 @@ int dtls1_buffer_record(SSL_CONNECTION *s, record_pqueue *queue, return 1; } -int dtls1_retrieve_buffered_record(SSL_CONNECTION *s, record_pqueue *queue) +/* Unbuffer a previously buffered TLS_RECORD structure if any */ +static void dtls_unbuffer_record(SSL_CONNECTION *s) { + TLS_RECORD *rdata; pitem *item; - item = pqueue_pop(queue->q); - if (item) { - dtls1_copy_record(s, item); - - OPENSSL_free(item->data); - pitem_free(item); - - return 1; - } - - return 0; -} - -/* - * retrieve a buffered record that belongs to the new epoch, i.e., not - * processed yet - */ -#define dtls1_get_unprocessed_record(s) \ - dtls1_retrieve_buffered_record((s), \ - &((s)->rlayer.d->unprocessed_rcds)) - -int dtls1_process_buffered_records(SSL_CONNECTION *s) -{ - pitem *item; - SSL3_BUFFER *rb; - SSL3_RECORD *rr; - DTLS1_BITMAP *bitmap; - unsigned int is_next_epoch; - int replayok = 1; - - item = pqueue_peek(s->rlayer.d->unprocessed_rcds.q); - if (item) { - /* Check if epoch is current. */ - if (s->rlayer.d->unprocessed_rcds.epoch != s->rlayer.d->r_epoch) - return 1; /* Nothing to do. */ + /* If we already have records to handle then do nothing */ + if (s->rlayer.curr_rec < s->rlayer.num_recs) + return; - rr = RECORD_LAYER_get_rrec(&s->rlayer); + item = pqueue_pop(s->rlayer.d->buffered_app_data.q); + if (item != NULL) { + rdata = (TLS_RECORD *)item->data; - rb = s->rrlmethod->get0_rbuf(s->rrl); + s->rlayer.tlsrecs[0] = *rdata; + s->rlayer.num_recs = 1; + s->rlayer.curr_rec = 0; - if (SSL3_BUFFER_get_left(rb) > 0) { - /* - * We've still got data from the current packet to read. There could - * be a record from the new epoch in it - so don't overwrite it - * with the unprocessed records yet (we'll do it when we've - * finished reading the current packet). - */ - return 1; - } - - /* Process all the records. */ - while (pqueue_peek(s->rlayer.d->unprocessed_rcds.q)) { - dtls1_get_unprocessed_record(s); - bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch); - if (bitmap == NULL) { - /* - * Should not happen. This will only ever be NULL when the - * current record is from a different epoch. But that cannot - * be the case because we already checked the epoch above - */ - SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); - return 0; - } #ifndef OPENSSL_NO_SCTP - /* Only do replay check if no SCTP bio */ - if (!BIO_dgram_is_sctp(SSL_get_rbio(SSL_CONNECTION_GET_SSL(s)))) + /* Restore bio_dgram_sctp_rcvinfo struct */ + if (BIO_dgram_is_sctp(SSL_get_rbio(s))) { + DTLS1_RECORD_DATA *rdata = (DTLS1_RECORD_DATA *)item->data; + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SCTP_SET_RCVINFO, + sizeof(rdata->recordinfo), &rdata->recordinfo); + } #endif - { - /* - * Check whether this is a repeat, or aged record. We did this - * check once already when we first received the record - but - * we might have updated the window since then due to - * records we subsequently processed. - */ - replayok = dtls1_record_replay_check(s, bitmap); - } - if (!replayok || !dtls1_process_record(s, bitmap)) { - if (ossl_statem_in_error(s)) { - /* dtls1_process_record called SSLfatal() */ - return 0; - } - /* dump this record */ - rr->length = 0; - s->rrlmethod->reset_packet_length(s->rrl); - continue; - } + /* Set proper sequence number for mac calculation */ + memcpy(&(s->rlayer.read_sequence[2]), &(rdata->seq_num[2]), 6); - if (dtls1_buffer_record(s, &(s->rlayer.d->processed_rcds), - SSL3_RECORD_get_seq_num(s->rlayer.rrec)) < 0) { - /* SSLfatal() already called */ - return 0; - } - } + OPENSSL_free(item->data); + pitem_free(item); } - - /* - * sync epoch numbers once all the unprocessed records have been - * processed - */ - s->rlayer.d->processed_rcds.epoch = s->rlayer.d->r_epoch; - s->rlayer.d->unprocessed_rcds.epoch = s->rlayer.d->r_epoch + 1; - - return 1; } /*- @@ -345,9 +224,9 @@ int dtls1_process_buffered_records(SSL_CONNECTION *s) int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, size_t len, int peek, size_t *readbytes) { - int i, j, iret; + int i, j, ret; size_t n; - SSL3_RECORD *rr; + TLS_RECORD *rr; void (*cb) (const SSL *ssl, int type2, int val) = NULL; SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s); @@ -382,37 +261,12 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, start: sc->rwstate = SSL_NOTHING; - /*- - * s->s3.rrec.type - is the type of record - * s->s3.rrec.data, - data - * s->s3.rrec.off, - offset into 'data' for next read - * s->s3.rrec.length, - number of bytes. - */ - rr = sc->rlayer.rrec; - /* * We are not handshaking and have no data yet, so process data buffered * during the last handshake in advance, if any. */ - if (SSL_is_init_finished(s) && SSL3_RECORD_get_length(rr) == 0) { - pitem *item; - item = pqueue_pop(sc->rlayer.d->buffered_app_data.q); - if (item) { -#ifndef OPENSSL_NO_SCTP - /* Restore bio_dgram_sctp_rcvinfo struct */ - if (BIO_dgram_is_sctp(SSL_get_rbio(s))) { - DTLS1_RECORD_DATA *rdata = (DTLS1_RECORD_DATA *)item->data; - BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SCTP_SET_RCVINFO, - sizeof(rdata->recordinfo), &rdata->recordinfo); - } -#endif - - dtls1_copy_record(sc, item); - - OPENSSL_free(item->data); - pitem_free(item); - } - } + if (SSL_is_init_finished(s)) + dtls_unbuffer_record(sc); /* Check for timeout */ if (dtls1_handle_timeout(sc) > 0) { @@ -423,49 +277,57 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, } /* get new packet if necessary */ - if ((SSL3_RECORD_get_length(rr) == 0) - || (sc->rlayer.rstate == SSL_ST_READ_BODY)) { - RECORD_LAYER_set_numrpipes(&sc->rlayer, 0); - iret = dtls1_get_record(sc); - if (iret <= 0) { - iret = dtls1_read_failed(sc, iret); - /* - * Anything other than a timeout is an error. SSLfatal() already - * called if appropriate. - */ - if (iret <= 0) - return iret; - else - goto start; - } - RECORD_LAYER_set_numrpipes(&sc->rlayer, 1); + if (sc->rlayer.curr_rec >= sc->rlayer.num_recs) { + sc->rlayer.curr_rec = sc->rlayer.num_recs = 0; + do { + rr = &sc->rlayer.tlsrecs[sc->rlayer.num_recs]; + + /* TODO(RECLAYER): Check HANDLE_RLAYER_RETURN for DTLS */ + ret = HANDLE_RLAYER_RETURN(sc, + sc->rrlmethod->read_record(sc->rrl, &rr->rechandle, + &rr->version, &rr->type, + &rr->data, &rr->length, + &rr->epoch, rr->seq_num)); + if (ret <= 0) { + ret = dtls1_read_failed(sc, ret); + /* + * Anything other than a timeout is an error. SSLfatal() already + * called if appropriate. + */ + if (ret <= 0) + return ret; + else + goto start; + } + rr->off = 0; + sc->rlayer.num_recs++; + } while (sc->rrlmethod->processed_read_pending(sc->rrl) + && sc->rlayer.num_recs < SSL_MAX_PIPELINES); } + rr = &sc->rlayer.tlsrecs[sc->rlayer.curr_rec]; /* * Reset the count of consecutive warning alerts if we've got a non-empty * record that isn't an alert. */ - if (SSL3_RECORD_get_type(rr) != SSL3_RT_ALERT - && SSL3_RECORD_get_length(rr) != 0) + if (rr->type != SSL3_RT_ALERT && rr->length != 0) sc->rlayer.alert_count = 0; /* we now have a packet which can be read and processed */ if (sc->s3.change_cipher_spec /* set when we receive ChangeCipherSpec, * reset by ssl3_get_finished */ - && (SSL3_RECORD_get_type(rr) != SSL3_RT_HANDSHAKE)) { + && (rr->type != SSL3_RT_HANDSHAKE)) { /* * 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. */ - if (dtls1_buffer_record(sc, &(sc->rlayer.d->buffered_app_data), - SSL3_RECORD_get_seq_num(rr)) < 0) { + if (dtls_buffer_record(sc, rr) < 0) { /* SSLfatal() already called */ return -1; } - SSL3_RECORD_set_length(rr, 0); - SSL3_RECORD_set_read(rr); + ssl_release_record(sc, rr); goto start; } @@ -474,14 +336,13 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, * 'peek' mode) */ if (sc->shutdown & SSL_RECEIVED_SHUTDOWN) { - SSL3_RECORD_set_length(rr, 0); - SSL3_RECORD_set_read(rr); + ssl_release_record(sc, rr); sc->rwstate = SSL_NOTHING; return 0; } - if (type == SSL3_RECORD_get_type(rr) - || (SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC + if (type == rr->type + || (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC && type == SSL3_RT_HANDSHAKE && recvd_type != NULL)) { /* * SSL3_RT_APPLICATION_DATA or @@ -500,37 +361,37 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, } if (recvd_type != NULL) - *recvd_type = SSL3_RECORD_get_type(rr); + *recvd_type = rr->type; if (len == 0) { /* - * Mark a zero length record as read. This ensures multiple calls to + * Release a zero length record. This ensures multiple calls to * SSL_read() with a zero length buffer will eventually cause * SSL_pending() to report data as being available. */ - if (SSL3_RECORD_get_length(rr) == 0) - SSL3_RECORD_set_read(rr); + if (rr->length == 0) + ssl_release_record(sc, rr); return 0; } - if (len > SSL3_RECORD_get_length(rr)) - n = SSL3_RECORD_get_length(rr); + if (len > rr->length) + n = rr->length; else n = len; - memcpy(buf, &(SSL3_RECORD_get_data(rr)[SSL3_RECORD_get_off(rr)]), n); + memcpy(buf, &(rr->data[rr->off]), n); if (peek) { - if (SSL3_RECORD_get_length(rr) == 0) - SSL3_RECORD_set_read(rr); + if (rr->length == 0) + ssl_release_record(sc, rr); } else { if (sc->options & SSL_OP_CLEANSE_PLAINTEXT) - OPENSSL_cleanse(&(SSL3_RECORD_get_data(rr)[SSL3_RECORD_get_off(rr)]), n); - SSL3_RECORD_sub_length(rr, n); - SSL3_RECORD_add_off(rr, n); - if (SSL3_RECORD_get_length(rr) == 0) { + OPENSSL_cleanse(&(rr->data[rr->off]), n); + rr->length -= n; + rr->off += n; + if (rr->length == 0) { + /* TODO(RECLAYER): Do something with this? */ sc->rlayer.rstate = SSL_ST_READ_HEADER; - SSL3_RECORD_set_off(rr, 0); - SSL3_RECORD_set_read(rr); + ssl_release_record(sc, rr); } } #ifndef OPENSSL_NO_SCTP @@ -555,13 +416,12 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, * then it was unexpected (Hello Request or Client Hello). */ - if (SSL3_RECORD_get_type(rr) == SSL3_RT_ALERT) { + if (rr->type == SSL3_RT_ALERT) { unsigned int alert_level, alert_descr; - unsigned char *alert_bytes = SSL3_RECORD_get_data(rr) - + SSL3_RECORD_get_off(rr); + unsigned char *alert_bytes = rr->data + rr->off; PACKET alert; - if (!PACKET_buf_init(&alert, alert_bytes, SSL3_RECORD_get_length(rr)) + if (!PACKET_buf_init(&alert, alert_bytes, rr->length) || !PACKET_get_1(&alert, &alert_level) || !PACKET_get_1(&alert, &alert_descr) || PACKET_remaining(&alert) != 0) { @@ -585,7 +445,7 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, if (alert_level == SSL3_AL_WARNING) { sc->s3.warn_alert = alert_descr; - SSL3_RECORD_set_read(rr); + ssl_release_record(sc, rr); sc->rlayer.alert_count++; if (sc->rlayer.alert_count == MAX_WARN_ALERT_COUNT) { @@ -620,7 +480,7 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, SSL_AD_REASON_OFFSET + alert_descr, "SSL alert number %d", alert_descr); sc->shutdown |= SSL_RECEIVED_SHUTDOWN; - SSL3_RECORD_set_read(rr); + ssl_release_record(sc, rr); SSL_CTX_remove_session(sc->session_ctx, sc->session); return 0; } else { @@ -634,36 +494,32 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, if (sc->shutdown & SSL_SENT_SHUTDOWN) { /* but we have not received a * shutdown */ sc->rwstate = SSL_NOTHING; - SSL3_RECORD_set_length(rr, 0); - SSL3_RECORD_set_read(rr); + ssl_release_record(sc, rr); return 0; } - if (SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC) { + if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC) { /* * We can't process a CCS now, because previous handshake messages * are still missing, so just drop it. */ - SSL3_RECORD_set_length(rr, 0); - SSL3_RECORD_set_read(rr); + ssl_release_record(sc, rr); goto start; } /* * Unexpected handshake message (Client Hello, or protocol violation) */ - if ((SSL3_RECORD_get_type(rr) == SSL3_RT_HANDSHAKE) && - !ossl_statem_get_in_handshake(sc)) { + if (rr->type == SSL3_RT_HANDSHAKE && !ossl_statem_get_in_handshake(sc)) { struct hm_header_st msg_hdr; /* * This may just be a stale retransmit. Also sanity check that we have * at least enough record bytes for a message header */ - if (SSL3_RECORD_get_epoch(rr) != sc->rlayer.d->r_epoch - || SSL3_RECORD_get_length(rr) < DTLS1_HM_HEADER_LENGTH) { - SSL3_RECORD_set_length(rr, 0); - SSL3_RECORD_set_read(rr); + if (rr->epoch != sc->rlayer.d->r_epoch + || rr->length < DTLS1_HM_HEADER_LENGTH) { + ssl_release_record(sc, rr); goto start; } @@ -684,8 +540,7 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, if (ossl_statem_in_error(sc)) return -1; } - SSL3_RECORD_set_length(rr, 0); - SSL3_RECORD_set_read(rr); + ssl_release_record(sc, rr); if (!(sc->mode & SSL_MODE_AUTO_RETRY)) { if (SSL3_BUFFER_get_left(sc->rrlmethod->get0_rbuf(sc->rrl)) == 0) { /* no read-ahead left? */ @@ -742,7 +597,7 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, goto start; } - switch (SSL3_RECORD_get_type(rr)) { + switch (rr->type) { default: SSLfatal(sc, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_UNEXPECTED_RECORD); return -1; @@ -1007,31 +862,6 @@ int do_dtls1_write(SSL_CONNECTION *sc, int type, const unsigned char *buf, return ssl3_write_pending(sc, type, buf, len, written); } -DTLS1_BITMAP *dtls1_get_bitmap(SSL_CONNECTION *s, SSL3_RECORD *rr, - unsigned int *is_next_epoch) -{ - - *is_next_epoch = 0; - - /* In current epoch, accept HM, CCS, DATA, & ALERT */ - if (rr->epoch == s->rlayer.d->r_epoch) - return &s->rlayer.d->bitmap; - - /* - * Only HM and ALERT messages can be from the next epoch and only if we - * have already processed all of the unprocessed records from the last - * epoch - */ - else if (rr->epoch == (unsigned long)(s->rlayer.d->r_epoch + 1) && - s->rlayer.d->unprocessed_rcds.epoch != s->rlayer.d->r_epoch && - (rr->type == SSL3_RT_HANDSHAKE || rr->type == SSL3_RT_ALERT)) { - *is_next_epoch = 1; - return &s->rlayer.d->next_bitmap; - } - - return NULL; -} - void dtls1_reset_seq_numbers(SSL_CONNECTION *s, int rw) { unsigned char *seq; diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c index 70e198be8b1..b51615c396b 100644 --- a/ssl/record/rec_layer_s3.c +++ b/ssl/record/rec_layer_s3.c @@ -78,34 +78,12 @@ void RECORD_LAYER_release(RECORD_LAYER *rl) /* Checks if we have unprocessed read ahead data pending */ int RECORD_LAYER_read_pending(const RECORD_LAYER *rl) { - /* - * TODO(RECLAYER): Temporarily do it the old way until DTLS is converted to - * the new record layer code - */ - if (SSL_CONNECTION_IS_DTLS(rl->s)) - return SSL3_BUFFER_get_left(&rl->rbuf) != 0; - return rl->s->rrlmethod->unprocessed_read_pending(rl->s->rrl); } /* Checks if we have decrypted unread record data pending */ int RECORD_LAYER_processed_read_pending(const RECORD_LAYER *rl) { - /* - * TODO(RECLAYER): Temporarily do it the old way until DTLS is converted to - * the new record layer code - */ - if (SSL_CONNECTION_IS_DTLS(rl->s)) { - const SSL3_RECORD *rr = rl->rrec; - - size_t curr_rec = 0, num_recs = RECORD_LAYER_get_numrpipes(rl); - - while (curr_rec < num_recs && SSL3_RECORD_is_read(&rr[curr_rec])) - curr_rec++; - - return curr_rec < num_recs; - } - return (rl->curr_rec < rl->num_recs) || rl->s->rrlmethod->processed_read_pending(rl->s->rrl); } @@ -137,32 +115,21 @@ size_t ssl3_pending(const SSL *s) if (sc->rlayer.rstate == SSL_ST_READ_BODY) return 0; - /* - * TODO(RECLAYER): We need to do it the old way temporary for DTLS until - * that is converted to use the new record layer code - */ if (SSL_CONNECTION_IS_DTLS(sc)) { - DTLS1_RECORD_DATA *rdata; + TLS_RECORD *rdata; pitem *item, *iter; iter = pqueue_iterator(sc->rlayer.d->buffered_app_data.q); while ((item = pqueue_next(&iter)) != NULL) { rdata = item->data; - num += rdata->rrec.length; + num += rdata->length; } + } - for (i = 0; i < RECORD_LAYER_get_numrpipes(&sc->rlayer); i++) { - if (SSL3_RECORD_get_type(&sc->rlayer.rrec[i]) - != SSL3_RT_APPLICATION_DATA) - return 0; - num += SSL3_RECORD_get_length(&sc->rlayer.rrec[i]); - } - } else { - for (i = 0; i rlayer.num_recs; i++) { - if (sc->rlayer.tlsrecs[i].type != SSL3_RT_APPLICATION_DATA) - return 0; - num += sc->rlayer.tlsrecs[i].length; - } + for (i = 0; i < sc->rlayer.num_recs; i++) { + if (sc->rlayer.tlsrecs[i].type != SSL3_RT_APPLICATION_DATA) + return num; + num += sc->rlayer.tlsrecs[i].length; } return num; @@ -1170,6 +1137,18 @@ int ossl_tls_handle_rlayer_return(SSL_CONNECTION *s, int ret, char *file, return ret; } +void ssl_release_record(SSL_CONNECTION *s, TLS_RECORD *rr) +{ + if (rr->rechandle != NULL) { + /* The record layer allocated the buffers for this record */ + s->rrlmethod->release_record(s->rrl, rr->rechandle); + } else { + /* We allocated the buffers for this record (only happens with DTLS) */ + OPENSSL_free(rr->data); + } + s->rlayer.curr_rec++; +} + /*- * Return up to 'len' payload bytes received in 'type' records. * 'type' is one of the following: @@ -1360,10 +1339,9 @@ int ssl3_read_bytes(SSL *ssl, int type, int *recvd_type, unsigned char *buf, * SSL_read() with a zero length buffer will eventually cause * SSL_pending() to report data as being available. */ - if (rr->length == 0) { - s->rrlmethod->release_record(s->rrl, rr->rechandle); - s->rlayer.curr_rec++; - } + if (rr->length == 0) + ssl_release_record(s, rr); + return 0; } @@ -1379,10 +1357,8 @@ int ssl3_read_bytes(SSL *ssl, int type, int *recvd_type, unsigned char *buf, buf += n; if (peek) { /* Mark any zero length record as consumed CVE-2016-6305 */ - if (rr->length == 0) { - s->rrlmethod->release_record(s->rrl, rr->rechandle); - s->rlayer.curr_rec++; - } + if (rr->length == 0) + ssl_release_record(s, rr); } else { if (s->options & SSL_OP_CLEANSE_PLAINTEXT) OPENSSL_cleanse(&(rr->data[rr->off]), n); @@ -1393,8 +1369,7 @@ int ssl3_read_bytes(SSL *ssl, int type, int *recvd_type, unsigned char *buf, #if 0 s->rlayer.rstate = SSL_ST_READ_HEADER; #endif - s->rrlmethod->release_record(s->rrl, rr->rechandle); - s->rlayer.curr_rec++; + ssl_release_record(s, rr); } } if (rr->length == 0 @@ -1490,8 +1465,7 @@ int ssl3_read_bytes(SSL *ssl, int type, int *recvd_type, unsigned char *buf, if ((!is_tls13 && alert_level == SSL3_AL_WARNING) || (is_tls13 && alert_descr == SSL_AD_USER_CANCELLED)) { s->s3.warn_alert = alert_descr; - s->rrlmethod->release_record(s->rrl, rr->rechandle); - s->rlayer.curr_rec++; + ssl_release_record(s, rr); s->rlayer.alert_count++; if (s->rlayer.alert_count == MAX_WARN_ALERT_COUNT) { @@ -1518,8 +1492,7 @@ int ssl3_read_bytes(SSL *ssl, int type, int *recvd_type, unsigned char *buf, SSL_AD_REASON_OFFSET + alert_descr, "SSL alert number %d", alert_descr); s->shutdown |= SSL_RECEIVED_SHUTDOWN; - s->rrlmethod->release_record(s->rrl, rr->rechandle); - s->rlayer.curr_rec++; + ssl_release_record(s, rr); SSL_CTX_remove_session(s->session_ctx, s->session); return 0; } else if (alert_descr == SSL_AD_NO_RENEGOTIATION) { @@ -1554,8 +1527,7 @@ int ssl3_read_bytes(SSL *ssl, int type, int *recvd_type, unsigned char *buf, * sent close_notify. */ if (!SSL_CONNECTION_IS_TLS13(s)) { - s->rrlmethod->release_record(s->rrl, rr->rechandle); - s->rlayer.curr_rec++; + ssl_release_record(s, rr); if ((s->mode & SSL_MODE_AUTO_RETRY) != 0) goto start; @@ -1574,8 +1546,7 @@ int ssl3_read_bytes(SSL *ssl, int type, int *recvd_type, unsigned char *buf, * above. * No alert sent because we already sent close_notify */ - s->rrlmethod->release_record(s->rrl, rr->rechandle); - s->rlayer.curr_rec++; + ssl_release_record(s, rr); SSLfatal(s, SSL_AD_NO_ALERT, SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY); return -1; @@ -1602,10 +1573,8 @@ int ssl3_read_bytes(SSL *ssl, int type, int *recvd_type, unsigned char *buf, rr->off += n; rr->length -= n; *dest_len += n; - if (rr->length == 0) { - s->rrlmethod->release_record(s->rrl, rr->rechandle); - s->rlayer.curr_rec++; - } + if (rr->length == 0) + ssl_release_record(s, rr); if (*dest_len < dest_maxlen) goto start; /* fragment was too small */ @@ -1709,8 +1678,7 @@ int ssl3_read_bytes(SSL *ssl, int type, int *recvd_type, unsigned char *buf, /* SSLfatal() already called */ return -1; } - s->rrlmethod->release_record(s->rrl, rr->rechandle); - s->rlayer.curr_rec++; + ssl_release_record(s, rr); goto start; } else { SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_UNEXPECTED_RECORD); diff --git a/ssl/record/record.h b/ssl/record/record.h index 51d96f26069..0b15e55fbc4 100644 --- a/ssl/record/record.h +++ b/ssl/record/record.h @@ -86,6 +86,13 @@ typedef struct tls_record_st { size_t length; /* Offset into the data buffer where to start reading */ size_t off; + /* epoch number. DTLS only */ + uint16_t epoch; + /* sequence number. DTLS only */ + unsigned char seq_num[SEQ_NUM_SIZE]; +#ifndef OPENSSL_NO_SCTP + struct bio_dgram_sctp_rcvinfo recordinfo; +#endif } TLS_RECORD; typedef struct dtls1_bitmap_st { @@ -122,9 +129,6 @@ typedef struct dtls_record_layer_st { DTLS1_BITMAP bitmap; /* renegotiation starts a new set of sequence numbers */ DTLS1_BITMAP next_bitmap; - /* Received handshake records (processed and unprocessed) */ - record_pqueue unprocessed_rcds; - record_pqueue processed_rcds; /* * Buffered application records. Only for records between CCS and * Finished to prevent either protocol violation or unnecessary message @@ -220,10 +224,6 @@ typedef struct ssl_mac_buf_st SSL_MAC_BUF; #define RECORD_LAYER_get_packet_length(rl) ((rl)->packet_length) #define RECORD_LAYER_add_packet_length(rl, inc) ((rl)->packet_length += (inc)) #define DTLS_RECORD_LAYER_get_w_epoch(rl) ((rl)->d->w_epoch) -#define DTLS_RECORD_LAYER_get_processed_rcds(rl) \ - ((rl)->d->processed_rcds) -#define DTLS_RECORD_LAYER_get_unprocessed_rcds(rl) \ - ((rl)->d->unprocessed_rcds) #define RECORD_LAYER_get_rbuf(rl) (&(rl)->rbuf) #define RECORD_LAYER_get_wbuf(rl) ((rl)->wbuf) @@ -276,7 +276,7 @@ int do_dtls1_write(SSL_CONNECTION *s, int type, const unsigned char *buf, void dtls1_reset_seq_numbers(SSL_CONNECTION *s, int rw); int dtls_buffer_listen_record(SSL_CONNECTION *s, size_t len, unsigned char *seq, size_t off); - +void ssl_release_record(SSL_CONNECTION *s, TLS_RECORD *rr); # define HANDLE_RLAYER_RETURN(s, ret) \ ossl_tls_handle_rlayer_return(s, ret, OPENSSL_FILE, OPENSSL_LINE) diff --git a/ssl/record/record_local.h b/ssl/record/record_local.h index c2b0109d8dc..8b898dfd0b1 100644 --- a/ssl/record/record_local.h +++ b/ssl/record/record_local.h @@ -36,19 +36,9 @@ #define RECORD_LAYER_clear_first_record(rl) ((rl)->is_first_record = 0) #define DTLS_RECORD_LAYER_get_r_epoch(rl) ((rl)->d->r_epoch) -DTLS1_BITMAP *dtls1_get_bitmap(SSL_CONNECTION *s, SSL3_RECORD *rr, - unsigned int *is_next_epoch); -int dtls1_process_buffered_records(SSL_CONNECTION *s); -int dtls1_retrieve_buffered_record(SSL_CONNECTION *s, record_pqueue *queue); -int dtls1_buffer_record(SSL_CONNECTION *s, record_pqueue *q, - unsigned char *priority); +int dtls_buffer_record(SSL_CONNECTION *s, TLS_RECORD *rec); void ssl3_record_sequence_update(unsigned char *seq); -/* Functions provided by the DTLS1_BITMAP component */ - -int dtls1_record_replay_check(SSL_CONNECTION *s, DTLS1_BITMAP *bitmap); -void dtls1_record_bitmap_update(SSL_CONNECTION *s, DTLS1_BITMAP *bitmap); - /* Macros/functions provided by the SSL3_BUFFER component */ #define SSL3_BUFFER_get_buf(b) ((b)->buf) @@ -120,8 +110,6 @@ __owur int tls1_cbc_remove_padding_and_mac(size_t *reclen, size_t block_size, size_t mac_size, int aead, OSSL_LIB_CTX *libctx); -int dtls1_process_record(SSL_CONNECTION *s, DTLS1_BITMAP *bitmap); -__owur int dtls1_get_record(SSL_CONNECTION *s); uint32_t ossl_get_max_early_data(SSL_CONNECTION *s); int ossl_early_data_count_ok(SSL_CONNECTION *s, size_t length, size_t overhead, int send); diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c index 42811e39c71..fac317a4ac6 100644 --- a/ssl/record/ssl3_record.c +++ b/ssl/record/ssl3_record.c @@ -833,430 +833,3 @@ int tls1_mac_old(SSL_CONNECTION *sc, SSL3_RECORD *rec, unsigned char *md, EVP_MD_CTX_free(hmac); return ret; } - -int dtls1_process_record(SSL_CONNECTION *s, DTLS1_BITMAP *bitmap) -{ - int i; - int enc_err; - SSL_SESSION *sess; - SSL3_RECORD *rr; - int imac_size; - size_t mac_size = 0; - unsigned char md[EVP_MAX_MD_SIZE]; - size_t max_plain_length = SSL3_RT_MAX_PLAIN_LENGTH; - SSL_MAC_BUF macbuf = { NULL, 0 }; - int ret = 0; - SSL *ssl = SSL_CONNECTION_GET_SSL(s); - - rr = RECORD_LAYER_get_rrec(&s->rlayer); - sess = s->session; - - /* - * At this point, s->rlayer.packet_length == SSL3_RT_HEADER_LNGTH + rr->length, - * and we have that many bytes in s->rlayer.packet - */ - rr->input = &(s->rrlmethod->get0_packet(s->rrl)[DTLS1_RT_HEADER_LENGTH]); - - /* - * ok, we can now read from 's->rlayer.packet' data into 'rr'. rr->input - * points at rr->length bytes, which need to be copied into rr->data by - * either the decryption or by the decompression. When the data is 'copied' - * into the rr->data buffer, rr->input will be pointed at the new buffer - */ - - /* - * We now have - encrypted [ MAC [ compressed [ plain ] ] ] rr->length - * bytes of encrypted compressed stuff. - */ - - /* check is not needed I believe */ - if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) { - SSLfatal(s, SSL_AD_RECORD_OVERFLOW, SSL_R_ENCRYPTED_LENGTH_TOO_LONG); - return 0; - } - - /* decrypt in place in 'rr->input' */ - rr->data = rr->input; - rr->orig_len = rr->length; - - if (s->read_hash != NULL) { - const EVP_MD *tmpmd = EVP_MD_CTX_get0_md(s->read_hash); - - if (tmpmd != NULL) { - imac_size = EVP_MD_get_size(tmpmd); - if (!ossl_assert(imac_size >= 0 && imac_size <= EVP_MAX_MD_SIZE)) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB); - return 0; - } - mac_size = (size_t)imac_size; - } - } - - if (SSL_READ_ETM(s) && s->read_hash) { - unsigned char *mac; - - if (rr->orig_len < mac_size) { - SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_TOO_SHORT); - return 0; - } - rr->length -= mac_size; - mac = rr->data + rr->length; - i = ssl->method->ssl3_enc->mac(s, rr, md, 0 /* not send */ ); - if (i == 0 || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0) { - SSLfatal(s, SSL_AD_BAD_RECORD_MAC, - SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); - return 0; - } - /* - * We've handled the mac now - there is no MAC inside the encrypted - * record - */ - mac_size = 0; - } - - /* - * Set a mark around the packet decryption attempt. This is DTLS, so - * bad packets are just ignored, and we don't want to leave stray - * errors in the queue from processing bogus junk that we ignored. - */ - ERR_set_mark(); - enc_err = ssl->method->ssl3_enc->enc(s, rr, 1, 0, &macbuf, mac_size); - - /*- - * enc_err is: - * 0: if the record is publicly invalid, or an internal error, or AEAD - * decryption failed, or ETM decryption failed. - * 1: Success or MTE decryption failed (MAC will be randomised) - */ - if (enc_err == 0) { - ERR_pop_to_mark(); - if (ossl_statem_in_error(s)) { - /* SSLfatal() got called */ - goto end; - } - /* For DTLS we simply ignore bad packets. */ - rr->length = 0; - s->rrlmethod->reset_packet_length(s->rrl); - goto end; - } - ERR_clear_last_mark(); - OSSL_TRACE_BEGIN(TLS) { - BIO_printf(trc_out, "dec %zd\n", rr->length); - BIO_dump_indent(trc_out, rr->data, rr->length, 4); - } OSSL_TRACE_END(TLS); - - /* r->length is now the compressed data plus mac */ - if ((sess != NULL) - && !SSL_READ_ETM(s) - && (s->enc_read_ctx != NULL) - && (EVP_MD_CTX_get0_md(s->read_hash) != NULL)) { - /* s->read_hash != NULL => mac_size != -1 */ - - i = ssl->method->ssl3_enc->mac(s, rr, md, 0 /* not send */ ); - if (i == 0 || macbuf.mac == NULL - || CRYPTO_memcmp(md, macbuf.mac, mac_size) != 0) - enc_err = 0; - if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH + mac_size) - enc_err = 0; - } - - if (enc_err == 0) { - /* decryption failed, silently discard message */ - rr->length = 0; - s->rrlmethod->reset_packet_length(s->rrl); - goto end; - } - - /* r->length is now just compressed */ - if (s->expand != NULL) { - if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH) { - SSLfatal(s, SSL_AD_RECORD_OVERFLOW, - SSL_R_COMPRESSED_LENGTH_TOO_LONG); - goto end; - } - if (!ssl3_do_uncompress(s, rr)) { - SSLfatal(s, SSL_AD_DECOMPRESSION_FAILURE, SSL_R_BAD_DECOMPRESSION); - goto end; - } - } - - /* use current Max Fragment Length setting if applicable */ - if (s->session != NULL && USE_MAX_FRAGMENT_LENGTH_EXT(s->session)) - max_plain_length = GET_MAX_FRAGMENT_LENGTH(s->session); - - /* send overflow if the plaintext is too long now it has passed MAC */ - if (rr->length > max_plain_length) { - SSLfatal(s, SSL_AD_RECORD_OVERFLOW, SSL_R_DATA_LENGTH_TOO_LONG); - goto end; - } - - rr->off = 0; - /*- - * So at this point the following is true - * ssl->s3.rrec.type is the type of record - * ssl->s3.rrec.length == number of bytes in record - * ssl->s3.rrec.off == offset to first valid byte - * ssl->s3.rrec.data == where to take bytes from, increment - * after use :-). - */ - - /* we have pulled in a full packet so zero things */ - s->rrlmethod->reset_packet_length(s->rrl); - - /* Mark receipt of record. */ - dtls1_record_bitmap_update(s, bitmap); - - ret = 1; - end: - if (macbuf.alloced) - OPENSSL_free(macbuf.mac); - return ret; -} - -/* - * Retrieve a buffered record that belongs to the current epoch, i.e. processed - */ -#define dtls1_get_processed_record(s) \ - dtls1_retrieve_buffered_record((s), \ - &(DTLS_RECORD_LAYER_get_processed_rcds(&s->rlayer))) - -/*- - * Call this to get a new input record. - * It will return <= 0 if more data is needed, normally due to an error - * or non-blocking IO. - * When it finishes, one packet has been decoded and can be found in - * ssl->s3.rrec.type - is the type of record - * ssl->s3.rrec.data - data - * ssl->s3.rrec.length - number of bytes - */ -/* used only by dtls1_read_bytes */ -int dtls1_get_record(SSL_CONNECTION *s) -{ - int ssl_major, ssl_minor; - int rret; - size_t more, n; - SSL3_RECORD *rr; - unsigned char *p = NULL; - unsigned short version; - DTLS1_BITMAP *bitmap; - unsigned int is_next_epoch; - SSL *ssl = SSL_CONNECTION_GET_SSL(s); - - rr = RECORD_LAYER_get_rrec(&s->rlayer); - - again: - /* - * The epoch may have changed. If so, process all the pending records. - * This is a non-blocking operation. - */ - if (!dtls1_process_buffered_records(s)) { - /* SSLfatal() already called */ - return -1; - } - - /* if we're renegotiating, then there may be buffered records */ - if (dtls1_get_processed_record(s)) - return 1; - - /* get something from the wire */ - - /* check if we have the header */ - if ((RECORD_LAYER_get_rstate(&s->rlayer) != SSL_ST_READ_BODY) || - (s->rrlmethod->get_packet_length(s->rrl) < DTLS1_RT_HEADER_LENGTH)) { - rret = HANDLE_RLAYER_RETURN(s, - s->rrlmethod->read_n(s->rrl, DTLS1_RT_HEADER_LENGTH, - SSL3_BUFFER_get_len(s->rrlmethod->get0_rbuf(s->rrl)), 0, 1, &n)); - /* read timeout is handled by dtls1_read_bytes */ - if (rret <= 0) { - /* SSLfatal() already called if appropriate */ - return rret; /* error or non-blocking */ - } - - /* this packet contained a partial record, dump it */ - if (s->rrlmethod->get_packet_length(s->rrl) != DTLS1_RT_HEADER_LENGTH) { - s->rrlmethod->reset_packet_length(s->rrl); - goto again; - } - - RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_BODY); - - p = s->rrlmethod->get0_packet(s->rrl); - - if (s->msg_callback) - s->msg_callback(0, 0, SSL3_RT_HEADER, p, DTLS1_RT_HEADER_LENGTH, - ssl, s->msg_callback_arg); - - /* Pull apart the header into the DTLS1_RECORD */ - rr->type = *(p++); - ssl_major = *(p++); - ssl_minor = *(p++); - version = (ssl_major << 8) | ssl_minor; - - /* sequence number is 64 bits, with top 2 bytes = epoch */ - n2s(p, rr->epoch); - - memcpy(&(RECORD_LAYER_get_read_sequence(&s->rlayer)[2]), p, 6); - p += 6; - - n2s(p, rr->length); - rr->read = 0; - - /* - * Lets check the version. We tolerate alerts that don't have the exact - * version number (e.g. because of protocol version errors) - */ - if (!s->first_packet && rr->type != SSL3_RT_ALERT) { - if (version != s->version) { - /* unexpected version, silently discard */ - rr->length = 0; - rr->read = 1; - s->rrlmethod->reset_packet_length(s->rrl); - goto again; - } - } - - if ((version & 0xff00) != (s->version & 0xff00)) { - /* wrong version, silently discard record */ - rr->length = 0; - rr->read = 1; - s->rrlmethod->reset_packet_length(s->rrl); - goto again; - } - - if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) { - /* record too long, silently discard it */ - rr->length = 0; - rr->read = 1; - s->rrlmethod->reset_packet_length(s->rrl); - goto again; - } - - /* If received packet overflows own-client Max Fragment Length setting */ - if (s->session != NULL && USE_MAX_FRAGMENT_LENGTH_EXT(s->session) - && rr->length > GET_MAX_FRAGMENT_LENGTH(s->session) + SSL3_RT_MAX_ENCRYPTED_OVERHEAD) { - /* record too long, silently discard it */ - rr->length = 0; - rr->read = 1; - s->rrlmethod->reset_packet_length(s->rrl); - goto again; - } - - /* now s->rlayer.rstate == SSL_ST_READ_BODY */ - } - - /* s->rlayer.rstate == SSL_ST_READ_BODY, get and decode the data */ - - if (rr->length > - s->rrlmethod->get_packet_length(s->rrl) - DTLS1_RT_HEADER_LENGTH) { - /* now s->rlayer.packet_length == DTLS1_RT_HEADER_LENGTH */ - more = rr->length; - rret = HANDLE_RLAYER_RETURN(s, - s->rrlmethod->read_n(s->rrl, more, more, 1, 1, &n)); - /* this packet contained a partial record, dump it */ - if (rret <= 0 || n != more) { - if (ossl_statem_in_error(s)) { - /* read_n() called SSLfatal() */ - return -1; - } - rr->length = 0; - rr->read = 1; - s->rrlmethod->reset_packet_length(s->rrl); - goto again; - } - - /* - * now n == rr->length, and s->rlayer.packet_length == - * DTLS1_RT_HEADER_LENGTH + rr->length - */ - } - /* set state for later operations */ - RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_HEADER); - - /* match epochs. NULL means the packet is dropped on the floor */ - bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch); - if (bitmap == NULL) { - rr->length = 0; - s->rrlmethod->reset_packet_length(s->rrl); /* dump this record */ - goto again; /* get another record */ - } -#ifndef OPENSSL_NO_SCTP - /* Only do replay check if no SCTP bio */ - if (!BIO_dgram_is_sctp(SSL_get_rbio(ssl))) { -#endif - /* Check whether this is a repeat, or aged record. */ - if (!dtls1_record_replay_check(s, bitmap)) { - rr->length = 0; - rr->read = 1; - s->rrlmethod->reset_packet_length(s->rrl); /* dump this record */ - goto again; /* get another record */ - } -#ifndef OPENSSL_NO_SCTP - } -#endif - - /* just read a 0 length packet */ - if (rr->length == 0) { - rr->read = 1; - goto again; - } - - /* - * If this record is from the next epoch (either HM or ALERT), and a - * handshake is currently in progress, buffer it since it cannot be - * processed at this time. - */ - if (is_next_epoch) { - if ((SSL_in_init(ssl) || ossl_statem_get_in_handshake(s))) { - if (dtls1_buffer_record (s, - &(DTLS_RECORD_LAYER_get_unprocessed_rcds(&s->rlayer)), - rr->seq_num) < 0) { - /* SSLfatal() already called */ - return -1; - } - } - rr->length = 0; - rr->read = 1; - s->rrlmethod->reset_packet_length(s->rrl); - goto again; - } - - if (!dtls1_process_record(s, bitmap)) { - if (ossl_statem_in_error(s)) { - /* dtls1_process_record() called SSLfatal */ - return -1; - } - rr->length = 0; - rr->read = 1; - s->rrlmethod->reset_packet_length(s->rrl); /* dump this record */ - goto again; /* get another record */ - } - - return 1; - -} - -int dtls_buffer_listen_record(SSL_CONNECTION *s, size_t len, unsigned char *seq, - size_t off) -{ - SSL3_RECORD *rr; - - rr = RECORD_LAYER_get_rrec(&s->rlayer); - memset(rr, 0, sizeof(SSL3_RECORD)); - - rr->length = len; - rr->type = SSL3_RT_HANDSHAKE; - memcpy(rr->seq_num, seq, sizeof(rr->seq_num)); - rr->off = off; - - s->rrlmethod->set0_packet(s->rrl, s->rrlmethod->get0_rbuf(s->rrl)->buf, - DTLS1_RT_HEADER_LENGTH + len); - rr->data = s->rrlmethod->get0_packet(s->rrl) + DTLS1_RT_HEADER_LENGTH; - - if (dtls1_buffer_record(s, &(s->rlayer.d->processed_rcds), - SSL3_RECORD_get_seq_num(s->rlayer.rrec)) <= 0) { - /* SSLfatal() already called */ - return 0; - } - - return 1; -} diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index f20b10606f1..9e4d689c23c 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -1791,13 +1791,13 @@ int SSL_has_pending(const SSL *s) /* Check buffered app data if any first */ if (SSL_CONNECTION_IS_DTLS(sc)) { - DTLS1_RECORD_DATA *rdata; + TLS_RECORD *rdata; pitem *item, *iter; iter = pqueue_iterator(sc->rlayer.d->buffered_app_data.q); while ((item = pqueue_next(&iter)) != NULL) { rdata = item->data; - if (rdata->rrec.length > 0) + if (rdata->length > 0) return 1; } } diff --git a/ssl/statem/statem_dtls.c b/ssl/statem/statem_dtls.c index 6068c833c65..e1b6b5790e0 100644 --- a/ssl/statem/statem_dtls.c +++ b/ssl/statem/statem_dtls.c @@ -825,7 +825,7 @@ static int dtls_get_reassembled_message(SSL_CONNECTION *s, int *errtype, * We must have at least frag_len bytes left in the record to be read. * Fragments must not span records. */ - if (frag_len > RECORD_LAYER_get_rrec_length(&s->rlayer)) { + if (frag_len > s->rlayer.tlsrecs[s->rlayer.curr_rec].length) { SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_LENGTH); goto f_err; } diff --git a/test/sslapitest.c b/test/sslapitest.c index f470d91a7be..774728bbc1a 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -1544,6 +1544,7 @@ static int execute_cleanse_plaintext(const SSL_METHOD *smeth, int testresult = 0; void *zbuf; SSL_CONNECTION *serversc; + TLS_RECORD *rr; static unsigned char cbuf[16000]; static unsigned char sbuf[16000]; @@ -1606,24 +1607,11 @@ static int execute_cleanse_plaintext(const SSL_METHOD *smeth, */ if (!TEST_ptr(serversc = SSL_CONNECTION_FROM_SSL_ONLY(serverssl))) goto end; + rr = serversc->rlayer.tlsrecs; - /* - * TODO(RECLAYER): This is temporary until DTLS is converted to use the new - * record layer code. - */ - if (!SSL_is_dtls(serverssl)) { - TLS_RECORD *rr = serversc->rlayer.tlsrecs; - - zbuf = &rr->data[rr->off]; - if (!TEST_int_eq(rr->length, sizeof(cbuf))) - goto end; - } else { - SSL3_RECORD *rr = serversc->rlayer.rrec; - - zbuf = &rr->data[rr->off]; - if (!TEST_int_eq(rr->length, sizeof(cbuf))) - goto end; - } + zbuf = &rr->data[rr->off]; + if (!TEST_int_eq(rr->length, sizeof(cbuf))) + goto end; /* * After SSL_peek() the plaintext must still be stored in the -- 2.47.2