Make the bssl::SealRecord out_suffix arg fixed length.

Similarly, add EVP_AEAD_CTX_tag_len which computes the exact tag length
for required by EVP_AEAD_CTX_seal_scatter.

Change-Id: I069b0ad16fab314fd42f6048a3c1dc45e8376f7f
Reviewed-on: https://boringssl-review.googlesource.com/18324
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/cipher_extra/e_aesctrhmac.c b/crypto/cipher_extra/e_aesctrhmac.c
index 2982d0d..3034b8f 100644
--- a/crypto/cipher_extra/e_aesctrhmac.c
+++ b/crypto/cipher_extra/e_aesctrhmac.c
@@ -254,6 +254,7 @@
     aead_aes_ctr_hmac_sha256_seal_scatter,
     aead_aes_ctr_hmac_sha256_open_gather,
     NULL /* get_iv */,
+    NULL /* tag_len */,
 };
 
 static const EVP_AEAD aead_aes_256_ctr_hmac_sha256 = {
@@ -270,6 +271,7 @@
     aead_aes_ctr_hmac_sha256_seal_scatter,
     aead_aes_ctr_hmac_sha256_open_gather,
     NULL /* get_iv */,
+    NULL /* tag_len */,
 };
 
 const EVP_AEAD *EVP_aead_aes_128_ctr_hmac_sha256(void) {
diff --git a/crypto/cipher_extra/e_aesgcmsiv.c b/crypto/cipher_extra/e_aesgcmsiv.c
index 2dd1267..6adcf17 100644
--- a/crypto/cipher_extra/e_aesgcmsiv.c
+++ b/crypto/cipher_extra/e_aesgcmsiv.c
@@ -520,6 +520,7 @@
     aead_aes_gcm_siv_asm_seal_scatter,
     NULL /* open_gather */,
     NULL /* get_iv */,
+    NULL /* tag_len */,
 };
 
 static const EVP_AEAD aead_aes_256_gcm_siv_asm = {
@@ -536,6 +537,7 @@
     aead_aes_gcm_siv_asm_seal_scatter,
     NULL /* open_gather */,
     NULL /* get_iv */,
+    NULL /* tag_len */,
 };
 
 #endif  /* X86_64 && !NO_ASM */
@@ -804,6 +806,7 @@
     aead_aes_gcm_siv_seal_scatter,
     aead_aes_gcm_siv_open_gather,
     NULL /* get_iv */,
+    NULL /* tag_len */,
 };
 
 static const EVP_AEAD aead_aes_256_gcm_siv = {
@@ -820,6 +823,7 @@
     aead_aes_gcm_siv_seal_scatter,
     aead_aes_gcm_siv_open_gather,
     NULL /* get_iv */,
+    NULL /* tag_len */,
 };
 
 #if defined(OPENSSL_X86_64) && !defined(OPENSSL_NO_ASM)
diff --git a/crypto/cipher_extra/e_chacha20poly1305.c b/crypto/cipher_extra/e_chacha20poly1305.c
index 515b60f..162e14b 100644
--- a/crypto/cipher_extra/e_chacha20poly1305.c
+++ b/crypto/cipher_extra/e_chacha20poly1305.c
@@ -294,6 +294,7 @@
     aead_chacha20_poly1305_seal_scatter,
     aead_chacha20_poly1305_open_gather,
     NULL, /* get_iv */
+    NULL, /* tag_len */
 };
 
 const EVP_AEAD *EVP_aead_chacha20_poly1305(void) {
diff --git a/crypto/cipher_extra/e_ssl3.c b/crypto/cipher_extra/e_ssl3.c
index f2eb357..dc43713 100644
--- a/crypto/cipher_extra/e_ssl3.c
+++ b/crypto/cipher_extra/e_ssl3.c
@@ -123,13 +123,33 @@
   return 1;
 }
 
+static size_t aead_ssl3_tag_len(const EVP_AEAD_CTX *ctx, const size_t in_len,
+                                const size_t extra_in_len) {
+  assert(extra_in_len == 0);
+  const AEAD_SSL3_CTX *ssl3_ctx = (AEAD_SSL3_CTX*)ctx->aead_state;
+
+  const size_t digest_len = EVP_MD_CTX_size(&ssl3_ctx->md_ctx);
+  if (EVP_CIPHER_CTX_mode(&ssl3_ctx->cipher_ctx) != EVP_CIPH_CBC_MODE) {
+    // The NULL cipher.
+    return digest_len;
+  }
+
+  const size_t block_size = EVP_CIPHER_CTX_block_size(&ssl3_ctx->cipher_ctx);
+  /* An overflow of |in_len + digest_len| doesn't affect the result mod
+   * |block_size|, provided that |block_size| is a smaller power of two. */
+  assert(block_size != 0 && (block_size & (block_size - 1)) == 0);
+  const size_t pad_len = block_size - ((in_len + digest_len) % block_size);
+  return digest_len + pad_len;
+}
+
 static int aead_ssl3_seal_scatter(const EVP_AEAD_CTX *ctx, uint8_t *out,
                                   uint8_t *out_tag, size_t *out_tag_len,
-                                  size_t max_out_tag_len, const uint8_t *nonce,
-                                  size_t nonce_len, const uint8_t *in,
-                                  size_t in_len, const uint8_t *extra_in,
-                                  size_t extra_in_len, const uint8_t *ad,
-                                  size_t ad_len) {
+                                  const size_t max_out_tag_len,
+                                  const uint8_t *nonce, const size_t nonce_len,
+                                  const uint8_t *in, const size_t in_len,
+                                  const uint8_t *extra_in,
+                                  const size_t extra_in_len, const uint8_t *ad,
+                                  const size_t ad_len) {
   AEAD_SSL3_CTX *ssl3_ctx = (AEAD_SSL3_CTX *)ctx->aead_state;
 
   if (!ssl3_ctx->cipher_ctx.encrypt) {
@@ -144,8 +164,7 @@
     return 0;
   }
 
-  const size_t max_overhead = EVP_AEAD_max_overhead(ctx->aead);
-  if (max_out_tag_len < max_overhead) {
+  if (max_out_tag_len < aead_ssl3_tag_len(ctx, in_len, extra_in_len)) {
     OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
     return 0;
   }
@@ -222,7 +241,7 @@
     return 0;
   }
   tag_len += len;
-  assert(tag_len <= max_overhead);
+  assert(tag_len == aead_ssl3_tag_len(ctx, in_len, extra_in_len));
 
   *out_tag_len = tag_len;
   return 1;
@@ -372,6 +391,7 @@
     aead_ssl3_seal_scatter,
     NULL, /* open_gather */
     aead_ssl3_get_iv,
+    aead_ssl3_tag_len,
 };
 
 static const EVP_AEAD aead_aes_256_cbc_sha1_ssl3 = {
@@ -388,6 +408,7 @@
     aead_ssl3_seal_scatter,
     NULL, /* open_gather */
     aead_ssl3_get_iv,
+    aead_ssl3_tag_len,
 };
 
 static const EVP_AEAD aead_des_ede3_cbc_sha1_ssl3 = {
@@ -404,6 +425,7 @@
     aead_ssl3_seal_scatter,
     NULL, /* open_gather */
     aead_ssl3_get_iv,
+    aead_ssl3_tag_len,
 };
 
 static const EVP_AEAD aead_null_sha1_ssl3 = {
@@ -420,6 +442,7 @@
     aead_ssl3_seal_scatter,
     NULL, /* open_gather */
     NULL, /* get_iv */
+    aead_ssl3_tag_len,
 };
 
 const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_ssl3(void) {
diff --git a/crypto/cipher_extra/e_tls.c b/crypto/cipher_extra/e_tls.c
index 14d5377..ca206ab 100644
--- a/crypto/cipher_extra/e_tls.c
+++ b/crypto/cipher_extra/e_tls.c
@@ -99,13 +99,33 @@
   return 1;
 }
 
+static size_t aead_tls_tag_len(const EVP_AEAD_CTX *ctx, const size_t in_len,
+                               const size_t extra_in_len) {
+  assert(extra_in_len == 0);
+  AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX *)ctx->aead_state;
+
+  const size_t hmac_len = HMAC_size(&tls_ctx->hmac_ctx);
+  if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) != EVP_CIPH_CBC_MODE) {
+    // The NULL cipher.
+    return hmac_len;
+  }
+
+  const size_t block_size = EVP_CIPHER_CTX_block_size(&tls_ctx->cipher_ctx);
+  /* An overflow of |in_len + hmac_len| doesn't affect the result mod
+   * |block_size|, provided that |block_size| is a smaller power of two. */
+  assert(block_size != 0 && (block_size & (block_size - 1)) == 0);
+  const size_t pad_len = block_size - (in_len + hmac_len) % block_size;
+  return hmac_len + pad_len;
+}
+
 static int aead_tls_seal_scatter(const EVP_AEAD_CTX *ctx, uint8_t *out,
                                  uint8_t *out_tag, size_t *out_tag_len,
-                                 size_t max_out_tag_len, const uint8_t *nonce,
-                                 size_t nonce_len, const uint8_t *in,
-                                 size_t in_len, const uint8_t *extra_in,
-                                 size_t extra_in_len, const uint8_t *ad,
-                                 size_t ad_len) {
+                                 const size_t max_out_tag_len,
+                                 const uint8_t *nonce, const size_t nonce_len,
+                                 const uint8_t *in, const size_t in_len,
+                                 const uint8_t *extra_in,
+                                 const size_t extra_in_len, const uint8_t *ad,
+                                 const size_t ad_len) {
   AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX *)ctx->aead_state;
 
   if (!tls_ctx->cipher_ctx.encrypt) {
@@ -120,8 +140,7 @@
     return 0;
   }
 
-  const size_t max_overhead = EVP_AEAD_max_overhead(ctx->aead);
-  if (max_out_tag_len < max_overhead) {
+  if (max_out_tag_len < aead_tls_tag_len(ctx, in_len, extra_in_len)) {
     OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
     return 0;
   }
@@ -173,7 +192,8 @@
    * block from encrypting the input and split the result between |out| and
    * |out_tag|. Then feed the rest. */
 
-  size_t early_mac_len = (block_size - (in_len % block_size)) % block_size;
+  const size_t early_mac_len =
+      (block_size - (in_len % block_size) % block_size);
   if (early_mac_len != 0) {
     assert(len + block_size - early_mac_len == in_len);
     uint8_t buf[EVP_MAX_BLOCK_LENGTH];
@@ -212,8 +232,8 @@
   if (!EVP_EncryptFinal_ex(&tls_ctx->cipher_ctx, out_tag + tag_len, &len)) {
     return 0;
   }
-  tag_len += len;
-  assert(tag_len <= max_overhead);
+  assert(len == 0); /* Padding is explicit. */
+  assert(tag_len == aead_tls_tag_len(ctx, in_len, extra_in_len));
 
   *out_tag_len = tag_len;
   return 1;
@@ -467,6 +487,7 @@
     aead_tls_seal_scatter,
     NULL, /* open_gather */
     NULL, /* get_iv */
+    aead_tls_tag_len,
 };
 
 static const EVP_AEAD aead_aes_128_cbc_sha1_tls_implicit_iv = {
@@ -483,6 +504,7 @@
     aead_tls_seal_scatter,
     NULL,            /* open_gather */
     aead_tls_get_iv, /* get_iv */
+    aead_tls_tag_len,
 };
 
 static const EVP_AEAD aead_aes_128_cbc_sha256_tls = {
@@ -499,6 +521,7 @@
     aead_tls_seal_scatter,
     NULL, /* open_gather */
     NULL, /* get_iv */
+    aead_tls_tag_len,
 };
 
 static const EVP_AEAD aead_aes_256_cbc_sha1_tls = {
@@ -515,6 +538,7 @@
     aead_tls_seal_scatter,
     NULL, /* open_gather */
     NULL, /* get_iv */
+    aead_tls_tag_len,
 };
 
 static const EVP_AEAD aead_aes_256_cbc_sha1_tls_implicit_iv = {
@@ -531,6 +555,7 @@
     aead_tls_seal_scatter,
     NULL,            /* open_gather */
     aead_tls_get_iv, /* get_iv */
+    aead_tls_tag_len,
 };
 
 static const EVP_AEAD aead_aes_256_cbc_sha256_tls = {
@@ -547,6 +572,7 @@
     aead_tls_seal_scatter,
     NULL, /* open_gather */
     NULL, /* get_iv */
+    aead_tls_tag_len,
 };
 
 static const EVP_AEAD aead_aes_256_cbc_sha384_tls = {
@@ -563,6 +589,7 @@
     aead_tls_seal_scatter,
     NULL, /* open_gather */
     NULL, /* get_iv */
+    aead_tls_tag_len,
 };
 
 static const EVP_AEAD aead_des_ede3_cbc_sha1_tls = {
@@ -579,6 +606,7 @@
     aead_tls_seal_scatter,
     NULL, /* open_gather */
     NULL, /* get_iv */
+    aead_tls_tag_len,
 };
 
 static const EVP_AEAD aead_des_ede3_cbc_sha1_tls_implicit_iv = {
@@ -595,6 +623,7 @@
     aead_tls_seal_scatter,
     NULL,            /* open_gather */
     aead_tls_get_iv, /* get_iv */
+    aead_tls_tag_len,
 };
 
 static const EVP_AEAD aead_null_sha1_tls = {
@@ -611,6 +640,7 @@
     aead_tls_seal_scatter,
     NULL, /* open_gather */
     NULL, /* get_iv */
+    aead_tls_tag_len,
 };
 
 const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_tls(void) {
diff --git a/crypto/fipsmodule/cipher/aead.c b/crypto/fipsmodule/cipher/aead.c
index 79139e6..ed30209 100644
--- a/crypto/fipsmodule/cipher/aead.c
+++ b/crypto/fipsmodule/cipher/aead.c
@@ -264,3 +264,21 @@
 
   return ctx->aead->get_iv(ctx, out_iv, out_len);
 }
+
+int EVP_AEAD_CTX_tag_len(const EVP_AEAD_CTX *ctx, size_t *out_tag_len,
+                         const size_t in_len, const size_t extra_in_len) {
+  assert(ctx->aead->seal_scatter_supports_extra_in || !extra_in_len);
+
+  if (ctx->aead->tag_len) {
+    *out_tag_len = ctx->aead->tag_len(ctx, in_len, extra_in_len);
+    return 1;
+  }
+
+  if (extra_in_len + ctx->tag_len < extra_in_len) {
+    OPENSSL_PUT_ERROR(CIPHER, ERR_R_OVERFLOW);
+    *out_tag_len = 0;
+    return 0;
+  }
+  *out_tag_len = extra_in_len + ctx->tag_len;
+  return 1;
+}
diff --git a/crypto/fipsmodule/cipher/e_aes.c b/crypto/fipsmodule/cipher/e_aes.c
index 7c7521b..2c6fc41 100644
--- a/crypto/fipsmodule/cipher/e_aes.c
+++ b/crypto/fipsmodule/cipher/e_aes.c
@@ -1217,7 +1217,7 @@
     OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
     return 0;
   }
-  if (max_out_tag_len < ctx->tag_len + extra_in_len) {
+  if (max_out_tag_len < extra_in_len + ctx->tag_len) {
     OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
     return 0;
   }
@@ -1226,11 +1226,6 @@
     return 0;
   }
 
-  if (max_out_tag_len < ctx->tag_len) {
-    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
-    return 0;
-  }
-
   const AES_KEY *key = &gcm_ctx->ks.ks;
 
   OPENSSL_memcpy(&gcm, &gcm_ctx->gcm, sizeof(gcm));
diff --git a/crypto/fipsmodule/cipher/internal.h b/crypto/fipsmodule/cipher/internal.h
index ea59723..02335e0 100644
--- a/crypto/fipsmodule/cipher/internal.h
+++ b/crypto/fipsmodule/cipher/internal.h
@@ -107,6 +107,9 @@
 
   int (*get_iv)(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv,
                 size_t *out_len);
+
+  size_t (*tag_len)(const EVP_AEAD_CTX *ctx, size_t in_Len,
+                    size_t extra_in_len);
 };
 
 /* aes_ctr_set_key initialises |*aes_key| using |key_bytes| bytes from |key|,