Add move support to EVP_MD_CTX.

We'll need to maintain two transcripts on the ECH client and then, once
we know which of ClientHelloOuter or ClientHelloInner is used, overwrite
the default transcript with the alternate one.

Rather than indirect through a pointer, move support is easy enough.
Then this can just be hs->transcript = std::move(hs->inner_transcript).

Bug: 275
Change-Id: Id4b0a0a48b956cd65ce8fc3dacfd16eebe2eb778
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/47993
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/digest_extra/digest_test.cc b/crypto/digest_extra/digest_test.cc
index 80b5106..12858e2 100644
--- a/crypto/digest_extra/digest_test.cc
+++ b/crypto/digest_extra/digest_test.cc
@@ -163,7 +163,7 @@
   bssl::ScopedEVP_MD_CTX ctx;
 
   // Test the input provided.
-  ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), NULL));
+  ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), nullptr));
   for (size_t i = 0; i < test->repeat; i++) {
     ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), test->input, strlen(test->input)));
   }
@@ -173,8 +173,8 @@
   CompareDigest(test, digest.get(), digest_len);
 
   // Test the input one character at a time.
-  ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), NULL));
-  ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), NULL, 0));
+  ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), nullptr));
+  ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), nullptr, 0));
   for (size_t i = 0; i < test->repeat; i++) {
     for (const char *p = test->input; *p; p++) {
       ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), p, 1));
@@ -185,7 +185,7 @@
   CompareDigest(test, digest.get(), digest_len);
 
   // Test with unaligned input.
-  ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), NULL));
+  ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), nullptr));
   std::vector<char> unaligned(strlen(test->input) + 1);
   char *ptr = unaligned.data();
   if ((reinterpret_cast<uintptr_t>(ptr) & 1) == 0) {
@@ -199,7 +199,7 @@
   CompareDigest(test, digest.get(), digest_len);
 
   // Make a copy of the digest in the initial state.
-  ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), NULL));
+  ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), nullptr));
   bssl::ScopedEVP_MD_CTX copy;
   ASSERT_TRUE(EVP_MD_CTX_copy_ex(copy.get(), ctx.get()));
   for (size_t i = 0; i < test->repeat; i++) {
@@ -220,6 +220,27 @@
   ASSERT_TRUE(EVP_DigestFinal_ex(copy.get(), digest.get(), &digest_len));
   CompareDigest(test, digest.get(), digest_len);
 
+  // Move the digest from the initial state.
+  ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), nullptr));
+  copy = std::move(ctx);
+  for (size_t i = 0; i < test->repeat; i++) {
+    ASSERT_TRUE(EVP_DigestUpdate(copy.get(), test->input, strlen(test->input)));
+  }
+  ASSERT_TRUE(EVP_DigestFinal_ex(copy.get(), digest.get(), &digest_len));
+  CompareDigest(test, digest.get(), digest_len);
+
+  // Move the digest with half the input provided.
+  ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), nullptr));
+  ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), test->input, half));
+  copy = std::move(ctx);
+  ASSERT_TRUE(EVP_DigestUpdate(copy.get(), test->input + half,
+                               strlen(test->input) - half));
+  for (size_t i = 1; i < test->repeat; i++) {
+    ASSERT_TRUE(EVP_DigestUpdate(copy.get(), test->input, strlen(test->input)));
+  }
+  ASSERT_TRUE(EVP_DigestFinal_ex(copy.get(), digest.get(), &digest_len));
+  CompareDigest(test, digest.get(), digest_len);
+
   // Test the one-shot function.
   if (test->md.one_shot_func && test->repeat == 1) {
     uint8_t *out = test->md.one_shot_func((const uint8_t *)test->input,
diff --git a/crypto/fipsmodule/digest/digest.c b/crypto/fipsmodule/digest/digest.c
index 6b0c198..d893cbc 100644
--- a/crypto/fipsmodule/digest/digest.c
+++ b/crypto/fipsmodule/digest/digest.c
@@ -177,6 +177,13 @@
   return 1;
 }
 
+void EVP_MD_CTX_move(EVP_MD_CTX *out, EVP_MD_CTX *in) {
+  EVP_MD_CTX_cleanup(out);
+  // While not guaranteed, |EVP_MD_CTX| is currently safe to move with |memcpy|.
+  OPENSSL_memcpy(out, in, sizeof(EVP_MD_CTX));
+  EVP_MD_CTX_init(in);
+}
+
 int EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in) {
   EVP_MD_CTX_init(out);
   return EVP_MD_CTX_copy_ex(out, in);
diff --git a/include/openssl/base.h b/include/openssl/base.h
index 66d0493..d37c202 100644
--- a/include/openssl/base.h
+++ b/include/openssl/base.h
@@ -537,8 +537,39 @@
   StackAllocated() { init(&ctx_); }
   ~StackAllocated() { cleanup(&ctx_); }
 
-  StackAllocated(const StackAllocated<T, CleanupRet, init, cleanup> &) = delete;
-  T& operator=(const StackAllocated<T, CleanupRet, init, cleanup> &) = delete;
+  StackAllocated(const StackAllocated &) = delete;
+  StackAllocated& operator=(const StackAllocated &) = delete;
+
+  T *get() { return &ctx_; }
+  const T *get() const { return &ctx_; }
+
+  T *operator->() { return &ctx_; }
+  const T *operator->() const { return &ctx_; }
+
+  void Reset() {
+    cleanup(&ctx_);
+    init(&ctx_);
+  }
+
+ private:
+  T ctx_;
+};
+
+template <typename T, typename CleanupRet, void (*init)(T *),
+          CleanupRet (*cleanup)(T *), void (*move)(T *, T *)>
+class StackAllocatedMovable {
+ public:
+  StackAllocatedMovable() { init(&ctx_); }
+  ~StackAllocatedMovable() { cleanup(&ctx_); }
+
+  StackAllocatedMovable(StackAllocatedMovable &&other) {
+    init(&ctx_);
+    move(&ctx_, &other.ctx_);
+  }
+  StackAllocatedMovable &operator=(StackAllocatedMovable &&other) {
+    move(&ctx_, &other.ctx_);
+    return *this;
+  }
 
   T *get() { return &ctx_; }
   const T *get() const { return &ctx_; }
diff --git a/include/openssl/digest.h b/include/openssl/digest.h
index 66f1b5d..12542c1 100644
--- a/include/openssl/digest.h
+++ b/include/openssl/digest.h
@@ -124,6 +124,10 @@
 // copy of |in|. It returns one on success and zero on allocation failure.
 OPENSSL_EXPORT int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in);
 
+// EVP_MD_CTX_move sets |out|, which must already be initialised, to the hash
+// state in |in|. |in| is mutated and left in an empty state.
+OPENSSL_EXPORT void EVP_MD_CTX_move(EVP_MD_CTX *out, EVP_MD_CTX *in);
+
 // EVP_MD_CTX_reset calls |EVP_MD_CTX_cleanup| followed by |EVP_MD_CTX_init|. It
 // returns one.
 OPENSSL_EXPORT int EVP_MD_CTX_reset(EVP_MD_CTX *ctx);
@@ -324,8 +328,8 @@
 BORINGSSL_MAKE_DELETER(EVP_MD_CTX, EVP_MD_CTX_free)
 
 using ScopedEVP_MD_CTX =
-    internal::StackAllocated<EVP_MD_CTX, int, EVP_MD_CTX_init,
-                             EVP_MD_CTX_cleanup>;
+    internal::StackAllocatedMovable<EVP_MD_CTX, int, EVP_MD_CTX_init,
+                                    EVP_MD_CTX_cleanup, EVP_MD_CTX_move>;
 
 BSSL_NAMESPACE_END