move ECH-related setup code to util.h so that they can be used from quicly/cli
diff --git a/t/cli.c b/t/cli.c
index 73cea1f..67bfd4d 100644
--- a/t/cli.c
+++ b/t/cli.c
@@ -57,21 +57,6 @@
 /* sentinels indicating that the endpoint is in benchmark mode */
 static const char input_file_is_benchmark[] = "is:benchmark";
 
-static struct {
-    ptls_iovec_t config_list;
-    struct {
-        struct {
-            ptls_hpke_kem_t *kem;
-            ptls_key_exchange_context_t *ctx;
-        } list[16];
-        size_t count;
-    } keyex;
-    struct {
-        ptls_iovec_t configs;
-        char *fn;
-    } retry;
-} ech;
-
 static ptls_hpke_kem_t *find_kem(ptls_key_exchange_algorithm_t *algo)
 {
     for (size_t i = 0; ptls_openssl_hpke_kems[i] != NULL; ++i)
@@ -82,79 +67,6 @@
     return NULL;
 }
 
-static ptls_aead_context_t *create_ech_opener(ptls_ech_create_opener_t *self, ptls_hpke_kem_t **kem,
-                                              ptls_hpke_cipher_suite_t **cipher, ptls_t *tls, uint8_t config_id,
-                                              ptls_hpke_cipher_suite_id_t cipher_id, ptls_iovec_t enc, ptls_iovec_t info_prefix)
-{
-    const uint8_t *src = ech.config_list.base, *const end = src + ech.config_list.len;
-    size_t index = 0;
-    int ret = 0;
-
-    /* look for the cipher implementation; this should better be specific to each ECHConfig (as each of them may advertise different
-     * set of values) */
-    *cipher = NULL;
-    for (size_t i = 0; ptls_openssl_hpke_cipher_suites[i] != NULL; ++i) {
-        if (ptls_openssl_hpke_cipher_suites[i]->id.kdf == cipher_id.kdf &&
-            ptls_openssl_hpke_cipher_suites[i]->id.aead == cipher_id.aead) {
-            *cipher = ptls_openssl_hpke_cipher_suites[i];
-            break;
-        }
-    }
-    if (*cipher == NULL)
-        goto Exit;
-
-    ptls_decode_open_block(src, end, 2, {
-        uint16_t version;
-        if ((ret = ptls_decode16(&version, &src, end)) != 0)
-            goto Exit;
-        do {
-            ptls_decode_open_block(src, end, 2, {
-                if (src == end) {
-                    ret = PTLS_ALERT_DECODE_ERROR;
-                    goto Exit;
-                }
-                if (*src == config_id) {
-                    /* this is the ECHConfig that we have been looking for */
-                    if (index >= ech.keyex.count) {
-                        fprintf(stderr, "ECH key missing for config %zu\n", index);
-                        return NULL;
-                    }
-                    uint8_t *info = malloc(info_prefix.len + end - (src - 4));
-                    memcpy(info, info_prefix.base, info_prefix.len);
-                    memcpy(info + info_prefix.len, src - 4, end - (src - 4));
-                    ptls_aead_context_t *aead;
-                    ptls_hpke_setup_base_r(ech.keyex.list[index].kem, *cipher, ech.keyex.list[index].ctx, &aead, enc,
-                                           ptls_iovec_init(info, info_prefix.len + end - (src - 4)));
-                    free(info);
-                    *kem = ech.keyex.list[index].kem;
-                    return aead;
-                }
-                ++index;
-                src = end;
-            });
-        } while (src != end);
-    });
-
-Exit:
-    if (ret != 0)
-        fprintf(stderr, "ECH decode error:%d\n", ret);
-    return NULL;
-}
-
-static void ech_save_retry_configs(void)
-{
-    if (ech.retry.configs.base == NULL)
-        return;
-
-    FILE *fp;
-    if ((fp = fopen(ech.retry.fn, "wt")) == NULL) {
-        fprintf(stderr, "failed to write to ECH config file:%s:%s\n", ech.retry.fn, strerror(errno));
-        exit(1);
-    }
-    fwrite(ech.retry.configs.base, 1, ech.retry.configs.len, fp);
-    fclose(fp);
-}
-
 static void shift_buffer(ptls_buffer_t *buf, size_t delta)
 {
     if (delta != 0) {
@@ -528,7 +440,6 @@
 
     ptls_key_exchange_algorithm_t *key_exchanges[128] = {NULL};
     ptls_cipher_suite_t *cipher_suites[128] = {NULL};
-    ptls_ech_create_opener_t ech_opener = {.cb = create_ech_opener};
     ptls_context_t ctx = {
         .random_bytes = ptls_openssl_random_bytes,
         .get_time = &ptls_get_time,
@@ -602,42 +513,12 @@
         case 'S':
             ctx.require_dhe_on_psk = 1;
             break;
-        case 'E': {
-            FILE *fp;
-            if ((fp = fopen(optarg, "rt")) == NULL) {
-                fprintf(stderr, "failed to open ECHConfigList file:%s:%s\n", optarg, strerror(errno));
-                return 1;
-            }
-            ech.config_list.base = malloc(65536);
-            if ((ech.config_list.len = fread(ech.config_list.base, 1, 65536, fp)) == 65536) {
-                fprintf(stderr, "ECHConfigList is too large:%s\n", optarg);
-                return 1;
-            }
-            fclose(fp);
-            ech.retry.fn = optarg;
-        } break;
-        case 'K': {
-            FILE *fp;
-            EVP_PKEY *pkey;
-            int ret;
-            if ((fp = fopen(optarg, "rt")) == NULL) {
-                fprintf(stderr, "failed to open ECH private key file:%s:%s\n", optarg, strerror(errno));
-                return 1;
-            }
-            if ((pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL)) == NULL) {
-                fprintf(stderr, "failed to load private key from file:%s\n", optarg);
-                return 1;
-            }
-            if ((ret = ptls_openssl_create_key_exchange(&ech.keyex.list[ech.keyex.count].ctx, pkey)) != 0) {
-                fprintf(stderr, "failed to load private key from file:%s:picotls-error:%d", optarg, ret);
-                return 1;
-            }
-            ech.keyex.list[ech.keyex.count].kem = find_kem(ech.keyex.list[ech.keyex.count].ctx->algo);
-            ++ech.keyex.count;
-            EVP_PKEY_free(pkey);
-            fclose(fp);
-            ctx.ech.server.create_opener = &ech_opener;
-        } break;
+        case 'E':
+            ech_setup_configs(optarg);
+            break;
+        case 'K':
+            ech_setup_key(&ctx, optarg);
+            break;
         case 'l':
             setup_log_event(&ctx, optarg);
             break;
diff --git a/t/util.h b/t/util.h
index 3c59243..0ead3f7 100644
--- a/t/util.h
+++ b/t/util.h
@@ -251,6 +251,149 @@
     ctx->encrypt_ticket = &sc.super;
 }
 
+static struct {
+    ptls_iovec_t config_list;
+    struct {
+        struct {
+            ptls_hpke_kem_t *kem;
+            ptls_key_exchange_context_t *ctx;
+        } list[16];
+        size_t count;
+    } keyex;
+    struct {
+        ptls_iovec_t configs;
+        char *fn;
+    } retry;
+} ech;
+
+static ptls_aead_context_t *ech_create_opener(ptls_ech_create_opener_t *self, ptls_hpke_kem_t **kem,
+                                              ptls_hpke_cipher_suite_t **cipher, ptls_t *tls, uint8_t config_id,
+                                              ptls_hpke_cipher_suite_id_t cipher_id, ptls_iovec_t enc, ptls_iovec_t info_prefix)
+{
+    const uint8_t *src = ech.config_list.base, *const end = src + ech.config_list.len;
+    size_t index = 0;
+    int ret = 0;
+
+    /* look for the cipher implementation; this should better be specific to each ECHConfig (as each of them may advertise different
+     * set of values) */
+    *cipher = NULL;
+    for (size_t i = 0; ptls_openssl_hpke_cipher_suites[i] != NULL; ++i) {
+        if (ptls_openssl_hpke_cipher_suites[i]->id.kdf == cipher_id.kdf &&
+            ptls_openssl_hpke_cipher_suites[i]->id.aead == cipher_id.aead) {
+            *cipher = ptls_openssl_hpke_cipher_suites[i];
+            break;
+        }
+    }
+    if (*cipher == NULL)
+        goto Exit;
+
+    ptls_decode_open_block(src, end, 2, {
+        uint16_t version;
+        if ((ret = ptls_decode16(&version, &src, end)) != 0)
+            goto Exit;
+        do {
+            ptls_decode_open_block(src, end, 2, {
+                if (src == end) {
+                    ret = PTLS_ALERT_DECODE_ERROR;
+                    goto Exit;
+                }
+                if (*src == config_id) {
+                    /* this is the ECHConfig that we have been looking for */
+                    if (index >= ech.keyex.count) {
+                        fprintf(stderr, "ECH key missing for config %zu\n", index);
+                        return NULL;
+                    }
+                    uint8_t *info = malloc(info_prefix.len + end - (src - 4));
+                    memcpy(info, info_prefix.base, info_prefix.len);
+                    memcpy(info + info_prefix.len, src - 4, end - (src - 4));
+                    ptls_aead_context_t *aead;
+                    ptls_hpke_setup_base_r(ech.keyex.list[index].kem, *cipher, ech.keyex.list[index].ctx, &aead, enc,
+                                           ptls_iovec_init(info, info_prefix.len + end - (src - 4)));
+                    free(info);
+                    *kem = ech.keyex.list[index].kem;
+                    return aead;
+                }
+                ++index;
+                src = end;
+            });
+        } while (src != end);
+    });
+
+Exit:
+    if (ret != 0)
+        fprintf(stderr, "ECH decode error:%d\n", ret);
+    return NULL;
+}
+
+static void ech_save_retry_configs(void)
+{
+    if (ech.retry.configs.base == NULL)
+        return;
+
+    FILE *fp;
+    if ((fp = fopen(ech.retry.fn, "wt")) == NULL) {
+        fprintf(stderr, "failed to write to ECH config file:%s:%s\n", ech.retry.fn, strerror(errno));
+        exit(1);
+    }
+    fwrite(ech.retry.configs.base, 1, ech.retry.configs.len, fp);
+    fclose(fp);
+}
+
+static void ech_setup_configs(const char *fn)
+{
+    FILE *fp;
+
+    if ((fp = fopen(fn, "rt")) == NULL) {
+        fprintf(stderr, "failed to open ECHConfigList file:%s:%s\n", fn, strerror(errno));
+        exit(1);
+    }
+    ech.config_list.base = malloc(65536);
+    if ((ech.config_list.len = fread(ech.config_list.base, 1, 65536, fp)) == 65536) {
+        fprintf(stderr, "ECHConfigList is too large:%s\n", fn);
+        exit(1);
+    }
+    fclose(fp);
+    ech.retry.fn = strdup(fn);
+}
+
+static void ech_setup_key(ptls_context_t *ctx, const char *fn)
+{
+    FILE *fp;
+    EVP_PKEY *pkey;
+    int ret;
+
+    if ((fp = fopen(fn, "rt")) == NULL) {
+        fprintf(stderr, "failed to open ECH private key file:%s:%s\n", fn, strerror(errno));
+        exit(1);
+    }
+    if ((pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL)) == NULL) {
+        fprintf(stderr, "failed to load private key from file:%s\n", fn);
+        exit(1);
+    }
+    if ((ret = ptls_openssl_create_key_exchange(&ech.keyex.list[ech.keyex.count].ctx, pkey)) != 0) {
+        fprintf(stderr, "failed to load private key from file:%s:picotls-error:%d", fn, ret);
+        exit(1);
+    }
+    EVP_PKEY_free(pkey);
+    fclose(fp);
+
+    for (size_t i = 0; ptls_openssl_hpke_kems[i] != NULL; ++i) {
+        if (ptls_openssl_hpke_kems[i]->keyex == ech.keyex.list[ech.keyex.count].ctx->algo) {
+            ech.keyex.list[ech.keyex.count].kem = ptls_openssl_hpke_kems[i];
+            break;
+        }
+    }
+    if (ech.keyex.list[ech.keyex.count].kem == NULL) {
+        fprintf(stderr, "kem unknown for private key:%s\n", fn);
+        exit(1);
+    }
+
+    ++ech.keyex.count;
+
+    static ptls_ech_create_opener_t opener = {.cb = ech_create_opener};
+    ctx->ech.server.create_opener = &opener;
+}
+
 static inline int resolve_address(struct sockaddr *sa, socklen_t *salen, const char *host, const char *port, int family, int type,
                                   int proto)
 {