external/boringssl: Sync to 7a817f48bafee508b2d23ad278f892ee1cb32b91.

Re-lands https://r.android.com/1774909

This includes the following changes:

https://boringssl.googlesource.com/boringssl/+log/ae2bb641735447496bed334c495e4868b981fe32..7a817f48bafee508b2d23ad278f892ee1cb32b91

* Add 'generate-ech' command to bssl tool
* Don't enable atomics in NO_THREADS configurations.
* Check strtoul return for overflow error in GetUnsigned()
* Add convenience functions to malloc EVP_HPKE_CTX and EVP_HPKE_KEY.
* Document that SSL_PRIVATE_KEY_METHOD should configure signing prefs.
* Always have CRYPTO_sysrand_for_seed.
* hrss: use less stack space.
* Make X509_EXTENSION opaque.
Update-Note: Use X509_EXTENSION_get_* instead.
* Make X509_CRL opaque.
Update-Note: Use accessors instead.
* Switch another malloc to bssl::Array.
* Add a pointer alignment helper function.
* Remove unused field in X509_NAME_ENTRY.
Update-Note: Removed unused field in struct.
* Fix sign bit in BN_div if numerator and quotient alias.
* Handle the server case in SSL_get0_ech_name_override.
* Remove -2 return value from X509*_get_*_by_NID.
Update-Note: The return value convention of some functions was
simplified. This is not expected to affect any callers.
* Remove X509at_get0_data_by_OBJ.
Update-Note: X509at_get0_data_by_OBJ is removed. We found no callers of
this function.
* Document a batch of extension-related functions in x509.h.
* conf: fix getting keys from the default section.
* conf: don't crash when parsing.
* Add some OpenSSL compatibility aliases.
* Make ASN1_OBJECT opaque.
Update-Note: ASN1_OBJECT is now opaque. Callers should use accessors.
* Rename asn1_locl.h to internal.h.
* Update hpke_test.go.
* Decorate x509v3_a2i_ipadd declaration as its definition.
* SHA-256 is used on AArch64, even if NO_ASM.
* swtb is another AArch64 magic tweak.
* Implement ClientHelloOuter handshakes.
* runner: Add a convenience function for base64 flags.
* Reduce bouncing on the cache lock in ssl_update_cache.
Update-Note: This reshuffles some locks around the session cache.
(Hopefully for the better.)
* Only clear not_resumable after the handshake.
* runner: Test that clients actually use renewed tickets.
* runner: Clean up test logic.
* runner: Fix process exit timeout.
* Remove old ASN.1 SET macros.
* Document some ASN1_INTEGER and ASN1_ENUMERATED functions.
* Document ASN1_STRING_to_UTF8.
* Const-correct ASN1_item_verify a bit more.
* Compute ASN.1 BIT STRING sizes more consistently.
* Remove lh_FOO_doall.
* Prefix internal LHASH functions.
* Unexport almost all of LHASH.
Update-Note: BoringSSL no longer provides a general-purpose hash table
to callers. Use the language's standard library, or another
implementation.
* Rename t1_lib.cc to extensions.cc.
* Prefix and unexport a2i_ipadd.
* Fix a -Wdeprecated-copy warning.
* Validate ECH public names.
* Fold X509_VERIFY_PARAM_ID into X509_VERIFY_PARAM.
* Make X509_VERIFY_PARAM opaque.
Update-Note: Use setters instead of configuring X509_VERIFY_PARAM
directly.
* Move crypto/x509/vpm_int.h into internal.h.
* Reformat x509_vfy.h and convert comments.
* Reland "Add util/fetch_ech_config_list.go"
* Revert "Add util/fetch_ech_config_list.go"
* Add util/fetch_ech_config_list.go
* More reliably report handshake errors through SSL_write.
* Add an option to permute ClientHello extension order.
* runner: Check the test name against the protocol being tested.
* Remove outdated comment in primality testing.
* Add most of an ECH client implementation.
* Add a basic API to make ECHConfigs.
* Make ECH server APIs take EVP_HPKE_KEY.
* Rename SSL_ECH_SERVER_CONFIG_LIST to SSL_ECH_KEYS.
* runner: Self-check tests more accurately and earlier.
* Don't pad the second ClientHello.
* Fix ext_pre_shared_key_clienthello_length calculation.
* Tidy up the PSK binder logic.
* Move the TLS vs DTLS header length adjustment into ssl_add_clienthello_tlsext.
* Shift some complexity out of ssl_add_clienthello_tlsext.
* Add a note about extension callback names.
* Add move support to EVP_MD_CTX.
* Replace hs->needs_psk_binder with an output parameter.
* Make add_clienthello callbacks const.
* Fix documentation typo.
* Compute the ECH GREASE payload outside of the callbacks.
* Pick up the GREASE ECH config ID from grease_seed.
* Initialize grease_seed on construction.
* Remove the extension init hook.
* Move key_share computation out of ClientHello callbacks.
* Release some temporaries outside of ClientHello callbacks.
* Move the early_data_{offered,reason} logic out of extension callbacks.
* Implement a handshake hint for certificate compression.
* runner: Implement ECH server for testing.
* runner: Parse the status_request extension more strictly.
* runner: Make echIsInner a boolean.
* runner: Revise ECHConfig type in preparation for client implementation
* Fix ECH-Server-RepeatedConfigID test.
* Add SSL_ech_accepted API and ech_is_required alerts.
* Reject the ECH extension in TLS 1.2 ServerHello.
* Move ECH-related APIs to encrypted_client_hello.cc.
* Const-correct message creation hooks.
* Remove the Channel ID callback.
Update-Note: SSL_CTX_set_channel_id_cb is removed.
SSL_set_tls_channel_id_enabled no longer enables Channel ID as a client,
only as a server.
* Manage Channel ID handshake state better.
Update-Note: SSL_get_tls_channel_id will no longer return all zeros
during the handshake or on the client. I did not find any callers
relying on this.
* DTLS-SRTP is only defined for DTLS.
* Remove impossible ssl->s3 null check.
* fix #415: Perl scripts fail when building from a path with spaces
* Cite an RFC over 9000 (draft-ietf-quic-tls is now RFC 9001).
Update-Note: QUIC APIs now default to the standard code point rather
than the draft one. QUICHE has already been calling
SSL_set_quic_use_legacy_codepoint, so this should not affect them. Once
callers implementing the draft versions cycle out, we can then drop
SSL_set_quic_use_legacy_codepoint altogether. I've also bumped
BORINGSSL_API_VERSION in case we end up needing an ifdef.
* Add compatibility impl for EVP_PKEY_get0
* Make md32_common.h single-included and use an unsized helper for SHA-256.
* Pull HASH_TRANSFORM out of md32_common.h.
* Ensure name not null in EVP_get_cipherbyname
* Fix array-parameter warnings
* Don't copy client's session ID into server's session.
* Test ECH server with unique and repeated config IDs.
* Refresh SSL corpora after adding ECH fuzzer mode.
* Implement fuzzer mode for ECH server.
* Don't try to write empty early data in the tool.
* GREASE is now RFC 8701.
* runner: Reject all zero client and server randoms.
* Const-correct SSL_get_srtp_profiles.
Update-Note: The change to the return type isn't quite compatible, but I
only found one caller of this function, which has since been fixed. (If
we need to return a non-const value for compatibility, we can do that
and document that the caller should not mutate the output.)
* Update the ECH GREASE size selection.
* fuzz/minimise_corpora.sh: Add shebang and chmod +x
* Add a missing case to SSL_error_description.
* Remove draft tokbind implementation.
Update-Note: Token binding APIs are removed.
* Make X509_REQ and X509_REQ_INFO opaque.
Update-Note: Callers that reach into X509_REQ and X509_REQ_INFO must use
accessors instead.
* Check hs->early_session, not ssl->session, for the early data limit.
* Fix some includes.
* Be clearer which signing inputs are digests.
* Validate RSA public keys more consistently.
Update-Note: See above.
* Add APIs to manually fill in signatures for CRLs.
* Check for resumption identifiers in SSL_SESSION_is_resumable.
* Don't use SHA256(ticket) as the signaling session ID for tickets.
* Simplify renego + resumption handling.
* Move session ID assignment out of ssl_get_new_session.
* Fix the ech_accept comment.
* Export the HPKE implementation.
* Refer to EVP_HPKE_CTX by a consistent name.
* Shift the KEM dependency in HPKE up a step.
* Update ACVP URLs.
* Add SSL_can_release_private_key.
* Make X509_SIG and X509_CERT_AUX opaque.
Update-Note: Direct access of these structs should be replaced by
accessors.
* acvp: move hash iterations into modulewrapper.
* Switch HPKE to a three-parameter output buffer.
* Introduce EVP_HPKE_{AEAD,KDF} types.
* Don't mark up the first word in a collective comment.
* Revise the deterministic for_test variant of HPKE's SetupBaseS.
* Fix a memory leak with d2i_ASN1_OBJECT object reuse.
* Remove HPKE PSK mode.
* Remove HKDF-SHA384 and HKDF-SHA512 from HPKE.
* Correctly order PKCS#7 certificates and CRLs.
Update-Note: It is no longer the case that constructing a PKCS#7 file
and parsing them back out will keep the certificates and CRLs in the
same order.
* Implement ECH draft 10 and update HPKE to draft 08.
* Document expected use of BTI and PAC macros.
* Remove non-deterministic bits from ECDSA ACVP test.
* Reference the newer ChaCha20-Poly1305 RFC.
* Use passive entropy collection everywhere.
* Rename X509V*_VERSION constants.
Update-Note: This renames some BoringSSL-specific constants that we
recently added. It doesn't look like anyone's used them yet.
* Const-correct ASN1_OBJECT_create.
* Clarify OBJ_get0_data and OBJ_get_length.
* avcp: SHA-1 for ECDSA _verification_ is still supported by NIST.
* A couple of Aarch64 FIPS delocate fixes.
* Use a placeholder for unknown errors in ERR_*_error_string.
* Include assembly optimizations in Bazel builds on Linux-aarch64.
* Remove some BoringSSL-only X509_CINF functions.
Update-Note: X509_get_cert_info, X509_CINF_set_modified, and
X509_CINF_get_signature are removed. I believe all callers have been
updated. Callers should use i2d_re_X509_tbs, i2d_X509_tbs, and
X509_get0_tbs_sigalg instead.
* Document and test X509_ATTRIBUTE creation functions.
* Revert handshaker fd numbers and make StartProcess more flexible.
* Remove support for malformed X509_ATTRIBUTEs.
Update-Note: Given OpenSSL hasn't accepted these for five years, it's
unlikely anything depends on it. If something breaks, we can revert this
and revisit. No one calls X509_ATTRIBUTE_set1_data on a non-empty
X509_ATTRIBUTE, so the behavior change there should be safe.
* Make X509_ATTRIBUTE opaque.
Update-Note: Direct accesses of X509_ATTRIBUTE should be replaced with
one of the accessors. I couldn't find any direct accesses, so hopefully
this is fine.
* acvptool: Fix typo hard-coding the HTTP method.
* Document a few more x509.h functions.
* Make X509_PUBKEY opaque.
Update-Note: Direct accesses of X509_PUBKEY should be replaced with one
of the accessors. I believe all callers have been fixed at this point.
* Always encode booleans as DER.
Update-Note: Callers setting ASN1_BOOLEANs to a positive value other
than 0xff will now encode 0xff. This probably fixes a bug, but if anyone
was attaching significance to incorrectly-encoded booleans, that will
break.
* Fix issuerUID and subjectUID parsing in the key usage checker.
* Add experimental handshake hints API.
* Make our Python scripts Python-3-compatible.
* Export ssl_client_hello_init for fuzzers.
* acvp: support GMAC as an algorithm.
* Record a fuzzing corpus for the ClientHelloInner decoder.
* Use a consistent plural for 'corpus'.
* Add util/bot/libFuzzer to .gitignore.
* acvp: support KAS-ECC-SSC staticUnified mode.
* Check for invalid ALPN inputs in SSL_(CTX_)set_alpn_protos.
Update-Note: SSL_CTX_set_alpn_protos and SSL_set_alpn_protos will now
reject invalud inputs. Previously, they would accept them, but silently
send an invalid ALPN extension which the server would almost certainly
error on.
* Don't duplicate ServerHello construction code.
* Rearrange key share and early data logic.
* Only skip early data with HRR when offered.
* Add ECH server config API to ssl_ctx_api fuzzer
* Fix ppc64le build.
* Simplify the Lucky13 mitigation.
* Add ECH server (draft-ietf-tls-esni-09).
* runner: Remove unused field
* runner: Construct finishedHash earlier.
* Simplify tls_cbc.c slightly.
* Remove remnants of CBC SHA2 cipher suites.
* runner: Test different V2ClientHello challenge lengths.
* runner: Ensure helloBytes is always the same as hello.marshal().
* runner: Fix ECH confirmation calculation with PSKs in tests.
* runner: Fix HPKE parameter order.
* runner: UpdateForHelloRetryRequest cannot fail.
* runner: Don't use the buffer in TLS 1.3.
* runner: Don't maintain two copies of the same transcript hash.
* runner: Remove remnants of SSL 3.0.
* runner: Fix writeClientHash and writeRecord ordering.
* runner: Remove CheckTLS13DowngradeRandom.
* runner: Remove remnants of the separate HelloRetryRequest message.
* runner: Store a cipherSuite in ClientSessionState.
* runner: Move writeHash to the finishedHash struct.
* Fix the spelling of HPKE AEAD constants.
* Don't reset server callback expectations on new handshake.
* Fix MockQuicTransport::Flush error handling.
* Fold ripemd/internal.h into ripemd.c.
* Move load/store helpers to crypto/internal.h.
* Make words in crypto/fipsmodule/modes actually words.
* Handle EINTR more in handshaker.cc.
* Add a few missing SSL_R_BIO_NOT_SET cases.
* Fix some unreachable code in the QUIC handshaker driver.
* Rearrange SSLKeyShare::Serialize.
* Fix ssl/internal.h sectioning.
* Remove some now unnecessary test exclusions from split handshakes.
* Remove tls13-split-handshakes flag.
* Define HANDSHAKER_SUPPORTED in once place.
* Tidy up handshaker tester.
* modulewrapper: add option to print build information.
* FIPS counters for AES-CTR.
* Enforce that pre_shared_key must come with psk_key_exchange_modes.
* Zero out FIPS counters.
* Remove is_resume field on TestState.
* Remove OPENSSL_DANGEROUS_RELEASE_PTHREAD_KEY build flag.
* Add some warnings on how to use OPENSSL_memory_* functions.
* Use an unsized helper for truncated SHA-512 variants.
Update-Note: There is a small chance the asserts will trip something,
but hopefully not since I've left SHA512_Final alone.
* Fix mismatch between header and implementation of bn_sqr_comba8.
* Remove GCC 4.8.99 check.
* Bump minimum CMake version.
* Automatically enable C11 atomics when available.
Update-Note: If something fails to compile, we'll revert this and adjust
the check, or add an opt-out, or give up. Also, if building with
-std=c99, consider -std=c11.
* Make generate_build_files.py python3 compatible.
* Remove X509_REQ_set_extension_nids and document related functions.
Update-Note: This removes a pair of unused functions.
* Document a few more functions in x509.h.
* Do not access value.ptr with V_ASN1_BOOLEAN.
* Add X509_PUBKEY_get0_public_key.
* Test empty EVP_CIPHER inputs and fix exact memcpy overlap.
* Revert "Implement rsa_pkcs1_sha256_legacy."
* Fix unnecessarily direction-specific tests in cipher_tests.txt
* Refactor HPKE API to include explicit length parameters.
* Generalize make_errors.go to allow EVP covering multiple directories.
* Add a Windows no-op impl of BORINGSSL_self_test
* Only pass -handshaker-path in split handshakes tests.
* Add RNG support for FreeBSD.
* Move fips.c into a subdirectory.
* Implement rsa_pkcs1_sha256_legacy.
* Better document nullable X.509 getters.
* runner: Remove redundant -enable-all-curves shim flag.
* Initialize nonce in PerAEADTest.ABI.
* Document ASN1_TYPE and related functions.
* fips: add counters.
* Align with OpenSSL on constness of static ASN1_OBJECTs.
Update-Note: The change to OBJ_nid2obj should be compatible. The changes
to X509_PUBKEY_set0_param and X509_ALGOR_set0 may require fixing some
pointer types.
* Add -rr-record flag to runner.go.
* Register NAME_CONSTRAINTS with bssl::UniquePtr.
* Register POLICY_MAPPING with bssl::UniquePtr.
* Stub out some more of PKCS7.
* Remove TODO to reverse the output of PKCS12_parse.
* Make the X509_VAL structure opaque.
Update-Note: I believe this is now safe to do. If there are compile
failures, switch to X509_get0_notBefore, X509_getm_notBefore, and
X509_set1_notBefore, or revert this if I'm wrong and too many callers
still need updating.
* Support creating unencrypted PKCS#12 files.
* Move PKCS#12 samples to embed_test_data.
* Remove some remnants of TLS 1.3 downgrade carveouts.
Update-Note:
https://boringssl-review.googlesource.com/c/boringssl/+/44124 made these
functions a no-op, but we kept them around because there were still some
call sites floating around. That code has since been updated, so we can
remove this.
* Remove X509_REQ_to_X509.
Update-Note: This removes a function that appears to be unused. It also
hardcodes the use of MD5, so please do not use it.
* Fix OPENSSL_EC_* constants and add EC_GROUP_get_asn1_flag
* RAND_set_rand_method returns int.
* Check the inner and outer CRL signature algorithms match.
Update-Note: Invalid CRLs with inconsistent inner and outer signature
algorithms will now be rejected.
* Remove block_mask from EVP_CIPHER_CTX.
Update-Note: It doesn't look like anyone is reading into this field. If
they are, we can ideally fix it, or revert this if absolutely necessary.
* Document a couple more functions in x509.h.
* Define X509V*_VERSION constants.
* Handle the default X.509 version explicitly.
* Compile for RISC-V.
* Add ECDSA nonce-testing functions.
* Rearrange ECDSA implementation.
* Split the FIPS mode PRNG lock in two.
* Remove legacy vs_toolchain.py environment variable.
* runner: Rename 'masterSecret' on session objects to plain 'secret'.
* Test ECDSA signing is non-deterministic.
* acvp: split ACVP modulewrapper for reuse by Trusty
* No-op CL to trigger some builds.
* Use CIPD Go packages.
* Update CMake on the bots and switch to CIPD where available.
* Future-proof vs_toolchain.py for VS2019.
* Revert "Revert "Disable check that X.509 extensions implies v3.""
* Update Clang and Go on the bots.
* Check for OBJ_nid2obj failures in X509_ATTRIBUTE_create.
* Don't overflow the output length in EVP_CipherUpdate calls.
Update-Note: Passing extremely large input lengths into EVP_CipherUpdate
will now fail. Use EVP_AEAD instead, which is size_t-based and has more
explicit output bounds.
* Remove X509_issuer_and_serial_hash.
Update-Note: No one uses this function. It had a NULL dereference in
some error cases. See CVE-2021-23841.
* Fix Bazel build breakage.
* Specify VS toolchain by command-line argument.
* Update Android Bazel build support in BUILD.toplevel.
* Honor SSL_TLSEXT_ERR_ALERT_FATAL in the ALPN callback.
Update-Note: Callers that return SSL_TLSEXT_ERR_ALERT_FATAL from the
ALPN callback will change behavior. The old behavior may be restored by
returning SSL_TLSEXT_ERR_NOACK, though see the documentation for new
recommendations on return values.
* acvp: detect header element in JSON.
* Align the ARM capability functions.
* Skip runtime NEON checks if __ARM_NEON is defined.
Update-Note: Builds with __ARM_NEON (-mfpu=neon) will now drop about
30KiB of dead code, but no longer work (if they even did before) on a
particular buggy CPU. Builds without __ARM_NEON are not affected.
* acvp: don't include CMAC-AES in regcap dump.
* acvp: fix CMAC verify
* Include bn/internal.h for non-bcm.c builds.
* Add various function calls to test_fips.
* Add missing include to self_check.c.
* Revert "Disable check that X.509 extensions implies v3."
* Fix TLS13SessionID-TLS13 test.

Test: atest CtsLibcoreTestCases CtsLibcoreOkHttpTestCases
Change-Id: Idb0a37fccba5d1c3f6a40fe91a81c5189170ed23
diff --git a/src/ssl/handshake_server.cc b/src/ssl/handshake_server.cc
index bc0a0d1..c8a23a1 100644
--- a/src/ssl/handshake_server.cc
+++ b/src/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>
@@ -563,7 +565,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 +583,116 @@
     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.
+    uint8_t config_id;
+    uint16_t kdf_id, aead_id;
+    CBS enc, payload;
+    if (!CBS_get_u16(&ech_body, &kdf_id) ||  //
+        !CBS_get_u16(&ech_body, &aead_id) ||
+        !CBS_get_u8(&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_keys = UpRef(ssl->ctx->ech_keys);
+    }
+
+    if (hs->ech_keys) {
+      for (const auto &config : hs->ech_keys->configs) {
+        hs->ech_hpke_ctx.Reset();
+        if (config_id != config->ech_config().config_id ||
+            !config->SetupContext(hs->ech_hpke_ctx.get(), kdf_id, aead_id,
+                                  enc)) {
+          // 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_config_id = config_id;
+        ssl->s3->ech_status = ssl_ech_accepted;
+        break;
+      }
+    }
+
+    // If we did not accept ECH, proceed with the ClientHelloOuter. Note this
+    // could be key mismatch or ECH GREASE, so we most complete the handshake
+    // as usual, except EncryptedExtensions will contain retry configs.
+    if (ssl->s3->ech_status != ssl_ech_accepted) {
+      ssl->s3->ech_status = ssl_ech_rejected;
+    }
+  }
+
   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 +720,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 +764,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 +803,22 @@
     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(ssl->s3->ech_status != ssl_ech_accepted);
+
+  // TODO(davidben): Also compute hints for TLS 1.2. When doing so, update the
+  // check in bssl_shim.cc to test this.
+  if (hs->hints_requested) {
+    return ssl_hs_hints_ready;
+  }
+
   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,10 +857,15 @@
   }
 
   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;
   }
 
+  hs->session_id_len = client_hello.session_id_len;
+  // This is checked in |ssl_client_hello_init|.
+  assert(hs->session_id_len <= sizeof(hs->session_id));
+  OPENSSL_memcpy(hs->session_id, client_hello.session_id, hs->session_id_len);
+
   // Determine whether we are doing session resumption.
   UniquePtr<SSL_SESSION> session;
   bool tickets_supported = false, renew_ticket = false;
@@ -778,16 +897,20 @@
     hs->ticket_expected = renew_ticket;
     ssl->session = std::move(session);
     ssl->s3->session_reused = true;
+    hs->can_release_private_key = true;
   } else {
     hs->ticket_expected = tickets_supported;
-    ssl_set_session(ssl, NULL);
-    if (!ssl_get_new_session(hs, 1 /* server */)) {
+    ssl_set_session(ssl, nullptr);
+    if (!ssl_get_new_session(hs)) {
       return ssl_hs_error;
     }
 
-    // Clear the session ID if we want the session to be single-use.
-    if (!(ssl->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)) {
-      hs->new_session->session_id_length = 0;
+    // Assign a session ID if not using session tickets.
+    if (!hs->ticket_expected &&
+        (ssl->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)) {
+      hs->new_session->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
+      RAND_bytes(hs->new_session->session_id,
+                 hs->new_session->session_id_length);
     }
   }
 
@@ -806,7 +929,7 @@
     hs->cert_request = !!(hs->config->verify_mode & SSL_VERIFY_PEER);
     // Only request a certificate if Channel ID isn't negotiated.
     if ((hs->config->verify_mode & SSL_VERIFY_PEER_IF_NO_OBC) &&
-        ssl->s3->channel_id_valid) {
+        hs->channel_id_negotiated) {
       hs->cert_request = false;
     }
     // CertificateRequest may only be sent in certificate-based ciphers.
@@ -860,9 +983,9 @@
 
   // We only accept ChannelIDs on connections with ECDHE in order to avoid a
   // known attack while we fix ChannelID itself.
-  if (ssl->s3->channel_id_valid &&
+  if (hs->channel_id_negotiated &&
       (hs->new_cipher->algorithm_mkey & SSL_kECDHE) == 0) {
-    ssl->s3->channel_id_valid = false;
+    hs->channel_id_negotiated = false;
   }
 
   // If this is a resumption and the original handshake didn't support
@@ -870,7 +993,7 @@
   // session and so cannot resume with ChannelIDs.
   if (ssl->session != NULL &&
       ssl->session->original_handshake_hash_len == 0) {
-    ssl->s3->channel_id_valid = false;
+    hs->channel_id_negotiated = false;
   }
 
   struct OPENSSL_timeval now;
@@ -901,19 +1024,22 @@
     }
   }
 
-  const SSL_SESSION *session = hs->new_session.get();
+  Span<const uint8_t> session_id;
   if (ssl->session != nullptr) {
-    session = ssl->session.get();
+    // Echo the session ID from the ClientHello to indicate resumption.
+    session_id = MakeConstSpan(hs->session_id, hs->session_id_len);
+  } else {
+    session_id = MakeConstSpan(hs->new_session->session_id,
+                               hs->new_session->session_id_length);
   }
 
   ScopedCBB cbb;
-  CBB body, session_id;
+  CBB body, session_id_bytes;
   if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_SERVER_HELLO) ||
       !CBB_add_u16(&body, ssl->version) ||
       !CBB_add_bytes(&body, ssl->s3->server_random, SSL3_RANDOM_SIZE) ||
-      !CBB_add_u8_length_prefixed(&body, &session_id) ||
-      !CBB_add_bytes(&session_id, session->session_id,
-                     session->session_id_length) ||
+      !CBB_add_u8_length_prefixed(&body, &session_id_bytes) ||
+      !CBB_add_bytes(&session_id_bytes, session_id.data(), session_id.size()) ||
       !CBB_add_u16(&body, SSL_CIPHER_get_protocol_id(hs->new_cipher)) ||
       !CBB_add_u8(&body, 0 /* no compression */) ||
       !ssl_add_serverhello_tlsext(hs, &body) ||
@@ -1083,6 +1209,7 @@
     }
   }
 
+  hs->can_release_private_key = true;
   if (!ssl_add_message_cbb(ssl, cbb.get())) {
     return ssl_hs_error;
   }
@@ -1415,6 +1542,7 @@
   }
   hs->new_session->extended_master_secret = hs->extended_master_secret;
   CONSTTIME_DECLASSIFY(hs->new_session->secret, hs->new_session->secret_length);
+  hs->can_release_private_key = true;
 
   ssl->method->next_message(ssl);
   hs->state = state12_read_client_certificate_verify;
@@ -1556,7 +1684,7 @@
 static enum ssl_hs_wait_t do_read_channel_id(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
 
-  if (!ssl->s3->channel_id_valid) {
+  if (!hs->channel_id_negotiated) {
     hs->state = state12_read_client_finished;
     return ssl_hs_ok;
   }
@@ -1666,16 +1794,21 @@
     ssl->ctx->x509_method->session_clear(hs->new_session.get());
   }
 
-  if (ssl->session != NULL) {
-    ssl->s3->established_session = UpRef(ssl->session);
-  } else {
+  bool has_new_session = hs->new_session != nullptr;
+  if (has_new_session) {
+    assert(ssl->session == nullptr);
     ssl->s3->established_session = std::move(hs->new_session);
     ssl->s3->established_session->not_resumable = false;
+  } else {
+    assert(ssl->session != nullptr);
+    ssl->s3->established_session = UpRef(ssl->session);
   }
 
   hs->handshake_finalized = true;
   ssl->s3->initial_handshake_complete = true;
-  ssl_update_cache(hs, SSL_SESS_CACHE_SERVER);
+  if (has_new_session) {
+    ssl_update_cache(ssl);
+  }
 
   hs->state = state12_done;
   return ssl_hs_ok;
@@ -1693,6 +1826,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 +1909,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: