|  | /* Copyright (c) 2015, Google Inc. | 
|  | * | 
|  | * Permission to use, copy, modify, and/or distribute this software for any | 
|  | * purpose with or without fee is hereby granted, provided that the above | 
|  | * copyright notice and this permission notice appear in all copies. | 
|  | * | 
|  | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 
|  | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 
|  | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | 
|  | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 
|  | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | 
|  | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | 
|  | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ | 
|  |  | 
|  | #include <openssl/ssl.h> | 
|  |  | 
|  | #include <assert.h> | 
|  | #include <limits.h> | 
|  | #include <stdlib.h> | 
|  | #include <string.h> | 
|  |  | 
|  | #include <openssl/bio.h> | 
|  | #include <openssl/err.h> | 
|  | #include <openssl/mem.h> | 
|  |  | 
|  | #include "../crypto/internal.h" | 
|  | #include "internal.h" | 
|  |  | 
|  |  | 
|  | BSSL_NAMESPACE_BEGIN | 
|  |  | 
|  | // BIO uses int instead of size_t. No lengths will exceed uint16_t, so this will | 
|  | // not overflow. | 
|  | static_assert(0xffff <= INT_MAX, "uint16_t does not fit in int"); | 
|  |  | 
|  | static_assert((SSL3_ALIGN_PAYLOAD & (SSL3_ALIGN_PAYLOAD - 1)) == 0, | 
|  | "SSL3_ALIGN_PAYLOAD must be a power of 2"); | 
|  |  | 
|  | void SSLBuffer::Clear() { | 
|  | if (buf_allocated_) { | 
|  | free(buf_);  // Allocated with malloc(). | 
|  | } | 
|  | buf_ = nullptr; | 
|  | buf_allocated_ = false; | 
|  | offset_ = 0; | 
|  | size_ = 0; | 
|  | cap_ = 0; | 
|  | } | 
|  |  | 
|  | bool SSLBuffer::EnsureCap(size_t header_len, size_t new_cap) { | 
|  | if (new_cap > 0xffff) { | 
|  | OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (cap_ >= new_cap) { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | uint8_t *new_buf; | 
|  | bool new_buf_allocated; | 
|  | size_t new_offset; | 
|  | if (new_cap <= sizeof(inline_buf_)) { | 
|  | // This function is called twice per TLS record, first for the five-byte | 
|  | // header. To avoid allocating twice, use an inline buffer for short inputs. | 
|  | new_buf = inline_buf_; | 
|  | new_buf_allocated = false; | 
|  | new_offset = 0; | 
|  | } else { | 
|  | // Add up to |SSL3_ALIGN_PAYLOAD| - 1 bytes of slack for alignment. | 
|  | // | 
|  | // Since this buffer gets allocated quite frequently and doesn't contain any | 
|  | // sensitive data, we allocate with malloc rather than |OPENSSL_malloc| and | 
|  | // avoid zeroing on free. | 
|  | new_buf = (uint8_t *)malloc(new_cap + SSL3_ALIGN_PAYLOAD - 1); | 
|  | if (new_buf == NULL) { | 
|  | OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); | 
|  | return false; | 
|  | } | 
|  | new_buf_allocated = true; | 
|  |  | 
|  | // Offset the buffer such that the record body is aligned. | 
|  | new_offset = | 
|  | (0 - header_len - (uintptr_t)new_buf) & (SSL3_ALIGN_PAYLOAD - 1); | 
|  | } | 
|  |  | 
|  | // Note if the both old and new buffer are inline, the source and destination | 
|  | // may alias. | 
|  | OPENSSL_memmove(new_buf + new_offset, buf_ + offset_, size_); | 
|  |  | 
|  | if (buf_allocated_) { | 
|  | free(buf_);  // Allocated with malloc(). | 
|  | } | 
|  |  | 
|  | buf_ = new_buf; | 
|  | buf_allocated_ = new_buf_allocated; | 
|  | offset_ = new_offset; | 
|  | cap_ = new_cap; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void SSLBuffer::DidWrite(size_t new_size) { | 
|  | if (new_size > cap() - size()) { | 
|  | abort(); | 
|  | } | 
|  | size_ += new_size; | 
|  | } | 
|  |  | 
|  | void SSLBuffer::Consume(size_t len) { | 
|  | if (len > size_) { | 
|  | abort(); | 
|  | } | 
|  | offset_ += (uint16_t)len; | 
|  | size_ -= (uint16_t)len; | 
|  | cap_ -= (uint16_t)len; | 
|  | } | 
|  |  | 
|  | void SSLBuffer::DiscardConsumed() { | 
|  | if (size_ == 0) { | 
|  | Clear(); | 
|  | } | 
|  | } | 
|  |  | 
|  | static int dtls_read_buffer_next_packet(SSL *ssl) { | 
|  | SSLBuffer *buf = &ssl->s3->read_buffer; | 
|  |  | 
|  | if (!buf->empty()) { | 
|  | // It is an error to call |dtls_read_buffer_extend| when the read buffer is | 
|  | // not empty. | 
|  | OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // Read a single packet from |ssl->rbio|. |buf->cap()| must fit in an int. | 
|  | int ret = | 
|  | BIO_read(ssl->rbio.get(), buf->data(), static_cast<int>(buf->cap())); | 
|  | if (ret <= 0) { | 
|  | ssl->s3->rwstate = SSL_ERROR_WANT_READ; | 
|  | return ret; | 
|  | } | 
|  | buf->DidWrite(static_cast<size_t>(ret)); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static int tls_read_buffer_extend_to(SSL *ssl, size_t len) { | 
|  | SSLBuffer *buf = &ssl->s3->read_buffer; | 
|  |  | 
|  | if (len > buf->cap()) { | 
|  | OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // Read until the target length is reached. | 
|  | while (buf->size() < len) { | 
|  | // The amount of data to read is bounded by |buf->cap|, which must fit in an | 
|  | // int. | 
|  | int ret = BIO_read(ssl->rbio.get(), buf->data() + buf->size(), | 
|  | static_cast<int>(len - buf->size())); | 
|  | if (ret <= 0) { | 
|  | ssl->s3->rwstate = SSL_ERROR_WANT_READ; | 
|  | return ret; | 
|  | } | 
|  | buf->DidWrite(static_cast<size_t>(ret)); | 
|  | } | 
|  |  | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | int ssl_read_buffer_extend_to(SSL *ssl, size_t len) { | 
|  | // |ssl_read_buffer_extend_to| implicitly discards any consumed data. | 
|  | ssl->s3->read_buffer.DiscardConsumed(); | 
|  |  | 
|  | if (SSL_is_dtls(ssl)) { | 
|  | static_assert( | 
|  | DTLS1_RT_MAX_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH <= 0xffff, | 
|  | "DTLS read buffer is too large"); | 
|  |  | 
|  | // The |len| parameter is ignored in DTLS. | 
|  | len = DTLS1_RT_MAX_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH; | 
|  | } | 
|  |  | 
|  | // The DTLS record header can have a variable length, so the |header_len| | 
|  | // value provided for buffer alignment only works if the header is the maximum | 
|  | // length. | 
|  | if (!ssl->s3->read_buffer.EnsureCap(DTLS1_RT_MAX_HEADER_LENGTH, len)) { | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | if (ssl->rbio == nullptr) { | 
|  | OPENSSL_PUT_ERROR(SSL, SSL_R_BIO_NOT_SET); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | int ret; | 
|  | if (SSL_is_dtls(ssl)) { | 
|  | // |len| is ignored for a datagram transport. | 
|  | ret = dtls_read_buffer_next_packet(ssl); | 
|  | } else { | 
|  | ret = tls_read_buffer_extend_to(ssl, len); | 
|  | } | 
|  |  | 
|  | if (ret <= 0) { | 
|  | // If the buffer was empty originally and remained empty after attempting to | 
|  | // extend it, release the buffer until the next attempt. | 
|  | ssl->s3->read_buffer.DiscardConsumed(); | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | int ssl_handle_open_record(SSL *ssl, bool *out_retry, ssl_open_record_t ret, | 
|  | size_t consumed, uint8_t alert) { | 
|  | *out_retry = false; | 
|  | if (ret != ssl_open_record_partial) { | 
|  | ssl->s3->read_buffer.Consume(consumed); | 
|  | } | 
|  | if (ret != ssl_open_record_success) { | 
|  | // Nothing was returned to the caller, so discard anything marked consumed. | 
|  | ssl->s3->read_buffer.DiscardConsumed(); | 
|  | } | 
|  | switch (ret) { | 
|  | case ssl_open_record_success: | 
|  | return 1; | 
|  |  | 
|  | case ssl_open_record_partial: { | 
|  | int read_ret = ssl_read_buffer_extend_to(ssl, consumed); | 
|  | if (read_ret <= 0) { | 
|  | return read_ret; | 
|  | } | 
|  | *out_retry = true; | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | case ssl_open_record_discard: | 
|  | *out_retry = true; | 
|  | return 1; | 
|  |  | 
|  | case ssl_open_record_close_notify: | 
|  | ssl->s3->rwstate = SSL_ERROR_ZERO_RETURN; | 
|  | return 0; | 
|  |  | 
|  | case ssl_open_record_error: | 
|  | if (alert != 0) { | 
|  | ssl_send_alert(ssl, SSL3_AL_FATAL, alert); | 
|  | } | 
|  | return -1; | 
|  | } | 
|  | assert(0); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  |  | 
|  | static_assert(SSL3_RT_HEADER_LENGTH * 2 + | 
|  | SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD * 2 + | 
|  | SSL3_RT_MAX_PLAIN_LENGTH <= | 
|  | 0xffff, | 
|  | "maximum TLS write buffer is too large"); | 
|  |  | 
|  | static_assert(DTLS1_RT_MAX_HEADER_LENGTH + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD + | 
|  | SSL3_RT_MAX_PLAIN_LENGTH <= | 
|  | 0xffff, | 
|  | "maximum DTLS write buffer is too large"); | 
|  |  | 
|  | static int tls_write_buffer_flush(SSL *ssl) { | 
|  | SSLBuffer *buf = &ssl->s3->write_buffer; | 
|  |  | 
|  | while (!buf->empty()) { | 
|  | int ret = BIO_write(ssl->wbio.get(), buf->data(), buf->size()); | 
|  | if (ret <= 0) { | 
|  | ssl->s3->rwstate = SSL_ERROR_WANT_WRITE; | 
|  | return ret; | 
|  | } | 
|  | buf->Consume(static_cast<size_t>(ret)); | 
|  | } | 
|  | buf->Clear(); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static int dtls_write_buffer_flush(SSL *ssl) { | 
|  | SSLBuffer *buf = &ssl->s3->write_buffer; | 
|  | if (buf->empty()) { | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | int ret = BIO_write(ssl->wbio.get(), buf->data(), buf->size()); | 
|  | if (ret <= 0) { | 
|  | ssl->s3->rwstate = SSL_ERROR_WANT_WRITE; | 
|  | // If the write failed, drop the write buffer anyway. Datagram transports | 
|  | // can't write half a packet, so the caller is expected to retry from the | 
|  | // top. | 
|  | buf->Clear(); | 
|  | return ret; | 
|  | } | 
|  | buf->Clear(); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | int ssl_write_buffer_flush(SSL *ssl) { | 
|  | if (ssl->wbio == nullptr) { | 
|  | OPENSSL_PUT_ERROR(SSL, SSL_R_BIO_NOT_SET); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | if (SSL_is_dtls(ssl)) { | 
|  | return dtls_write_buffer_flush(ssl); | 
|  | } else { | 
|  | return tls_write_buffer_flush(ssl); | 
|  | } | 
|  | } | 
|  |  | 
|  | BSSL_NAMESPACE_END |