dispose of ECH AEAD context during handshake, decryption failure of inner CH in 2nd CH is fatal
diff --git a/lib/picotls.c b/lib/picotls.c
index 45d6038..d671baf 100644
--- a/lib/picotls.c
+++ b/lib/picotls.c
@@ -171,11 +171,12 @@
  * Properties for ECH. Iff ECH is used and not rejected, `aead` is non-NULL.
  */
 struct st_ptls_ech_t {
-    ptls_aead_context_t *aead;
     uint8_t offered : 1;
+    uint8_t accepted : 1;
     uint8_t config_id;
     ptls_hpke_kem_t *kem;
     ptls_hpke_cipher_suite_t *cipher;
+    ptls_aead_context_t *aead;
     uint8_t inner_client_random[PTLS_HELLO_RANDOM_SIZE];
     struct {
         ptls_iovec_t enc;
@@ -2643,9 +2644,9 @@
         if ((ret = ech_calc_confirmation(tls->key_schedule, confirm_hash_expected, tls->ech.inner_client_random, label, message)) !=
             0)
             goto Exit;
-        int ech_accepted = ptls_mem_equal(confirm_hash_delivered, confirm_hash_expected, sizeof(confirm_hash_delivered));
+        tls->ech.accepted = ptls_mem_equal(confirm_hash_delivered, confirm_hash_expected, sizeof(confirm_hash_delivered));
         memcpy(message.base + confirm_hash_off, confirm_hash_delivered, sizeof(confirm_hash_delivered));
-        if (ech_accepted)
+        if (tls->ech.accepted)
             goto Exit;
     }
 
@@ -2690,12 +2691,17 @@
                                           tls->client.offered_psk && !tls->is_psk_handshake)) != 0)
         goto Exit;
 
-    /* check if ECH is accepted (at the same time rolling the hash) */
+    /* check if ECH is accepted, then free ECH AEAD */
     static const size_t confirm_hash_off =
         PTLS_HANDSHAKE_HEADER_SIZE + 2 /* legacy_version */ + PTLS_HELLO_RANDOM_SIZE - PTLS_ECH_CONFIRM_LENGTH;
-    if (tls->ech.aead != NULL &&
-        (ret = client_ech_select_hello(tls, message, confirm_hash_off, ECH_CONFIRMATION_SERVER_HELLO)) != 0)
-        goto Exit;
+    if (tls->ech.aead != NULL) {
+        if ((ret = client_ech_select_hello(tls, message, confirm_hash_off, ECH_CONFIRMATION_SERVER_HELLO)) != 0)
+            goto Exit;
+        if (tls->ech.aead != NULL) {
+            ptls_aead_free(tls->ech.aead);
+            tls->ech.aead = NULL;
+        }
+    }
 
     ptls__key_schedule_update_hash(tls->key_schedule, message.base, message.len, 0);
 
@@ -4167,6 +4173,7 @@
             memset(ech.ch_outer_aad + (ch->ech.payload.base - (message.base + PTLS_HANDSHAKE_HEADER_SIZE)), 0, ch->ech.payload.len);
             if (ptls_aead_decrypt(tls->ech.aead, ech.encoded_ch_inner, ch->ech.payload.base, ch->ech.payload.len, is_second_flight,
                                   ech.ch_outer_aad, message.len - PTLS_HANDSHAKE_HEADER_SIZE) != SIZE_MAX) {
+                tls->ech.accepted = 1;
                 /* successfully decrypted EncodedCHInner, build CHInner */
                 if ((ret = rebuild_ch_inner(&ech.ch_inner, ech.encoded_ch_inner,
                                             ech.encoded_ch_inner + ch->ech.payload.len - tls->ech.aead->algo->tag_size, ch,
@@ -4184,8 +4191,12 @@
                     goto Exit;
                 if (!is_second_flight)
                     memcpy(tls->ech.inner_client_random, ch->random_bytes, PTLS_HELLO_RANDOM_SIZE);
+            } else if (is_second_flight) {
+                /* decryption failure of inner CH in 2nd CH is fatal */
+                ret = PTLS_ALERT_DECRYPT_ERROR;
+                goto Exit;
             } else {
-                /* decryption failure indicates key mismatch; dispose of AEAD context to indicate that outerCH is adopted */
+                /* decryption failure of 1st CH indicates key mismatch; dispose of AEAD context to indicate adoption of outerCH */
                 ptls_aead_free(tls->ech.aead);
                 tls->ech.aead = NULL;
             }
@@ -4378,6 +4389,12 @@
         }
     }
 
+    /* dispose of ECH AEAD state now that processing of ECH is complete */
+    if (tls->ech.aead != NULL) {
+        ptls_aead_free(tls->ech.aead);
+        tls->ech.aead = NULL;
+    }
+
     /* handle unknown extensions */
     if ((ret = report_unknown_extensions(tls, properties, ch->unknown_extensions)) != 0)
         goto Exit;
@@ -5139,7 +5156,7 @@
 
 int ptls_is_ech_handshake(ptls_t *tls, ptls_hpke_kem_t **kem, ptls_hpke_cipher_suite_t **cipher)
 {
-    if (tls->ech.aead != NULL) {
+    if (tls->ech.accepted) {
         if (kem != NULL)
             *kem = tls->ech.kem;
         if (cipher != NULL)