Make SSL3_BUFFER a proper C++ class.
As with SSLTranscript before, we temporarily need some nastiness in
SSL3_STATE, but this is in preparation of giving SSL3_STATE a
constructor and destructor.
Change-Id: Ifc0ce34fdcd8691d521d8ea03ff5e83dad43b4a3
Reviewed-on: https://boringssl-review.googlesource.com/21944
Reviewed-by: Steven Valdez <svaldez@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/ssl/ssl_buffer.cc b/ssl/ssl_buffer.cc
index 412df73..a942054 100644
--- a/ssl/ssl_buffer.cc
+++ b/ssl/ssl_buffer.cc
@@ -36,17 +36,22 @@
static_assert((SSL3_ALIGN_PAYLOAD & (SSL3_ALIGN_PAYLOAD - 1)) == 0,
"SSL3_ALIGN_PAYLOAD must be a power of 2");
-// ensure_buffer ensures |buf| has capacity at least |cap|, aligned such that
-// data written after |header_len| is aligned to a |SSL3_ALIGN_PAYLOAD|-byte
-// boundary. It returns one on success and zero on error.
-static int ensure_buffer(SSL3_BUFFER *buf, size_t header_len, size_t cap) {
- if (cap > 0xffff) {
+void SSLBuffer::Clear() {
+ free(buf_); // Allocated with malloc().
+ buf_ = nullptr;
+ 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 0;
+ return false;
}
- if (buf->cap >= cap) {
- return 1;
+ if (cap_ >= new_cap) {
+ return true;
}
// Add up to |SSL3_ALIGN_PAYLOAD| - 1 bytes of slack for alignment.
@@ -54,88 +59,88 @@
// 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.
- uint8_t *new_buf = (uint8_t *)malloc(cap + SSL3_ALIGN_PAYLOAD - 1);
+ uint8_t *new_buf = (uint8_t *)malloc(new_cap + SSL3_ALIGN_PAYLOAD - 1);
if (new_buf == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
- return 0;
+ return false;
}
// Offset the buffer such that the record body is aligned.
size_t new_offset =
(0 - header_len - (uintptr_t)new_buf) & (SSL3_ALIGN_PAYLOAD - 1);
- if (buf->buf != NULL) {
- OPENSSL_memcpy(new_buf + new_offset, buf->buf + buf->offset, buf->len);
- free(buf->buf); // Allocated with malloc().
+ if (buf_ != NULL) {
+ OPENSSL_memcpy(new_buf + new_offset, buf_ + offset_, size_);
+ free(buf_); // Allocated with malloc().
}
- buf->buf = new_buf;
- buf->offset = new_offset;
- buf->cap = cap;
- return 1;
+ buf_ = new_buf;
+ offset_ = new_offset;
+ cap_ = new_cap;
+ return true;
}
-static void consume_buffer(SSL3_BUFFER *buf, size_t len) {
- if (len > buf->len) {
+void SSLBuffer::DidWrite(size_t new_size) {
+ if (new_size > cap() - size()) {
abort();
}
- buf->offset += (uint16_t)len;
- buf->len -= (uint16_t)len;
- buf->cap -= (uint16_t)len;
+ size_ += new_size;
}
-static void clear_buffer(SSL3_BUFFER *buf) {
- free(buf->buf); // Allocated with malloc().
- OPENSSL_memset(buf, 0, sizeof(SSL3_BUFFER));
+void SSLBuffer::Consume(size_t len) {
+ if (len > size_) {
+ abort();
+ }
+ offset_ += (uint16_t)len;
+ size_ -= (uint16_t)len;
+ cap_ -= (uint16_t)len;
}
-Span<uint8_t> ssl_read_buffer(SSL *ssl) {
- return MakeSpan(ssl->s3->read_buffer.buf + ssl->s3->read_buffer.offset,
- ssl->s3->read_buffer.len);
+void SSLBuffer::DiscardConsumed() {
+ if (size_ == 0) {
+ Clear();
+ }
}
static int dtls_read_buffer_next_packet(SSL *ssl) {
- SSL3_BUFFER *buf = &ssl->s3->read_buffer;
+ SSLBuffer *buf = &ssl->s3->read_buffer;
- if (buf->len > 0) {
+ 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, buf->buf + buf->offset, (int)buf->cap);
+ // Read a single packet from |ssl->rbio|. |buf->cap()| must fit in an int.
+ int ret = BIO_read(ssl->rbio, buf->data(), static_cast<int>(buf->cap()));
if (ret <= 0) {
ssl->rwstate = SSL_READING;
return ret;
}
- // |BIO_read| was bound by |buf->cap|, so this cannot overflow.
- buf->len = (uint16_t)ret;
+ buf->DidWrite(static_cast<size_t>(ret));
return 1;
}
static int tls_read_buffer_extend_to(SSL *ssl, size_t len) {
- SSL3_BUFFER *buf = &ssl->s3->read_buffer;
+ SSLBuffer *buf = &ssl->s3->read_buffer;
- if (len > buf->cap) {
+ if (len > buf->cap()) {
OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
return -1;
}
// Read until the target length is reached.
- while (buf->len < len) {
+ 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, buf->buf + buf->offset + buf->len,
- (int)(len - buf->len));
+ int ret = BIO_read(ssl->rbio, buf->data() + buf->size(),
+ static_cast<int>(len - buf->size()));
if (ret <= 0) {
ssl->rwstate = SSL_READING;
return ret;
}
- // |BIO_read| was bound by |buf->cap - buf->len|, so this cannot
- // overflow.
- buf->len += (uint16_t)ret;
+ buf->DidWrite(static_cast<size_t>(ret));
}
return 1;
@@ -143,7 +148,7 @@
int ssl_read_buffer_extend_to(SSL *ssl, size_t len) {
// |ssl_read_buffer_extend_to| implicitly discards any consumed data.
- ssl_read_buffer_discard(ssl);
+ ssl->s3->read_buffer.DiscardConsumed();
if (SSL_is_dtls(ssl)) {
static_assert(
@@ -154,7 +159,7 @@
len = DTLS1_RT_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH;
}
- if (!ensure_buffer(&ssl->s3->read_buffer, ssl_record_prefix_len(ssl), len)) {
+ if (!ssl->s3->read_buffer.EnsureCap(ssl_record_prefix_len(ssl), len)) {
return -1;
}
@@ -174,43 +179,20 @@
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_read_buffer_discard(ssl);
+ ssl->s3->read_buffer.DiscardConsumed();
}
return ret;
}
-void ssl_read_buffer_consume(SSL *ssl, size_t len) {
- SSL3_BUFFER *buf = &ssl->s3->read_buffer;
-
- consume_buffer(buf, len);
-
- // The TLS stack never reads beyond the current record, so there will never be
- // unconsumed data. If read-ahead is ever reimplemented,
- // |ssl_read_buffer_discard| will require a |memcpy| to shift the excess back
- // to the front of the buffer, to ensure there is enough space for the next
- // record.
- assert(SSL_is_dtls(ssl) || len == 0 || buf->len == 0);
-}
-
-void ssl_read_buffer_discard(SSL *ssl) {
- if (ssl->s3->read_buffer.len == 0) {
- ssl_read_buffer_clear(ssl);
- }
-}
-
-void ssl_read_buffer_clear(SSL *ssl) {
- clear_buffer(&ssl->s3->read_buffer);
-}
-
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_read_buffer_consume(ssl, consumed);
+ ssl->s3->read_buffer.Consume(consumed);
}
if (ret != ssl_open_record_success) {
// Nothing was returned to the caller, so discard anything marked consumed.
- ssl_read_buffer_discard(ssl);
+ ssl->s3->read_buffer.DiscardConsumed();
}
switch (ret) {
case ssl_open_record_success:
@@ -243,10 +225,6 @@
}
-int ssl_write_buffer_is_pending(const SSL *ssl) {
- return ssl->s3->write_buffer.len > 0;
-}
-
static_assert(SSL3_RT_HEADER_LENGTH * 2 +
SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD * 2 +
SSL3_RT_MAX_PLAIN_LENGTH <=
@@ -258,61 +236,37 @@
0xffff,
"maximum DTLS write buffer is too large");
-int ssl_write_buffer_init(SSL *ssl, uint8_t **out_ptr, size_t max_len) {
- SSL3_BUFFER *buf = &ssl->s3->write_buffer;
-
- if (buf->buf != NULL) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- if (!ensure_buffer(buf, ssl_seal_align_prefix_len(ssl), max_len)) {
- return 0;
- }
- *out_ptr = buf->buf + buf->offset;
- return 1;
-}
-
-void ssl_write_buffer_set_len(SSL *ssl, size_t len) {
- SSL3_BUFFER *buf = &ssl->s3->write_buffer;
-
- if (len > buf->cap) {
- abort();
- }
- buf->len = len;
-}
-
static int tls_write_buffer_flush(SSL *ssl) {
- SSL3_BUFFER *buf = &ssl->s3->write_buffer;
+ SSLBuffer *buf = &ssl->s3->write_buffer;
- while (buf->len > 0) {
- int ret = BIO_write(ssl->wbio, buf->buf + buf->offset, buf->len);
+ while (!buf->empty()) {
+ int ret = BIO_write(ssl->wbio, buf->data(), buf->size());
if (ret <= 0) {
ssl->rwstate = SSL_WRITING;
return ret;
}
- consume_buffer(buf, (size_t)ret);
+ buf->Consume(static_cast<size_t>(ret));
}
- ssl_write_buffer_clear(ssl);
+ buf->Clear();
return 1;
}
static int dtls_write_buffer_flush(SSL *ssl) {
- SSL3_BUFFER *buf = &ssl->s3->write_buffer;
- if (buf->len == 0) {
+ SSLBuffer *buf = &ssl->s3->write_buffer;
+ if (buf->empty()) {
return 1;
}
- int ret = BIO_write(ssl->wbio, buf->buf + buf->offset, buf->len);
+ int ret = BIO_write(ssl->wbio, buf->data(), buf->size());
if (ret <= 0) {
ssl->rwstate = SSL_WRITING;
// 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.
- ssl_write_buffer_clear(ssl);
+ buf->Clear();
return ret;
}
- ssl_write_buffer_clear(ssl);
+ buf->Clear();
return 1;
}
@@ -329,8 +283,4 @@
}
}
-void ssl_write_buffer_clear(SSL *ssl) {
- clear_buffer(&ssl->s3->write_buffer);
-}
-
} // namespace bssl