ENDPOINT role = ENDPOINT_BOTH;
custom_ext_method *meth = NULL;
- if ((context & SSL_EXT_CLIENT_HELLO) != 0)
+ if ((context & SSL_EXT_CLIENT_HELLO) != 0) {
+#ifndef OPENSSL_NO_ECH
+ if (s->ext.ech.attempted == 1 && s->ext.ech.ch_depth == 1)
+ role = ENDPOINT_CLIENT;
+ else
+ role = ENDPOINT_SERVER;
+#else
role = ENDPOINT_SERVER;
- else if ((context & SSL_EXT_TLS1_2_SERVER_HELLO) != 0)
+#endif
+ } else if ((context & SSL_EXT_TLS1_2_SERVER_HELLO) != 0)
role = ENDPOINT_CLIENT;
meth = custom_ext_find(meths, role, type, &offset);
* Initialise server side custom extensions. Client side is done during
* construction of extensions for the ClientHello.
*/
+#ifndef OPENSSL_NO_ECH
+ if ((context & SSL_EXT_CLIENT_HELLO) != 0 && s->ext.ech.attempted == 0)
+ custom_ext_init(&s->cert->custext);
+#else
if ((context & SSL_EXT_CLIENT_HELLO) != 0)
custom_ext_init(&s->cert->custext);
+#endif
num_exts = OSSL_NELEM(ext_defs) + (exts != NULL ? exts->meths_count : 0);
raw_extensions = OPENSSL_calloc(num_exts, sizeof(*raw_extensions));
}
/* Add custom extensions first */
- if ((context & SSL_EXT_CLIENT_HELLO) != 0) {
+#ifndef OPENSSL_NO_ECH
+ if ((context & SSL_EXT_CLIENT_HELLO) != 0 && s->ext.ech.attempted == 0)
/* On the server side with initialise during ClientHello parsing */
custom_ext_init(&s->cert->custext);
- }
+#else
+ if ((context & SSL_EXT_CLIENT_HELLO) != 0)
+ /* On the server side with initialise during ClientHello parsing */
+ custom_ext_init(&s->cert->custext);
+#endif
if (!custom_ext_add(s, context, pkt, x, chainidx, max_version)) {
/* SSLfatal() already called */
return 0;
#include "internal/quic_error.h"
static OSSL_LIB_CTX *libctx = NULL;
+static char *propq = NULL;
static OSSL_PROVIDER *defctxnull = NULL;
static char *certsdir = NULL;
static char *cert = NULL;
"::2", 4434);
}
+/* Test ECH with quic */
+static int test_ech(void)
+{
+ /*
+ * Don't try this test if various ECC things are set of unavailable
+ * or we're in a no-ech build
+ */
+#if defined(OPENSSL_NO_EC) || defined(OPENSSL_NO_ECX) || defined(OPENSSL_NO_ECH)
+ propq = NULL; /* avoid unused var warning */
+ return 1;
+#else
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientquic = NULL;
+ char *rinner = NULL, *router = NULL;
+ const char *inner = "inner.example.com";
+ QUIC_TSERVER *qtserv = NULL;
+ int testresult = 0;
+ /* p256 ech key pair with public name server.example */
+ const char echpem[] = "-----BEGIN PRIVATE KEY-----\n"
+ "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg+Ygt9nhASeoYbzo2\n"
+ "Nz/jGFAdeTo25SVYWQvnf86qzbahRANCAARS9QqkjJU311J7kS8LsyISJ8xYFbJ5\n"
+ "5BX/pu4QiFXJ3dEGrjYh4PDH/ehFfaqZgtRRg2r/AP+vwkLiP2mqCfdv\n"
+ "-----END PRIVATE KEY-----\n"
+ "-----BEGIN ECHCONFIG-----\n"
+ "AGL+DQBezwAQAEEEUvUKpIyVN9dSe5EvC7MiEifMWBWyeeQV/6buEIhVyd3RBq42\n"
+ "IeDwx/3oRX2qmYLUUYNq/wD/r8JC4j9pqgn3bwAEAAEAAQAOc2VydmVyLmV4YW1w\n"
+ "bGUAAA==\n"
+ "-----END ECHCONFIG-----\n";
+ const char ec_pub[] = "AGL+DQBezwAQAEEEUvUKpIyVN9dSe5EvC7MiEifMWBWyeeQV/6buEIhVyd3RBq42"
+ "IeDwx/3oRX2qmYLUUYNq/wD/r8JC4j9pqgn3bwAEAAEAAQAOc2VydmVyLmV4YW1w"
+ "bGUAAA==";
+ size_t ec_publen = sizeof(ec_pub) - 1;
+ BIO *in = NULL;
+ OSSL_ECHSTORE *es = NULL;
+
+ /* HPKE and FIPS are not friends, so don't test in that case */
+ if (is_fips) {
+ TEST_info("No real ECH test as is_fips is set\n");
+ return 1;
+ } else {
+ TEST_info("Doing real ECH test as is_fips is not set\n");
+ }
+
+ /* make an OSSL_ECHSTORE for echpem */
+ if ((in = BIO_new(BIO_s_mem())) == NULL
+ || BIO_write(in, echpem, (int)strlen(echpem)) <= 0
+ || !TEST_ptr(es = OSSL_ECHSTORE_new(libctx, propq))
+ || !TEST_true(OSSL_ECHSTORE_read_pem(es, in, OSSL_ECH_FOR_RETRY)))
+ goto err;
+
+ cctx = SSL_CTX_new_ex(libctx, NULL, OSSL_QUIC_client_method());
+ sctx = SSL_CTX_new_ex(libctx, NULL, TLS_method());
+ /* set OSSL_ECHSTORE for server */
+ if (!TEST_ptr(sctx) || !TEST_true(SSL_CTX_set1_echstore(sctx, es)))
+ goto err;
+
+ if (!TEST_ptr(cctx)
+ || !TEST_true(qtest_create_quic_objects(libctx, cctx, sctx, cert,
+ privkey,
+ QTEST_FLAG_FAKE_TIME,
+ &qtserv,
+ &clientquic, NULL, NULL)))
+ goto err;
+
+ /* set echconfig for client */
+ if (!TEST_true(SSL_set1_ech_config_list(clientquic,
+ (unsigned char *)ec_pub, ec_publen))
+ || !TEST_true(SSL_set_tlsext_host_name(clientquic, inner)))
+ goto err;
+ /* we expect the connection to succeed */
+ if (!TEST_true(qtest_create_quic_connection(qtserv, clientquic)))
+ goto err;
+ SSL_set_verify_result(clientquic, X509_V_OK);
+ if (!TEST_int_eq(SSL_ech_get1_status(clientquic, &rinner, &router),
+ SSL_ECH_STATUS_SUCCESS))
+ goto err;
+
+ testresult = 1;
+err:
+ ossl_quic_tserver_free(qtserv);
+ SSL_free(clientquic);
+ OPENSSL_free(router);
+ OPENSSL_free(rinner);
+ SSL_CTX_free(cctx);
+ SSL_CTX_free(sctx);
+ OSSL_ECHSTORE_free(es);
+ BIO_free_all(in);
+
+ return testresult;
+#endif
+}
+
/***********************************************************************************/
OPT_TEST_DECLARE_USAGE("provider config certsdir datadir\n")
ADD_TEST(test_client_hello_retry);
ADD_TEST(test_quic_peer_addr_v6);
ADD_TEST(test_quic_peer_addr_v4);
+ ADD_TEST(test_ech);
return 1;
err: