Add EVP_AEAD_CTX_zero.

Match the other stack-allocated types in that we expose a wrapper function to
get them into the zero state. Makes it more amenable to templates like
ScopedOpenSSLContext.

Change-Id: Ibc7b2b1bc0421ce5ccc84760c78c0b143441ab0f
Reviewed-on: https://boringssl-review.googlesource.com/5753
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/cipher/aead.c b/crypto/cipher/aead.c
index 1b2f921..7e747f8 100644
--- a/crypto/cipher/aead.c
+++ b/crypto/cipher/aead.c
@@ -30,6 +30,10 @@
 
 size_t EVP_AEAD_max_tag_len(const EVP_AEAD *aead) { return aead->max_tag_len; }
 
+void EVP_AEAD_CTX_zero(EVP_AEAD_CTX *ctx) {
+  memset(ctx, 0, sizeof(EVP_AEAD_CTX));
+}
+
 int EVP_AEAD_CTX_init(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead,
                       const uint8_t *key, size_t key_len, size_t tag_len,
                       ENGINE *impl) {
diff --git a/crypto/cipher/aead_test.cc b/crypto/cipher/aead_test.cc
index c9eab1c..baaee9e 100644
--- a/crypto/cipher/aead_test.cc
+++ b/crypto/cipher/aead_test.cc
@@ -22,6 +22,7 @@
 #include <openssl/err.h>
 
 #include "../test/file_test.h"
+#include "../test/scoped_types.h"
 #include "../test/stl_compat.h"
 
 
@@ -35,18 +36,6 @@
 //   CT: 5294265a60
 //   TAG: 1d45758621762e061368e68868e2f929
 
-// EVP_AEAD_CTX lacks a zero state, so it doesn't fit easily into
-// ScopedOpenSSLContext.
-class EVP_AEAD_CTXScoper {
- public:
-  EVP_AEAD_CTXScoper(EVP_AEAD_CTX *ctx) : ctx_(ctx) {}
-  ~EVP_AEAD_CTXScoper() {
-    EVP_AEAD_CTX_cleanup(ctx_);
-  }
- private:
-  EVP_AEAD_CTX *ctx_;
-};
-
 static bool TestAEAD(FileTest *t, void *arg) {
   const EVP_AEAD *aead = reinterpret_cast<const EVP_AEAD*>(arg);
 
@@ -60,20 +49,19 @@
     return false;
   }
 
-  EVP_AEAD_CTX ctx;
-  if (!EVP_AEAD_CTX_init_with_direction(&ctx, aead, bssl::vector_data(&key),
-                                        key.size(), tag.size(),
-                                        evp_aead_seal)) {
+  ScopedEVP_AEAD_CTX ctx;
+  if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead,
+                                        bssl::vector_data(&key), key.size(),
+                                        tag.size(), evp_aead_seal)) {
     t->PrintLine("Failed to init AEAD.");
     return false;
   }
-  EVP_AEAD_CTXScoper cleanup(&ctx);
 
   std::vector<uint8_t> out(in.size() + EVP_AEAD_max_overhead(aead));
   if (!t->HasAttribute("NO_SEAL")) {
     size_t out_len;
-    if (!EVP_AEAD_CTX_seal(&ctx, bssl::vector_data(&out), &out_len, out.size(),
-                           bssl::vector_data(&nonce), nonce.size(),
+    if (!EVP_AEAD_CTX_seal(ctx.get(), bssl::vector_data(&out), &out_len,
+                           out.size(), bssl::vector_data(&nonce), nonce.size(),
                            bssl::vector_data(&in), in.size(),
                            bssl::vector_data(&ad), ad.size())) {
       t->PrintLine("Failed to run AEAD.");
@@ -101,17 +89,17 @@
 
   // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
   // reset after each operation.
-  EVP_AEAD_CTX_cleanup(&ctx);
-  if (!EVP_AEAD_CTX_init_with_direction(&ctx, aead, bssl::vector_data(&key),
-                                        key.size(), tag.size(),
-                                        evp_aead_open)) {
+  ctx.Reset();
+  if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead,
+                                        bssl::vector_data(&key), key.size(),
+                                        tag.size(), evp_aead_open)) {
     t->PrintLine("Failed to init AEAD.");
     return false;
   }
 
   std::vector<uint8_t> out2(out.size());
   size_t out2_len;
-  int ret = EVP_AEAD_CTX_open(&ctx,
+  int ret = EVP_AEAD_CTX_open(ctx.get(),
                               bssl::vector_data(&out2), &out2_len, out2.size(),
                               bssl::vector_data(&nonce), nonce.size(),
                               bssl::vector_data(&out), out.size(),
@@ -137,10 +125,10 @@
 
   // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
   // reset after each operation.
-  EVP_AEAD_CTX_cleanup(&ctx);
-  if (!EVP_AEAD_CTX_init_with_direction(&ctx, aead, bssl::vector_data(&key),
-                                        key.size(), tag.size(),
-                                        evp_aead_open)) {
+  ctx.Reset();
+  if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead,
+                                        bssl::vector_data(&key), key.size(),
+                                        tag.size(), evp_aead_open)) {
     t->PrintLine("Failed to init AEAD.");
     return false;
   }
@@ -148,8 +136,8 @@
   // Garbage at the end isn't ignored.
   out.push_back(0);
   out2.resize(out.size());
-  if (EVP_AEAD_CTX_open(&ctx, bssl::vector_data(&out2), &out2_len, out2.size(),
-                        bssl::vector_data(&nonce), nonce.size(),
+  if (EVP_AEAD_CTX_open(ctx.get(), bssl::vector_data(&out2), &out2_len,
+                        out2.size(), bssl::vector_data(&nonce), nonce.size(),
                         bssl::vector_data(&out), out.size(),
                         bssl::vector_data(&ad), ad.size())) {
     t->PrintLine("Decrypted bad data with trailing garbage.");
@@ -159,10 +147,10 @@
 
   // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
   // reset after each operation.
-  EVP_AEAD_CTX_cleanup(&ctx);
-  if (!EVP_AEAD_CTX_init_with_direction(&ctx, aead, bssl::vector_data(&key),
-                                        key.size(), tag.size(),
-                                        evp_aead_open)) {
+  ctx.Reset();
+  if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead,
+                                        bssl::vector_data(&key), key.size(),
+                                        tag.size(), evp_aead_open)) {
     t->PrintLine("Failed to init AEAD.");
     return false;
   }
@@ -171,8 +159,8 @@
   out[0] ^= 0x80;
   out.resize(out.size() - 1);
   out2.resize(out.size());
-  if (EVP_AEAD_CTX_open(&ctx, bssl::vector_data(&out2), &out2_len, out2.size(),
-                        bssl::vector_data(&nonce), nonce.size(),
+  if (EVP_AEAD_CTX_open(ctx.get(), bssl::vector_data(&out2), &out2_len,
+                        out2.size(), bssl::vector_data(&nonce), nonce.size(),
                         bssl::vector_data(&out), out.size(),
                         bssl::vector_data(&ad), ad.size())) {
     t->PrintLine("Decrypted bad data with corrupted byte.");
diff --git a/crypto/test/scoped_types.h b/crypto/test/scoped_types.h
index c5c8cfe..d9eaad2 100644
--- a/crypto/test/scoped_types.h
+++ b/crypto/test/scoped_types.h
@@ -18,6 +18,7 @@
 #include <stdint.h>
 #include <stdio.h>
 
+#include <openssl/aead.h>
 #include <openssl/bio.h>
 #include <openssl/bn.h>
 #include <openssl/cmac.h>
@@ -115,6 +116,9 @@
 
 using ScopedX509Stack = ScopedOpenSSLStack<STACK_OF(X509), X509, X509_free>;
 
+using ScopedEVP_AEAD_CTX = ScopedOpenSSLContext<EVP_AEAD_CTX, void,
+                                                EVP_AEAD_CTX_zero,
+                                                EVP_AEAD_CTX_cleanup>;
 using ScopedEVP_CIPHER_CTX = ScopedOpenSSLContext<EVP_CIPHER_CTX, int,
                                                   EVP_CIPHER_CTX_init,
                                                   EVP_CIPHER_CTX_cleanup>;
diff --git a/include/openssl/aead.h b/include/openssl/aead.h
index d36cf95..f61c495 100644
--- a/include/openssl/aead.h
+++ b/include/openssl/aead.h
@@ -223,6 +223,12 @@
   evp_aead_seal,
 };
 
+/* EVP_AEAD_CTX_zero sets an uninitialized |ctx| to the zero state. It must be
+ * initialized with |EVP_AEAD_CTX_init| before use. It is safe, but not
+ * necessary, to call |EVP_AEAD_CTX_cleanup| in this state. This may be used for
+ * more uniform cleanup of |EVP_AEAD_CTX|. */
+OPENSSL_EXPORT void EVP_AEAD_CTX_zero(EVP_AEAD_CTX *ctx);
+
 /* EVP_AEAD_CTX_init initializes |ctx| for the given AEAD algorithm. The |impl|
  * argument is ignored and should be NULL. Authentication tags may be truncated
  * by passing a size as |tag_len|. A |tag_len| of zero indicates the default