Fix output bounds checking in EVP_AEAD_CTX_seal_scatter

This broke with the CRYPTO_IOVEC change and, in calls with extra_in, we
didn't actually notice if the output buffer wasn't sized correctly.

Bug: 383343306
Change-Id: I719f427cf53359c2d77829e2732d8a9d119a4d67
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/93547
Auto-Submit: David Benjamin <davidben@google.com>
Presubmit-BoringSSL-Verified: boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com <boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com>
Commit-Queue: Rudolf Polzer <rpolzer@google.com>
Reviewed-by: Rudolf Polzer <rpolzer@google.com>
diff --git a/crypto/cipher/aead_test.cc b/crypto/cipher/aead_test.cc
index 1131263..12a35c6 100644
--- a/crypto/cipher/aead_test.cc
+++ b/crypto/cipher/aead_test.cc
@@ -332,6 +332,25 @@
       EXPECT_EQ(Bytes(ct), Bytes(out.data(), in.size()));
       EXPECT_EQ(Bytes(tag), Bytes(out_tag.data() + extra_in_size,
                                   tag_bytes_written - extra_in_size));
+
+      // Bounds on the tag output should be checked.
+      {
+        std::vector<uint8_t> tag_buf(extra_in_size == 0 ? 0
+                                                        : extra_in_size - 1);
+        EXPECT_FALSE(EVP_AEAD_CTX_seal_scatter(
+            ctx.get(), out.data(), tag_buf.data(), &tag_bytes_written,
+            tag_buf.size(), nonce.data(), nonce.size(), in.data(),
+            in.size() - extra_in_size, in.data() + in.size() - extra_in_size,
+            extra_in_size, ad.data(), ad.size()));
+      }
+      {
+        std::vector<uint8_t> tag_buf(extra_in_size + tag.size() - 1);
+        EXPECT_FALSE(EVP_AEAD_CTX_seal_scatter(
+            ctx.get(), out.data(), tag_buf.data(), &tag_bytes_written,
+            tag_buf.size(), nonce.data(), nonce.size(), in.data(),
+            in.size() - extra_in_size, in.data() + in.size() - extra_in_size,
+            extra_in_size, ad.data(), ad.size()));
+      }
     }
   });
 }
diff --git a/crypto/fipsmodule/cipher/aead.cc.inc b/crypto/fipsmodule/cipher/aead.cc.inc
index caee3ed..0e721ac 100644
--- a/crypto/fipsmodule/cipher/aead.cc.inc
+++ b/crypto/fipsmodule/cipher/aead.cc.inc
@@ -178,19 +178,28 @@
     }
   });
 
+  // |out_tag| contains both the encryption of |extra_in| and the tag.
+  Span<uint8_t> out_tag_span(out_tag, max_out_tag_len);
+  if (out_tag_span.size() < extra_in_len) {
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
+    return 0;
+  }
+  Span<uint8_t> extra_out = out_tag_span.first(extra_in_len);
+  Span<uint8_t> tag_only_out = out_tag_span.subspan(extra_in_len);
+
   CRYPTO_IOVEC iovec[2];
   iovec[0].in = in;
   iovec[0].out = out;
   iovec[0].len = in_len;
   iovec[1].in = extra_in;
-  iovec[1].out = out_tag;
+  iovec[1].out = extra_out.data();
   iovec[1].len = extra_in_len;
   CRYPTO_IVEC aadvec[1];
   aadvec[0].in = ad;
   aadvec[0].len = ad_len;
-  if (!EVP_AEAD_CTX_sealv(
-          ctx, iovec, extra_in_len ? 2 : 1, out_tag + extra_in_len, out_tag_len,
-          max_out_tag_len - extra_in_len, nonce, nonce_len, aadvec, 1)) {
+  if (!EVP_AEAD_CTX_sealv(ctx, iovec, extra_in_len ? 2 : 1, tag_only_out.data(),
+                          out_tag_len, tag_only_out.size(), nonce, nonce_len,
+                          aadvec, 1)) {
     *out_tag_len = 0;
     return 0;
   }