| // Copyright 2005-2016 The OpenSSL Project Authors. All Rights Reserved. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // https://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #include <openssl/ssl.h> | |
| #include <assert.h> | |
| #include <limits.h> | |
| #include <string.h> | |
| #include <algorithm> | |
| #include <openssl/err.h> | |
| #include <openssl/evp.h> | |
| #include <openssl/mem.h> | |
| #include <openssl/rand.h> | |
| #include "../crypto/internal.h" | |
| #include "internal.h" | |
| BSSL_NAMESPACE_BEGIN | |
| // TODO(davidben): 28 comes from the size of IP + UDP header. Is this reasonable | |
| // for these values? Notably, why is kMinMTU a function of the transport | |
| // protocol's overhead rather than, say, what's needed to hold a minimally-sized | |
| // handshake fragment plus protocol overhead. | |
| // kMinMTU is the minimum acceptable MTU value. | |
| static const unsigned int kMinMTU = 256 - 28; | |
| // kDefaultMTU is the default MTU value to use if neither the user nor | |
| // the underlying BIO supplies one. | |
| static const unsigned int kDefaultMTU = 1500 - 28; | |
| // BitRange returns a |uint8_t| with bits |start|, inclusive, to |end|, | |
| // exclusive, set. | |
| static uint8_t BitRange(size_t start, size_t end) { | |
| assert(start <= end && end <= 8); | |
| return static_cast<uint8_t>(~((1u << start) - 1) & ((1u << end) - 1)); | |
| } | |
| // FirstUnmarkedRangeInByte returns the first unmarked range in bits |b|. | |
| static DTLSMessageBitmap::Range FirstUnmarkedRangeInByte(uint8_t b) { | |
| size_t start, end; | |
| for (start = 0; start < 8; start++) { | |
| if ((b & (1u << start)) == 0) { | |
| break; | |
| } | |
| } | |
| for (end = start; end < 8; end++) { | |
| if ((b & (1u << end)) != 0) { | |
| break; | |
| } | |
| } | |
| return DTLSMessageBitmap::Range{start, end}; | |
| } | |
| bool DTLSMessageBitmap::Init(size_t num_bits) { | |
| if (num_bits + 7 < num_bits) { | |
| OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); | |
| return false; | |
| } | |
| size_t num_bytes = (num_bits + 7) / 8; | |
| size_t bits_rounded = num_bytes * 8; | |
| if (!bytes_.Init(num_bytes)) { | |
| return false; | |
| } | |
| MarkRange(num_bits, bits_rounded); | |
| first_unmarked_byte_ = 0; | |
| return true; | |
| } | |
| void DTLSMessageBitmap::MarkRange(size_t start, size_t end) { | |
| assert(start <= end); | |
| // Don't bother touching bytes that have already been marked. | |
| start = std::max(start, first_unmarked_byte_ << 3); | |
| // Clamp everything within range. | |
| start = std::min(start, bytes_.size() << 3); | |
| end = std::min(end, bytes_.size() << 3); | |
| if (start >= end) { | |
| return; | |
| } | |
| if ((start >> 3) == (end >> 3)) { | |
| bytes_[start >> 3] |= BitRange(start & 7, end & 7); | |
| } else { | |
| bytes_[start >> 3] |= BitRange(start & 7, 8); | |
| for (size_t i = (start >> 3) + 1; i < (end >> 3); i++) { | |
| bytes_[i] = 0xff; | |
| } | |
| if ((end & 7) != 0) { | |
| bytes_[end >> 3] |= BitRange(0, end & 7); | |
| } | |
| } | |
| // Maintain the |first_unmarked_byte_| invariant. This work is amortized | |
| // across all |MarkRange| calls. | |
| while (first_unmarked_byte_ < bytes_.size() && | |
| bytes_[first_unmarked_byte_] == 0xff) { | |
| first_unmarked_byte_++; | |
| } | |
| // If the whole message is marked, we no longer need to spend memory on the | |
| // bitmap. | |
| if (first_unmarked_byte_ >= bytes_.size()) { | |
| bytes_.Reset(); | |
| first_unmarked_byte_ = 0; | |
| } | |
| } | |
| DTLSMessageBitmap::Range DTLSMessageBitmap::NextUnmarkedRange( | |
| size_t start) const { | |
| // Don't bother looking at bytes that are known to be fully marked. | |
| start = std::max(start, first_unmarked_byte_ << 3); | |
| size_t idx = start >> 3; | |
| if (idx >= bytes_.size()) { | |
| return Range{0, 0}; | |
| } | |
| // Look at the bits from |start| up to a byte boundary. | |
| uint8_t byte = bytes_[idx] | BitRange(0, start & 7); | |
| if (byte == 0xff) { | |
| // Nothing unmarked at this byte. Keep searching for an unmarked bit. | |
| for (idx = idx + 1; idx < bytes_.size(); idx++) { | |
| if (bytes_[idx] != 0xff) { | |
| byte = bytes_[idx]; | |
| break; | |
| } | |
| } | |
| if (idx >= bytes_.size()) { | |
| return Range{0, 0}; | |
| } | |
| } | |
| Range range = FirstUnmarkedRangeInByte(byte); | |
| assert(!range.empty()); | |
| bool should_extend = range.end == 8; | |
| range.start += idx << 3; | |
| range.end += idx << 3; | |
| if (!should_extend) { | |
| // The range did not end at a byte boundary. We're done. | |
| return range; | |
| } | |
| // Collect all fully unmarked bytes. | |
| for (idx = idx + 1; idx < bytes_.size(); idx++) { | |
| if (bytes_[idx] != 0) { | |
| break; | |
| } | |
| } | |
| range.end = idx << 3; | |
| // Add any bits from the remaining byte, if any. | |
| if (idx < bytes_.size()) { | |
| Range extra = FirstUnmarkedRangeInByte(bytes_[idx]); | |
| if (extra.start == 0) { | |
| range.end += extra.end; | |
| } | |
| } | |
| return range; | |
| } | |
| // Receiving handshake messages. | |
| static UniquePtr<DTLSIncomingMessage> dtls_new_incoming_message( | |
| const struct hm_header_st *msg_hdr) { | |
| ScopedCBB cbb; | |
| UniquePtr<DTLSIncomingMessage> frag = MakeUnique<DTLSIncomingMessage>(); | |
| if (!frag) { | |
| return nullptr; | |
| } | |
| frag->type = msg_hdr->type; | |
| frag->seq = msg_hdr->seq; | |
| // Allocate space for the reassembled message and fill in the header. | |
| if (!frag->data.InitForOverwrite(DTLS1_HM_HEADER_LENGTH + msg_hdr->msg_len)) { | |
| return nullptr; | |
| } | |
| if (!CBB_init_fixed(cbb.get(), frag->data.data(), DTLS1_HM_HEADER_LENGTH) || | |
| !CBB_add_u8(cbb.get(), msg_hdr->type) || | |
| !CBB_add_u24(cbb.get(), msg_hdr->msg_len) || | |
| !CBB_add_u16(cbb.get(), msg_hdr->seq) || | |
| !CBB_add_u24(cbb.get(), 0 /* frag_off */) || | |
| !CBB_add_u24(cbb.get(), msg_hdr->msg_len) || | |
| !CBB_finish(cbb.get(), NULL, NULL)) { | |
| return nullptr; | |
| } | |
| if (!frag->reassembly.Init(msg_hdr->msg_len)) { | |
| return nullptr; | |
| } | |
| return frag; | |
| } | |
| // dtls1_is_current_message_complete returns whether the current handshake | |
| // message is complete. | |
| static bool dtls1_is_current_message_complete(const SSL *ssl) { | |
| size_t idx = ssl->d1->handshake_read_seq % SSL_MAX_HANDSHAKE_FLIGHT; | |
| DTLSIncomingMessage *frag = ssl->d1->incoming_messages[idx].get(); | |
| return frag != nullptr && frag->reassembly.IsComplete(); | |
| } | |
| // dtls1_get_incoming_message returns the incoming message corresponding to | |
| // |msg_hdr|. If none exists, it creates a new one and inserts it in the | |
| // queue. Otherwise, it checks |msg_hdr| is consistent with the existing one. It | |
| // returns NULL on failure. The caller does not take ownership of the result. | |
| static DTLSIncomingMessage *dtls1_get_incoming_message( | |
| SSL *ssl, uint8_t *out_alert, const struct hm_header_st *msg_hdr) { | |
| if (msg_hdr->seq < ssl->d1->handshake_read_seq || | |
| msg_hdr->seq - ssl->d1->handshake_read_seq >= SSL_MAX_HANDSHAKE_FLIGHT) { | |
| *out_alert = SSL_AD_INTERNAL_ERROR; | |
| return NULL; | |
| } | |
| size_t idx = msg_hdr->seq % SSL_MAX_HANDSHAKE_FLIGHT; | |
| DTLSIncomingMessage *frag = ssl->d1->incoming_messages[idx].get(); | |
| if (frag != NULL) { | |
| assert(frag->seq == msg_hdr->seq); | |
| // The new fragment must be compatible with the previous fragments from this | |
| // message. | |
| if (frag->type != msg_hdr->type || // | |
| frag->msg_len() != msg_hdr->msg_len) { | |
| OPENSSL_PUT_ERROR(SSL, SSL_R_FRAGMENT_MISMATCH); | |
| *out_alert = SSL_AD_ILLEGAL_PARAMETER; | |
| return NULL; | |
| } | |
| return frag; | |
| } | |
| // This is the first fragment from this message. | |
| ssl->d1->incoming_messages[idx] = dtls_new_incoming_message(msg_hdr); | |
| if (!ssl->d1->incoming_messages[idx]) { | |
| *out_alert = SSL_AD_INTERNAL_ERROR; | |
| return NULL; | |
| } | |
| return ssl->d1->incoming_messages[idx].get(); | |
| } | |
| bool dtls1_process_handshake_fragments(SSL *ssl, uint8_t *out_alert, | |
| DTLSRecordNumber record_number, | |
| Span<const uint8_t> record) { | |
| bool implicit_ack = false; | |
| bool skipped_fragments = false; | |
| CBS cbs = record; | |
| while (CBS_len(&cbs) > 0) { | |
| // Read a handshake fragment. | |
| struct hm_header_st msg_hdr; | |
| CBS body; | |
| if (!dtls1_parse_fragment(&cbs, &msg_hdr, &body)) { | |
| OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HANDSHAKE_RECORD); | |
| *out_alert = SSL_AD_DECODE_ERROR; | |
| return false; | |
| } | |
| const size_t frag_off = msg_hdr.frag_off; | |
| const size_t frag_len = msg_hdr.frag_len; | |
| const size_t msg_len = msg_hdr.msg_len; | |
| if (frag_off > msg_len || frag_len > msg_len - frag_off) { | |
| OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HANDSHAKE_RECORD); | |
| *out_alert = SSL_AD_ILLEGAL_PARAMETER; | |
| return false; | |
| } | |
| if (msg_hdr.seq < ssl->d1->handshake_read_seq || | |
| ssl->d1->handshake_read_overflow) { | |
| // Ignore fragments from the past. This is a retransmit of data we already | |
| // received. | |
| // | |
| // TODO(crbug.com/42290594): Use this to drive retransmits. | |
| continue; | |
| } | |
| if (record_number.epoch() != ssl->d1->read_epoch.epoch || | |
| ssl->d1->next_read_epoch != nullptr) { | |
| // New messages can only arrive in the latest epoch. This can fail if the | |
| // record came from |prev_read_epoch|, or if it came from |read_epoch| but | |
| // |next_read_epoch| exists. (It cannot come from |next_read_epoch| | |
| // because |next_read_epoch| becomes |read_epoch| once it receives a | |
| // record.) | |
| OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESS_HANDSHAKE_DATA); | |
| *out_alert = SSL_AD_UNEXPECTED_MESSAGE; | |
| return false; | |
| } | |
| if (msg_len > ssl_max_handshake_message_len(ssl)) { | |
| OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE); | |
| *out_alert = SSL_AD_ILLEGAL_PARAMETER; | |
| return false; | |
| } | |
| if (SSL_in_init(ssl) && ssl_has_final_version(ssl) && | |
| ssl_protocol_version(ssl) >= TLS1_3_VERSION) { | |
| // During the handshake, if we receive any portion of the next flight, the | |
| // peer must have received our most recent flight. In DTLS 1.3, this is an | |
| // implicit ACK. See RFC 9147, Section 7.1. | |
| // | |
| // This only applies during the handshake. After the handshake, the next | |
| // message may be part of a post-handshake transaction. It also does not | |
| // apply immediately after the handshake. As a client, receiving a | |
| // KeyUpdate or NewSessionTicket does not imply the server has received | |
| // our Finished. The server may have sent those messages in half-RTT. | |
| implicit_ack = true; | |
| } | |
| if (msg_hdr.seq - ssl->d1->handshake_read_seq > SSL_MAX_HANDSHAKE_FLIGHT) { | |
| // Ignore fragments too far in the future. | |
| skipped_fragments = true; | |
| continue; | |
| } | |
| DTLSIncomingMessage *frag = | |
| dtls1_get_incoming_message(ssl, out_alert, &msg_hdr); | |
| if (frag == nullptr) { | |
| return false; | |
| } | |
| assert(frag->msg_len() == msg_len); | |
| if (frag->reassembly.IsComplete()) { | |
| // The message is already assembled. | |
| continue; | |
| } | |
| assert(msg_len > 0); | |
| // Copy the body into the fragment. | |
| Span<uint8_t> dest = frag->msg().subspan(frag_off, CBS_len(&body)); | |
| OPENSSL_memcpy(dest.data(), CBS_data(&body), CBS_len(&body)); | |
| frag->reassembly.MarkRange(frag_off, frag_off + frag_len); | |
| } | |
| if (implicit_ack) { | |
| dtls1_stop_timer(ssl); | |
| dtls_clear_outgoing_messages(ssl); | |
| } | |
| if (!skipped_fragments) { | |
| ssl->d1->records_to_ack.PushBack(record_number); | |
| if (ssl_has_final_version(ssl) && | |
| ssl_protocol_version(ssl) >= TLS1_3_VERSION && | |
| !ssl->d1->ack_timer.IsSet() && !ssl->d1->sending_ack) { | |
| // Schedule sending an ACK. The delay serves several purposes: | |
| // - If there are more records to come, we send only one ACK. | |
| // - If there are more records to come and the flight is now complete, we | |
| // will send the reply (which implicitly ACKs the previous flight) and | |
| // cancel the timer. | |
| // - If there are more records to come, the flight is now complete, but | |
| // generating the response is delayed (e.g. a slow, async private key), | |
| // the timer will fire and we send an ACK anyway. | |
| OPENSSL_timeval now = ssl_ctx_get_current_time(ssl->ctx.get()); | |
| ssl->d1->ack_timer.StartMicroseconds( | |
| now, uint64_t{ssl->d1->timeout_duration_ms} * 1000 / 4); | |
| } | |
| } | |
| return true; | |
| } | |
| ssl_open_record_t dtls1_open_handshake(SSL *ssl, size_t *out_consumed, | |
| uint8_t *out_alert, Span<uint8_t> in) { | |
| uint8_t type; | |
| DTLSRecordNumber record_number; | |
| Span<uint8_t> record; | |
| auto ret = dtls_open_record(ssl, &type, &record_number, &record, out_consumed, | |
| out_alert, in); | |
| if (ret != ssl_open_record_success) { | |
| return ret; | |
| } | |
| switch (type) { | |
| case SSL3_RT_APPLICATION_DATA: | |
| // In DTLS 1.2, out-of-order application data may be received between | |
| // ChangeCipherSpec and Finished. Discard it. | |
| return ssl_open_record_discard; | |
| case SSL3_RT_CHANGE_CIPHER_SPEC: | |
| if (record.size() != 1u || record[0] != SSL3_MT_CCS) { | |
| OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC); | |
| *out_alert = SSL_AD_ILLEGAL_PARAMETER; | |
| return ssl_open_record_error; | |
| } | |
| // We do not support renegotiation, so encrypted ChangeCipherSpec records | |
| // are illegal. | |
| if (record_number.epoch() != 0) { | |
| OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD); | |
| *out_alert = SSL_AD_UNEXPECTED_MESSAGE; | |
| return ssl_open_record_error; | |
| } | |
| // Ignore ChangeCipherSpec from a previous epoch. | |
| if (record_number.epoch() != ssl->d1->read_epoch.epoch) { | |
| return ssl_open_record_discard; | |
| } | |
| // Flag the ChangeCipherSpec for later. | |
| // TODO(crbug.com/42290594): Should we reject this in DTLS 1.3? | |
| ssl->d1->has_change_cipher_spec = true; | |
| ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_CHANGE_CIPHER_SPEC, | |
| record); | |
| return ssl_open_record_success; | |
| case SSL3_RT_ACK: | |
| return dtls1_process_ack(ssl, out_alert, record_number, record); | |
| case SSL3_RT_HANDSHAKE: | |
| if (!dtls1_process_handshake_fragments(ssl, out_alert, record_number, | |
| record)) { | |
| return ssl_open_record_error; | |
| } | |
| return ssl_open_record_success; | |
| default: | |
| OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD); | |
| *out_alert = SSL_AD_UNEXPECTED_MESSAGE; | |
| return ssl_open_record_error; | |
| } | |
| } | |
| bool dtls1_get_message(const SSL *ssl, SSLMessage *out) { | |
| if (!dtls1_is_current_message_complete(ssl)) { | |
| return false; | |
| } | |
| size_t idx = ssl->d1->handshake_read_seq % SSL_MAX_HANDSHAKE_FLIGHT; | |
| const DTLSIncomingMessage *frag = ssl->d1->incoming_messages[idx].get(); | |
| out->type = frag->type; | |
| out->raw = CBS(frag->data); | |
| out->body = CBS(frag->msg()); | |
| out->is_v2_hello = false; | |
| if (!ssl->s3->has_message) { | |
| ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HANDSHAKE, out->raw); | |
| ssl->s3->has_message = true; | |
| } | |
| return true; | |
| } | |
| void dtls1_next_message(SSL *ssl) { | |
| assert(ssl->s3->has_message); | |
| assert(dtls1_is_current_message_complete(ssl)); | |
| size_t index = ssl->d1->handshake_read_seq % SSL_MAX_HANDSHAKE_FLIGHT; | |
| ssl->d1->incoming_messages[index].reset(); | |
| ssl->d1->handshake_read_seq++; | |
| if (ssl->d1->handshake_read_seq == 0) { | |
| ssl->d1->handshake_read_overflow = true; | |
| } | |
| ssl->s3->has_message = false; | |
| // If we previously sent a flight, mark it as having a reply, so | |
| // |on_handshake_complete| can manage post-handshake retransmission. | |
| if (ssl->d1->outgoing_messages_complete) { | |
| ssl->d1->flight_has_reply = true; | |
| } | |
| } | |
| bool dtls_has_unprocessed_handshake_data(const SSL *ssl) { | |
| size_t current = ssl->d1->handshake_read_seq % SSL_MAX_HANDSHAKE_FLIGHT; | |
| for (size_t i = 0; i < SSL_MAX_HANDSHAKE_FLIGHT; i++) { | |
| // Skip the current message. | |
| if (ssl->s3->has_message && i == current) { | |
| assert(dtls1_is_current_message_complete(ssl)); | |
| continue; | |
| } | |
| if (ssl->d1->incoming_messages[i] != nullptr) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| bool dtls1_parse_fragment(CBS *cbs, struct hm_header_st *out_hdr, | |
| CBS *out_body) { | |
| OPENSSL_memset(out_hdr, 0x00, sizeof(struct hm_header_st)); | |
| if (!CBS_get_u8(cbs, &out_hdr->type) || | |
| !CBS_get_u24(cbs, &out_hdr->msg_len) || | |
| !CBS_get_u16(cbs, &out_hdr->seq) || | |
| !CBS_get_u24(cbs, &out_hdr->frag_off) || | |
| !CBS_get_u24(cbs, &out_hdr->frag_len) || | |
| !CBS_get_bytes(cbs, out_body, out_hdr->frag_len)) { | |
| return false; | |
| } | |
| return true; | |
| } | |
| ssl_open_record_t dtls1_open_change_cipher_spec(SSL *ssl, size_t *out_consumed, | |
| uint8_t *out_alert, | |
| Span<uint8_t> in) { | |
| if (!ssl->d1->has_change_cipher_spec) { | |
| // dtls1_open_handshake processes both handshake and ChangeCipherSpec. | |
| auto ret = dtls1_open_handshake(ssl, out_consumed, out_alert, in); | |
| if (ret != ssl_open_record_success) { | |
| return ret; | |
| } | |
| } | |
| if (ssl->d1->has_change_cipher_spec) { | |
| ssl->d1->has_change_cipher_spec = false; | |
| return ssl_open_record_success; | |
| } | |
| return ssl_open_record_discard; | |
| } | |
| // Sending handshake messages. | |
| void dtls_clear_outgoing_messages(SSL *ssl) { | |
| ssl->d1->outgoing_messages.clear(); | |
| ssl->d1->sent_records = nullptr; | |
| ssl->d1->outgoing_written = 0; | |
| ssl->d1->outgoing_offset = 0; | |
| ssl->d1->outgoing_messages_complete = false; | |
| ssl->d1->flight_has_reply = false; | |
| ssl->d1->sending_flight = false; | |
| dtls_clear_unused_write_epochs(ssl); | |
| } | |
| void dtls_clear_unused_write_epochs(SSL *ssl) { | |
| ssl->d1->extra_write_epochs.EraseIf( | |
| [ssl](const UniquePtr<DTLSWriteEpoch> &write_epoch) -> bool { | |
| // Non-current epochs may be discarded once there are no incomplete | |
| // outgoing messages that reference them. | |
| // | |
| // TODO(crbug.com/42290594): Epoch 1 (0-RTT) should be retained until | |
| // epoch 3 (app data) is available. | |
| for (const auto &msg : ssl->d1->outgoing_messages) { | |
| if (msg.epoch == write_epoch->epoch() && !msg.IsFullyAcked()) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| }); | |
| } | |
| bool dtls1_init_message(const SSL *ssl, CBB *cbb, CBB *body, uint8_t type) { | |
| // Pick a modest size hint to save most of the |realloc| calls. | |
| if (!CBB_init(cbb, 64) || // | |
| !CBB_add_u8(cbb, type) || // | |
| !CBB_add_u24(cbb, 0 /* length (filled in later) */) || // | |
| !CBB_add_u16(cbb, ssl->d1->handshake_write_seq) || // | |
| !CBB_add_u24(cbb, 0 /* offset */) || // | |
| !CBB_add_u24_length_prefixed(cbb, body)) { | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool dtls1_finish_message(const SSL *ssl, CBB *cbb, Array<uint8_t> *out_msg) { | |
| if (!CBBFinishArray(cbb, out_msg) || | |
| out_msg->size() < DTLS1_HM_HEADER_LENGTH) { | |
| OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); | |
| return false; | |
| } | |
| // Fix up the header. Copy the fragment length into the total message | |
| // length. | |
| OPENSSL_memcpy(out_msg->data() + 1, | |
| out_msg->data() + DTLS1_HM_HEADER_LENGTH - 3, 3); | |
| return true; | |
| } | |
| // add_outgoing adds a new handshake message or ChangeCipherSpec to the current | |
| // outgoing flight. It returns true on success and false on error. | |
| static bool add_outgoing(SSL *ssl, bool is_ccs, Array<uint8_t> data) { | |
| if (ssl->d1->outgoing_messages_complete) { | |
| // If we've begun writing a new flight, we received the peer flight. Discard | |
| // the timer and the our flight. | |
| dtls1_stop_timer(ssl); | |
| dtls_clear_outgoing_messages(ssl); | |
| } | |
| if (!is_ccs) { | |
| if (ssl->d1->handshake_write_overflow) { | |
| OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); | |
| return false; | |
| } | |
| // TODO(svaldez): Move this up a layer to fix abstraction for SSLTranscript | |
| // on hs. | |
| if (ssl->s3->hs != NULL && !ssl->s3->hs->transcript.Update(data)) { | |
| OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); | |
| return false; | |
| } | |
| ssl->d1->handshake_write_seq++; | |
| if (ssl->d1->handshake_write_seq == 0) { | |
| ssl->d1->handshake_write_overflow = true; | |
| } | |
| } | |
| DTLSOutgoingMessage msg; | |
| msg.data = std::move(data); | |
| msg.epoch = ssl->d1->write_epoch.epoch(); | |
| msg.is_ccs = is_ccs; | |
| // Zero-length messages need 1 bit to track whether the peer has received the | |
| // message header. (Normally the message header is implicitly received when | |
| // any fragment of the message is received at all.) | |
| if (!is_ccs && !msg.acked.Init(std::max(msg.msg_len(), size_t{1}))) { | |
| return false; | |
| } | |
| // This should not fail if |SSL_MAX_HANDSHAKE_FLIGHT| was sized correctly. | |
| // | |
| // TODO(crbug.com/42290594): This can currently fail in DTLS 1.3. The caller | |
| // can configure how many tickets to send, up to kMaxTickets. Additionally, if | |
| // we send 0.5-RTT tickets in 0-RTT, we may even have tickets queued up with | |
| // the server flight. | |
| if (!ssl->d1->outgoing_messages.TryPushBack(std::move(msg))) { | |
| assert(false); | |
| OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool dtls1_add_message(SSL *ssl, Array<uint8_t> data) { | |
| return add_outgoing(ssl, false /* handshake */, std::move(data)); | |
| } | |
| bool dtls1_add_change_cipher_spec(SSL *ssl) { | |
| // DTLS 1.3 disables compatibility mode, which means that DTLS 1.3 never sends | |
| // a ChangeCipherSpec message. | |
| if (ssl_protocol_version(ssl) > TLS1_2_VERSION) { | |
| return true; | |
| } | |
| return add_outgoing(ssl, true /* ChangeCipherSpec */, Array<uint8_t>()); | |
| } | |
| // dtls1_update_mtu updates the current MTU from the BIO, ensuring it is above | |
| // the minimum. | |
| static void dtls1_update_mtu(SSL *ssl) { | |
| // TODO(davidben): No consumer implements |BIO_CTRL_DGRAM_SET_MTU| and the | |
| // only |BIO_CTRL_DGRAM_QUERY_MTU| implementation could use | |
| // |SSL_set_mtu|. Does this need to be so complex? | |
| if (ssl->d1->mtu < dtls1_min_mtu() && | |
| !(SSL_get_options(ssl) & SSL_OP_NO_QUERY_MTU)) { | |
| long mtu = BIO_ctrl(ssl->wbio.get(), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); | |
| if (mtu >= 0 && mtu <= (1 << 30) && (unsigned)mtu >= dtls1_min_mtu()) { | |
| ssl->d1->mtu = (unsigned)mtu; | |
| } else { | |
| ssl->d1->mtu = kDefaultMTU; | |
| BIO_ctrl(ssl->wbio.get(), BIO_CTRL_DGRAM_SET_MTU, ssl->d1->mtu, NULL); | |
| } | |
| } | |
| // The MTU should be above the minimum now. | |
| assert(ssl->d1->mtu >= dtls1_min_mtu()); | |
| } | |
| enum seal_result_t { | |
| seal_error, | |
| seal_continue, | |
| seal_flush, | |
| }; | |
| // seal_next_record seals one record's worth of messages to |out| and advances | |
| // |ssl|'s internal state past the data that was sealed. If progress was made, | |
| // it returns |seal_flush| or |seal_continue| and sets | |
| // |*out_len| to the number of bytes written. | |
| // | |
| // If the function stopped because the next message could not be combined into | |
| // this record, it returns |seal_continue| and the caller should loop again. | |
| // Otherwise, it returns |seal_flush| and the packet is complete (either because | |
| // there are no more messages or the packet is full). | |
| static seal_result_t seal_next_record(SSL *ssl, Span<uint8_t> out, | |
| size_t *out_len) { | |
| *out_len = 0; | |
| // Skip any fully acked messages. | |
| while (ssl->d1->outgoing_written < ssl->d1->outgoing_messages.size() && | |
| ssl->d1->outgoing_messages[ssl->d1->outgoing_written].IsFullyAcked()) { | |
| ssl->d1->outgoing_offset = 0; | |
| ssl->d1->outgoing_written++; | |
| } | |
| // There was nothing left to write. | |
| if (ssl->d1->outgoing_written >= ssl->d1->outgoing_messages.size()) { | |
| return seal_flush; | |
| } | |
| const auto &first_msg = ssl->d1->outgoing_messages[ssl->d1->outgoing_written]; | |
| size_t prefix_len = dtls_seal_prefix_len(ssl, first_msg.epoch); | |
| size_t max_in_len = dtls_seal_max_input_len(ssl, first_msg.epoch, out.size()); | |
| if (max_in_len == 0) { | |
| // There is no room for a single record. | |
| return seal_flush; | |
| } | |
| if (first_msg.is_ccs) { | |
| static const uint8_t kChangeCipherSpec[1] = {SSL3_MT_CCS}; | |
| DTLSRecordNumber record_number; | |
| if (!dtls_seal_record(ssl, &record_number, out.data(), out_len, out.size(), | |
| SSL3_RT_CHANGE_CIPHER_SPEC, kChangeCipherSpec, | |
| sizeof(kChangeCipherSpec), first_msg.epoch)) { | |
| return seal_error; | |
| } | |
| ssl_do_msg_callback(ssl, /*is_write=*/1, SSL3_RT_CHANGE_CIPHER_SPEC, | |
| kChangeCipherSpec); | |
| ssl->d1->outgoing_offset = 0; | |
| ssl->d1->outgoing_written++; | |
| return seal_continue; | |
| } | |
| // TODO(crbug.com/374991962): For now, only send one message per record in | |
| // epoch 0. Sending multiple is allowed and more efficient, but breaks | |
| // b/378742138. | |
| const bool allow_multiple_messages = first_msg.epoch != 0; | |
| // Pack as many handshake fragments into one record as we can. We stage the | |
| // fragments in the output buffer, to be sealed in-place. | |
| bool should_continue = false; | |
| Span<uint8_t> fragments = out.subspan(prefix_len, max_in_len); | |
| CBB cbb; | |
| CBB_init_fixed(&cbb, fragments.data(), fragments.size()); | |
| DTLSSentRecord sent_record; | |
| sent_record.first_msg = ssl->d1->outgoing_written; | |
| sent_record.first_msg_start = ssl->d1->outgoing_offset; | |
| while (ssl->d1->outgoing_written < ssl->d1->outgoing_messages.size()) { | |
| const auto &msg = ssl->d1->outgoing_messages[ssl->d1->outgoing_written]; | |
| if (msg.epoch != first_msg.epoch || msg.is_ccs) { | |
| // We can only pack messages if the epoch matches. There may be more room | |
| // in the packet, so tell the caller to keep going. | |
| should_continue = true; | |
| break; | |
| } | |
| // Decode |msg|'s header. | |
| CBS cbs(msg.data), body_cbs; | |
| struct hm_header_st hdr; | |
| if (!dtls1_parse_fragment(&cbs, &hdr, &body_cbs) || // | |
| hdr.frag_off != 0 || // | |
| hdr.frag_len != CBS_len(&body_cbs) || // | |
| hdr.msg_len != CBS_len(&body_cbs) || // | |
| CBS_len(&cbs) != 0) { | |
| OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); | |
| return seal_error; | |
| } | |
| // Iterate over every un-acked range in the message, if any. | |
| Span<const uint8_t> body = body_cbs; | |
| for (;;) { | |
| auto range = msg.acked.NextUnmarkedRange(ssl->d1->outgoing_offset); | |
| if (range.empty()) { | |
| // Advance to the next message. | |
| ssl->d1->outgoing_offset = 0; | |
| ssl->d1->outgoing_written++; | |
| break; | |
| } | |
| // Determine how much progress can be made (minimum one byte of progress). | |
| size_t capacity = fragments.size() - CBB_len(&cbb); | |
| if (capacity < DTLS1_HM_HEADER_LENGTH + 1) { | |
| goto packet_full; | |
| } | |
| size_t todo = std::min(range.size(), capacity - DTLS1_HM_HEADER_LENGTH); | |
| // Empty messages are special-cased in ACK tracking. We act as if they | |
| // have one byte, but in reality that byte is tracking the header. | |
| Span<const uint8_t> frag; | |
| if (!body.empty()) { | |
| frag = body.subspan(range.start, todo); | |
| } | |
| // Assemble the fragment. | |
| size_t frag_start = CBB_len(&cbb); | |
| CBB child; | |
| if (!CBB_add_u8(&cbb, hdr.type) || // | |
| !CBB_add_u24(&cbb, hdr.msg_len) || // | |
| !CBB_add_u16(&cbb, hdr.seq) || // | |
| !CBB_add_u24(&cbb, range.start) || // | |
| !CBB_add_u24_length_prefixed(&cbb, &child) || // | |
| !CBB_add_bytes(&child, frag.data(), frag.size()) || // | |
| !CBB_flush(&cbb)) { | |
| OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); | |
| return seal_error; | |
| } | |
| size_t frag_end = CBB_len(&cbb); | |
| // TODO(davidben): It is odd that, on output, we inform the caller of | |
| // retransmits and individual fragments, but on input we only inform the | |
| // caller of complete messages. | |
| ssl_do_msg_callback(ssl, /*is_write=*/1, SSL3_RT_HANDSHAKE, | |
| fragments.subspan(frag_start, frag_end - frag_start)); | |
| ssl->d1->outgoing_offset = range.start + todo; | |
| if (todo < range.size()) { | |
| // The packet was the limiting factor. | |
| goto packet_full; | |
| } | |
| } | |
| if (!allow_multiple_messages) { | |
| should_continue = true; | |
| break; | |
| } | |
| } | |
| packet_full: | |
| sent_record.last_msg = ssl->d1->outgoing_written; | |
| sent_record.last_msg_end = ssl->d1->outgoing_offset; | |
| // We could not fit anything. Don't try to make a record. | |
| if (CBB_len(&cbb) == 0) { | |
| assert(!should_continue); | |
| return seal_flush; | |
| } | |
| if (!dtls_seal_record(ssl, &sent_record.number, out.data(), out_len, | |
| out.size(), SSL3_RT_HANDSHAKE, CBB_data(&cbb), | |
| CBB_len(&cbb), first_msg.epoch)) { | |
| return seal_error; | |
| } | |
| // If DTLS 1.3 (or if the version is not yet known and it may be DTLS 1.3), | |
| // save the record number to match against ACKs later. | |
| if (ssl->s3->version == 0 || ssl_protocol_version(ssl) >= TLS1_3_VERSION) { | |
| if (ssl->d1->sent_records == nullptr) { | |
| ssl->d1->sent_records = | |
| MakeUnique<MRUQueue<DTLSSentRecord, DTLS_MAX_ACK_BUFFER>>(); | |
| if (ssl->d1->sent_records == nullptr) { | |
| return seal_error; | |
| } | |
| } | |
| ssl->d1->sent_records->PushBack(sent_record); | |
| } | |
| return should_continue ? seal_continue : seal_flush; | |
| } | |
| // seal_next_packet writes as much of the next flight as possible to |out| and | |
| // advances |ssl->d1->outgoing_written| and |ssl->d1->outgoing_offset| as | |
| // appropriate. | |
| static bool seal_next_packet(SSL *ssl, Span<uint8_t> out, size_t *out_len) { | |
| size_t total = 0; | |
| for (;;) { | |
| size_t len; | |
| seal_result_t ret = seal_next_record(ssl, out, &len); | |
| switch (ret) { | |
| case seal_error: | |
| return false; | |
| case seal_flush: | |
| case seal_continue: | |
| out = out.subspan(len); | |
| total += len; | |
| break; | |
| } | |
| if (ret == seal_flush) { | |
| break; | |
| } | |
| } | |
| *out_len = total; | |
| return true; | |
| } | |
| static int send_flight(SSL *ssl) { | |
| if (ssl->s3->write_shutdown != ssl_shutdown_none) { | |
| OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN); | |
| return -1; | |
| } | |
| if (ssl->wbio == nullptr) { | |
| OPENSSL_PUT_ERROR(SSL, SSL_R_BIO_NOT_SET); | |
| return -1; | |
| } | |
| if (ssl->d1->num_timeouts > DTLS1_MAX_TIMEOUTS) { | |
| OPENSSL_PUT_ERROR(SSL, SSL_R_READ_TIMEOUT_EXPIRED); | |
| return -1; | |
| } | |
| dtls1_update_mtu(ssl); | |
| Array<uint8_t> packet; | |
| if (!packet.InitForOverwrite(ssl->d1->mtu)) { | |
| return -1; | |
| } | |
| while (ssl->d1->outgoing_written < ssl->d1->outgoing_messages.size()) { | |
| uint8_t old_written = ssl->d1->outgoing_written; | |
| uint32_t old_offset = ssl->d1->outgoing_offset; | |
| size_t packet_len; | |
| if (!seal_next_packet(ssl, Span(packet), &packet_len)) { | |
| return -1; | |
| } | |
| if (packet_len == 0 && | |
| ssl->d1->outgoing_written < ssl->d1->outgoing_messages.size()) { | |
| // We made no progress with the packet size available, but did not reach | |
| // the end. | |
| OPENSSL_PUT_ERROR(SSL, SSL_R_MTU_TOO_SMALL); | |
| return false; | |
| } | |
| if (packet_len != 0) { | |
| int bio_ret = BIO_write(ssl->wbio.get(), packet.data(), packet_len); | |
| if (bio_ret <= 0) { | |
| // Retry this packet the next time around. | |
| ssl->d1->outgoing_written = old_written; | |
| ssl->d1->outgoing_offset = old_offset; | |
| ssl->s3->rwstate = SSL_ERROR_WANT_WRITE; | |
| return bio_ret; | |
| } | |
| } | |
| } | |
| if (BIO_flush(ssl->wbio.get()) <= 0) { | |
| ssl->s3->rwstate = SSL_ERROR_WANT_WRITE; | |
| return -1; | |
| } | |
| return 1; | |
| } | |
| void dtls1_finish_flight(SSL *ssl) { | |
| if (ssl->d1->outgoing_messages.empty() || | |
| ssl->d1->outgoing_messages_complete) { | |
| return; // Nothing to do. | |
| } | |
| if (ssl->d1->outgoing_messages[0].epoch <= 2) { | |
| // DTLS 1.3 handshake messages (epoch 2 and below) implicitly ACK the | |
| // previous flight, so there is no need to ACK previous records. This | |
| // clears the ACK buffer slightly earlier than the specification suggests. | |
| // See the discussion in | |
| // https://mailarchive.ietf.org/arch/msg/tls/kjJnquJOVaWxu5hUCmNzB35eqY0/ | |
| ssl->d1->records_to_ack.Clear(); | |
| ssl->d1->ack_timer.Stop(); | |
| ssl->d1->sending_ack = false; | |
| } | |
| ssl->d1->outgoing_messages_complete = true; | |
| ssl->d1->sending_flight = true; | |
| // Stop retransmitting the previous flight. In DTLS 1.3, we'll have stopped | |
| // the timer already, but DTLS 1.2 keeps it running until the next flight is | |
| // ready. | |
| dtls1_stop_timer(ssl); | |
| } | |
| void dtls1_schedule_ack(SSL *ssl) { | |
| ssl->d1->ack_timer.Stop(); | |
| ssl->d1->sending_ack = !ssl->d1->records_to_ack.empty(); | |
| } | |
| static int send_ack(SSL *ssl) { | |
| assert(ssl_protocol_version(ssl) >= TLS1_3_VERSION); | |
| // Ensure we don't send so many ACKs that we overflow the MTU. There is a | |
| // 2-byte length prefix and each ACK is 16 bytes. | |
| dtls1_update_mtu(ssl); | |
| size_t max_plaintext = | |
| dtls_seal_max_input_len(ssl, ssl->d1->write_epoch.epoch(), ssl->d1->mtu); | |
| if (max_plaintext < 2 + 16) { | |
| OPENSSL_PUT_ERROR(SSL, SSL_R_MTU_TOO_SMALL); // No room for even one ACK. | |
| return -1; | |
| } | |
| size_t num_acks = | |
| std::min((max_plaintext - 2) / 16, ssl->d1->records_to_ack.size()); | |
| // Assemble the ACK. RFC 9147 says to sort ACKs numerically. It is unclear if | |
| // other implementations do this, but go ahead and sort for now. See | |
| // https://mailarchive.ietf.org/arch/msg/tls/kjJnquJOVaWxu5hUCmNzB35eqY0/. | |
| // Remove this if rfc9147bis removes this requirement. | |
| InplaceVector<DTLSRecordNumber, DTLS_MAX_ACK_BUFFER> sorted; | |
| for (size_t i = ssl->d1->records_to_ack.size() - num_acks; | |
| i < ssl->d1->records_to_ack.size(); i++) { | |
| sorted.PushBack(ssl->d1->records_to_ack[i]); | |
| } | |
| std::sort(sorted.begin(), sorted.end()); | |
| uint8_t buf[2 + 16 * DTLS_MAX_ACK_BUFFER]; | |
| CBB cbb, child; | |
| CBB_init_fixed(&cbb, buf, sizeof(buf)); | |
| BSSL_CHECK(CBB_add_u16_length_prefixed(&cbb, &child)); | |
| for (const auto &number : sorted) { | |
| BSSL_CHECK(CBB_add_u64(&child, number.epoch())); | |
| BSSL_CHECK(CBB_add_u64(&child, number.sequence())); | |
| } | |
| BSSL_CHECK(CBB_flush(&cbb)); | |
| // Encrypt it. | |
| uint8_t record[DTLS1_3_RECORD_HEADER_WRITE_LENGTH + sizeof(buf) + | |
| 1 /* record type */ + EVP_AEAD_MAX_OVERHEAD]; | |
| size_t record_len; | |
| DTLSRecordNumber record_number; | |
| if (!dtls_seal_record(ssl, &record_number, record, &record_len, | |
| sizeof(record), SSL3_RT_ACK, CBB_data(&cbb), | |
| CBB_len(&cbb), ssl->d1->write_epoch.epoch())) { | |
| return -1; | |
| } | |
| ssl_do_msg_callback(ssl, /*is_write=*/1, SSL3_RT_ACK, | |
| Span(CBB_data(&cbb), CBB_len(&cbb))); | |
| int bio_ret = | |
| BIO_write(ssl->wbio.get(), record, static_cast<int>(record_len)); | |
| if (bio_ret <= 0) { | |
| ssl->s3->rwstate = SSL_ERROR_WANT_WRITE; | |
| return bio_ret; | |
| } | |
| if (BIO_flush(ssl->wbio.get()) <= 0) { | |
| ssl->s3->rwstate = SSL_ERROR_WANT_WRITE; | |
| return -1; | |
| } | |
| return 1; | |
| } | |
| int dtls1_flush(SSL *ssl) { | |
| // Send the pending ACK, if any. | |
| if (ssl->d1->sending_ack) { | |
| int ret = send_ack(ssl); | |
| if (ret <= 0) { | |
| return ret; | |
| } | |
| ssl->d1->sending_ack = false; | |
| } | |
| // Send the pending flight, if any. | |
| if (ssl->d1->sending_flight) { | |
| int ret = send_flight(ssl); | |
| if (ret <= 0) { | |
| return ret; | |
| } | |
| // Reset state for the next send. | |
| ssl->d1->outgoing_written = 0; | |
| ssl->d1->outgoing_offset = 0; | |
| ssl->d1->sending_flight = false; | |
| // Schedule the next retransmit timer. In DTLS 1.3, we retransmit all | |
| // flights until ACKed. In DTLS 1.2, the final Finished flight is never | |
| // ACKed, so we do not keep the timer running after the handshake. | |
| if (SSL_in_init(ssl) || ssl_protocol_version(ssl) >= TLS1_3_VERSION) { | |
| if (ssl->d1->num_timeouts == 0) { | |
| ssl->d1->timeout_duration_ms = ssl->initial_timeout_duration_ms; | |
| } else { | |
| ssl->d1->timeout_duration_ms = | |
| std::min(ssl->d1->timeout_duration_ms * 2, uint32_t{60000}); | |
| } | |
| OPENSSL_timeval now = ssl_ctx_get_current_time(ssl->ctx.get()); | |
| ssl->d1->retransmit_timer.StartMicroseconds( | |
| now, uint64_t{ssl->d1->timeout_duration_ms} * 1000); | |
| } | |
| } | |
| return 1; | |
| } | |
| unsigned int dtls1_min_mtu(void) { return kMinMTU; } | |
| BSSL_NAMESPACE_END |