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