Add ECH server (draft-ietf-tls-esni-09).

This CL adds an initial implementation of the ECH server, with pieces of
the client in BoGo as necessary for testing. In particular, the server
supports ClientHelloInner compression with ech_outer_extensions. When
ECH decryption fails, it can send retry_configs back to the client.

This server passes the "ech-accept" and "ech-reject" test cases in
tls-interop-runner[0] when tested against both the cloudflare-go and nss
clients. For reproducibility, I started with the main branch at commit
707604c262d8bcf3e944ed1d5a675077304732ce and updated the endpoint's
script to pass the server's ECHConfig and private key to the boringssl
tool.

Follow-up CLs will update HPKE to the latest draft and catch us up to
draft-10.

[0]: https://github.com/xvzcf/tls-interop-runner

Bug: 275
Change-Id: I49be35af46d1fd5dd9c62252f07d0bae179381ab
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/45285
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/ssl/handshake_server.cc b/ssl/handshake_server.cc
index bc0a0d1..1c5f0cf 100644
--- a/ssl/handshake_server.cc
+++ b/ssl/handshake_server.cc
@@ -154,6 +154,8 @@
 #include <openssl/bn.h>
 #include <openssl/bytestring.h>
 #include <openssl/cipher.h>
+#include <openssl/curve25519.h>
+#include <openssl/digest.h>
 #include <openssl/ec.h>
 #include <openssl/ecdsa.h>
 #include <openssl/err.h>
@@ -167,6 +169,7 @@
 
 #include "internal.h"
 #include "../crypto/internal.h"
+#include "../crypto/hpke/internal.h"
 
 
 BSSL_NAMESPACE_BEGIN
@@ -563,7 +566,7 @@
   }
 
   SSL_CLIENT_HELLO client_hello;
-  if (!ssl_client_hello_init(ssl, &client_hello, msg)) {
+  if (!ssl_client_hello_init(ssl, &client_hello, msg.body)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
     return ssl_hs_error;
@@ -581,12 +584,137 @@
     return ssl_hs_handoff;
   }
 
+  // If the ClientHello contains an encrypted_client_hello extension (and no
+  // ech_is_inner extension), act as a client-facing server and attempt to
+  // decrypt the ClientHelloInner.
+  CBS ech_body;
+  if (ssl_client_hello_get_extension(&client_hello, &ech_body,
+                                      TLSEXT_TYPE_encrypted_client_hello)) {
+    CBS unused;
+    if (ssl_client_hello_get_extension(&client_hello, &unused,
+                                       TLSEXT_TYPE_ech_is_inner)) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+      ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+      return ssl_hs_error;
+    }
+
+    // Parse a ClientECH out of the extension body.
+    uint16_t kdf_id, aead_id;
+    CBS config_id, enc, payload;
+    if (!CBS_get_u16(&ech_body, &kdf_id) ||  //
+        !CBS_get_u16(&ech_body, &aead_id) ||
+        !CBS_get_u8_length_prefixed(&ech_body, &config_id) ||
+        !CBS_get_u16_length_prefixed(&ech_body, &enc) ||
+        !CBS_get_u16_length_prefixed(&ech_body, &payload) ||
+        CBS_len(&ech_body) != 0) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+      ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+      return ssl_hs_error;
+    }
+
+    {
+      MutexReadLock lock(&ssl->ctx->lock);
+      hs->ech_server_config_list = UpRef(ssl->ctx->ech_server_config_list);
+    }
+
+    if (hs->ech_server_config_list) {
+      for (const ECHServerConfig &ech_config :
+           hs->ech_server_config_list->configs) {
+        // Skip this config if the client-provided config_id does not match or
+        // if the client indicated an unsupported HPKE ciphersuite.
+        if (config_id != ech_config.config_id_sha256() ||
+            !ech_config.SupportsCipherSuite(kdf_id, aead_id)) {
+          continue;
+        }
+
+        static const uint8_t kInfoLabel[] = "tls ech";
+        ScopedCBB info_cbb;
+        if (!CBB_init(info_cbb.get(),
+                      sizeof(kInfoLabel) + ech_config.raw().size()) ||
+            !CBB_add_bytes(info_cbb.get(), kInfoLabel,
+                           sizeof(kInfoLabel) /* includes trailing NUL */) ||
+            !CBB_add_bytes(info_cbb.get(), ech_config.raw().data(),
+                           ech_config.raw().size())) {
+          OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+          return ssl_hs_error;
+        }
+
+        // Set up a fresh HPKE context for each decryption attempt.
+        hs->ech_hpke_ctx.Reset();
+
+        if (CBS_len(&enc) != X25519_PUBLIC_VALUE_LEN ||
+            !EVP_HPKE_CTX_setup_base_r_x25519(
+                hs->ech_hpke_ctx.get(), kdf_id, aead_id, CBS_data(&enc),
+                CBS_len(&enc), ech_config.public_key().data(),
+                ech_config.public_key().size(), ech_config.private_key().data(),
+                ech_config.private_key().size(), CBB_data(info_cbb.get()),
+                CBB_len(info_cbb.get()))) {
+          // Ignore the error and try another ECHConfig.
+          ERR_clear_error();
+          continue;
+        }
+        Array<uint8_t> encoded_client_hello_inner;
+        bool is_decrypt_error;
+        if (!ssl_client_hello_decrypt(hs->ech_hpke_ctx.get(),
+                                      &encoded_client_hello_inner,
+                                      &is_decrypt_error, &client_hello, kdf_id,
+                                      aead_id, config_id, enc, payload)) {
+          if (is_decrypt_error) {
+            // Ignore the error and try another ECHConfig.
+            ERR_clear_error();
+            continue;
+          }
+          OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED);
+          return ssl_hs_error;
+        }
+
+        // Recover the ClientHelloInner from the EncodedClientHelloInner.
+        uint8_t alert = SSL_AD_DECODE_ERROR;
+        bssl::Array<uint8_t> client_hello_inner;
+        if (!ssl_decode_client_hello_inner(ssl, &alert, &client_hello_inner,
+                                           encoded_client_hello_inner,
+                                           &client_hello)) {
+          ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
+          OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+          return ssl_hs_error;
+        }
+        hs->ech_client_hello_buf = std::move(client_hello_inner);
+
+        // Load the ClientHelloInner into |client_hello|.
+        if (!hs->GetClientHello(&msg, &client_hello)) {
+          OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+          return ssl_hs_error;
+        }
+
+        hs->ech_accept = true;
+        break;
+      }
+    }
+
+    // If we did not set |hs->ech_accept| to true, we will send the current
+    // ECHConfigs as retry_configs in the ServerHello's encrypted extensions.
+    // Proceed with the ClientHelloOuter.
+  }
+
   uint8_t alert = SSL_AD_DECODE_ERROR;
   if (!extract_sni(hs, &alert, &client_hello)) {
     ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
     return ssl_hs_error;
   }
 
+  hs->state = state12_read_client_hello_after_ech;
+  return ssl_hs_ok;
+}
+
+static enum ssl_hs_wait_t do_read_client_hello_after_ech(SSL_HANDSHAKE *hs) {
+  SSL *const ssl = hs->ssl;
+
+  SSLMessage msg_unused;
+  SSL_CLIENT_HELLO client_hello;
+  if (!hs->GetClientHello(&msg_unused, &client_hello)) {
+    return ssl_hs_error;
+  }
+
   // Run the early callback.
   if (ssl->ctx->select_certificate_cb != NULL) {
     switch (ssl->ctx->select_certificate_cb(&client_hello)) {
@@ -614,6 +742,7 @@
     hs->apply_jdk11_workaround = true;
   }
 
+  uint8_t alert = SSL_AD_DECODE_ERROR;
   if (!negotiate_version(hs, &alert, &client_hello)) {
     ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
     return ssl_hs_error;
@@ -657,11 +786,6 @@
 static enum ssl_hs_wait_t do_select_certificate(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
 
-  SSLMessage msg;
-  if (!ssl->method->get_message(ssl, &msg)) {
-    return ssl_hs_read_message;
-  }
-
   // Call |cert_cb| to update server certificates if required.
   if (hs->config->cert->cert_cb != NULL) {
     int rv = hs->config->cert->cert_cb(ssl, hs->config->cert->cert_cb_arg);
@@ -701,10 +825,16 @@
     return ssl_hs_ok;
   }
 
+  // It should not be possible to negotiate TLS 1.2 with ECH. The
+  // ClientHelloInner decoding function rejects ClientHellos which offer TLS 1.2
+  // or below.
+  assert(!hs->ech_accept);
+
   ssl->s3->early_data_reason = ssl_early_data_protocol_version;
 
+  SSLMessage msg_unused;
   SSL_CLIENT_HELLO client_hello;
-  if (!ssl_client_hello_init(ssl, &client_hello, msg)) {
+  if (!hs->GetClientHello(&msg_unused, &client_hello)) {
     return ssl_hs_error;
   }
 
@@ -743,7 +873,7 @@
   }
 
   SSL_CLIENT_HELLO client_hello;
-  if (!ssl_client_hello_init(ssl, &client_hello, msg)) {
+  if (!ssl_client_hello_init(ssl, &client_hello, msg.body)) {
     return ssl_hs_error;
   }
 
@@ -1693,6 +1823,9 @@
       case state12_read_client_hello:
         ret = do_read_client_hello(hs);
         break;
+      case state12_read_client_hello_after_ech:
+        ret = do_read_client_hello_after_ech(hs);
+        break;
       case state12_select_certificate:
         ret = do_select_certificate(hs);
         break;
@@ -1773,6 +1906,8 @@
       return "TLS server start_accept";
     case state12_read_client_hello:
       return "TLS server read_client_hello";
+    case state12_read_client_hello_after_ech:
+      return "TLS server read_client_hello_after_ech";
     case state12_select_certificate:
       return "TLS server select_certificate";
     case state12_tls13: