Add SSL_AEAD_CTX_seal_scatter.

This plumbs EVP_AEAD_CTX_seal_scatter all the way through to
tls_record.c, so we can add a new zero-copy record sealing method on top
of the existing code.

Change-Id: I01fdd88abef5442dc16605ea31b29b4b1231c073
Reviewed-on: https://boringssl-review.googlesource.com/17684
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/ssl_aead_ctx.cc b/ssl/ssl_aead_ctx.cc
index 0cdf717..b78b06b 100644
--- a/ssl/ssl_aead_ctx.cc
+++ b/ssl/ssl_aead_ctx.cc
@@ -140,16 +140,19 @@
   return 0;
 }
 
-size_t SSL_AEAD_CTX_max_overhead(const SSL_AEAD_CTX *aead) {
+size_t SSL_AEAD_CTX_max_suffix_len(const SSL_AEAD_CTX *aead,
+                                   size_t extra_in_len) {
 #if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
   aead = NULL;
 #endif
 
-  if (aead == NULL) {
-    return 0;
-  }
-  return EVP_AEAD_max_overhead(aead->ctx.aead) +
-         SSL_AEAD_CTX_explicit_nonce_len(aead);
+  return extra_in_len +
+         (aead == NULL ? 0 : EVP_AEAD_max_overhead(aead->ctx.aead));
+}
+
+size_t SSL_AEAD_CTX_max_overhead(const SSL_AEAD_CTX *aead) {
+  return SSL_AEAD_CTX_explicit_nonce_len(aead) +
+         SSL_AEAD_CTX_max_suffix_len(aead, 0);
 }
 
 /* ssl_aead_ctx_get_ad writes the additional data for |aead| into |out| and
@@ -252,22 +255,32 @@
   return 1;
 }
 
-int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len,
-                      size_t max_out, uint8_t type, uint16_t wire_version,
-                      const uint8_t seqnum[8], const uint8_t *in,
-                      size_t in_len) {
+int SSL_AEAD_CTX_seal_scatter(SSL_AEAD_CTX *aead, uint8_t *out_prefix,
+                              uint8_t *out, uint8_t *out_suffix,
+                              size_t *out_suffix_len, size_t max_out_suffix_len,
+                              uint8_t type, uint16_t wire_version,
+                              const uint8_t seqnum[8], const uint8_t *in,
+                              size_t in_len, const uint8_t *extra_in,
+                              size_t extra_in_len) {
 #if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
   aead = NULL;
 #endif
 
+  if ((in != out && buffers_alias(in, in_len, out, in_len)) ||
+      buffers_alias(in, in_len, out_suffix, max_out_suffix_len)) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT);
+    return 0;
+  }
+  if (extra_in_len > max_out_suffix_len) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
+    return 0;
+  }
+
   if (aead == NULL) {
     /* Handle the initial NULL cipher. */
-    if (in_len > max_out) {
-      OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
-      return 0;
-    }
     OPENSSL_memmove(out, in, in_len);
-    *out_len = in_len;
+    OPENSSL_memmove(out_suffix, extra_in, extra_in_len);
+    *out_suffix_len = extra_in_len;
     return 1;
   }
 
@@ -303,22 +316,14 @@
   nonce_len += aead->variable_nonce_len;
 
   /* Emit the variable nonce if included in the record. */
-  size_t extra_len = 0;
   if (aead->variable_nonce_included_in_record) {
     assert(!aead->xor_fixed_nonce);
-    if (max_out < aead->variable_nonce_len) {
-      OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
-      return 0;
-    }
-    if (out < in + in_len && in < out + aead->variable_nonce_len) {
+    if (buffers_alias(in, in_len, out_prefix, aead->variable_nonce_len)) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT);
       return 0;
     }
-    OPENSSL_memcpy(out, nonce + aead->fixed_nonce_len,
+    OPENSSL_memcpy(out_prefix, nonce + aead->fixed_nonce_len,
                    aead->variable_nonce_len);
-    extra_len = aead->variable_nonce_len;
-    out += aead->variable_nonce_len;
-    max_out -= aead->variable_nonce_len;
   }
 
   /* XOR the fixed nonce, if necessary. */
@@ -329,10 +334,33 @@
     }
   }
 
-  if (!EVP_AEAD_CTX_seal(&aead->ctx, out, out_len, max_out, nonce, nonce_len,
-                         in, in_len, ad, ad_len)) {
+  return EVP_AEAD_CTX_seal_scatter(&aead->ctx, out, out_suffix, out_suffix_len,
+                                   max_out_suffix_len, nonce, nonce_len, in,
+                                   in_len, extra_in, extra_in_len, ad, ad_len);
+}
+
+int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len,
+                      size_t max_out_len, uint8_t type, uint16_t wire_version,
+                      const uint8_t seqnum[8], const uint8_t *in,
+                      size_t in_len) {
+  size_t prefix_len = SSL_AEAD_CTX_explicit_nonce_len(aead);
+  if (in_len + prefix_len < in_len) {
+    OPENSSL_PUT_ERROR(CIPHER, SSL_R_RECORD_TOO_LARGE);
     return 0;
   }
-  *out_len += extra_len;
+  if (in_len + prefix_len > max_out_len) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
+    return 0;
+  }
+
+  size_t suffix_len;
+  if (!SSL_AEAD_CTX_seal_scatter(aead, out, out + prefix_len,
+                                 out + prefix_len + in_len, &suffix_len,
+                                 max_out_len - prefix_len - in_len, type,
+                                 wire_version, seqnum, in, in_len, 0, 0)) {
+    return 0;
+  }
+  assert(suffix_len <= SSL_AEAD_CTX_max_suffix_len(aead, 0));
+  *out_len = prefix_len + in_len + suffix_len;
   return 1;
 }