#if defined(USE_ECH)
static CURLcode
init_config_builder_ech(struct Curl_easy *data,
+ const struct ssl_connect_data *connssl,
struct rustls_client_config_builder *builder)
{
const rustls_hpke *hpke = rustls_supported_hpke();
unsigned char *ech_config = NULL;
size_t ech_config_len = 0;
+ struct Curl_dns_entry *dns = NULL;
+ struct Curl_https_rrinfo *rinfo = NULL;
+ CURLcode result = CURLE_OK;
+ rustls_result rr;
if(!hpke) {
failf(data,
"rustls: ECH unavailable, rustls-ffi built without "
"HPKE compatible crypto provider");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto cleanup;
}
if(data->set.str[STRING_ECH_PUBLIC]) {
failf(data, "rustls: ECH outername not supported");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto cleanup;
}
if(data->set.tls_ech == CURLECH_GREASE) {
- rustls_result rr;
rr = rustls_client_config_builder_enable_ech_grease(builder, hpke);
if(rr != RUSTLS_RESULT_OK) {
rustls_failf(data, rr, "rustls: failed to configure ECH GREASE");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto cleanup;
}
+ return CURLE_OK;
}
- else if(data->set.tls_ech & CURLECH_CLA_CFG
+
+ if(data->set.tls_ech & CURLECH_CLA_CFG
&& data->set.str[STRING_ECH_CONFIG]) {
const char *b64 = data->set.str[STRING_ECH_CONFIG];
size_t decode_result;
- rustls_result rr;
if(!b64) {
infof(data, "rustls: ECHConfig from command line empty");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto cleanup;
}
/* rustls-ffi expects the raw TLS encoded ECHConfigList bytes */
decode_result = Curl_base64_decode(b64, &ech_config, &ech_config_len);
if(decode_result || !ech_config) {
infof(data, "rustls: cannot base64 decode ECHConfig from command line");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto cleanup;
}
- rr = rustls_client_config_builder_enable_ech(builder,
- ech_config,
- ech_config_len,
- hpke);
- if(rr != RUSTLS_RESULT_OK) {
- rustls_failf(data, rr, "rustls: failed to configure ECH");
- return CURLE_SSL_CONNECT_ERROR;
+ }
+ else {
+ if(connssl->peer.hostname) {
+ dns = Curl_fetch_addr(
+ data,
+ connssl->peer.hostname,
+ connssl->peer.port);
+ }
+ if(!dns) {
+ failf(data, "rustls: ECH requested but no DNS info available");
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto cleanup;
}
+ rinfo = dns->hinfo;
+ if(!rinfo || !rinfo->echconfiglist) {
+ failf(data, "rustls: ECH requested but no ECHConfig available");
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto cleanup;
+ }
+ ech_config = rinfo->echconfiglist;
+ ech_config_len = rinfo->echconfiglist_len;
}
- return CURLE_OK;
+ rr = rustls_client_config_builder_enable_ech(builder,
+ ech_config,
+ ech_config_len,
+ hpke);
+ if(rr != RUSTLS_RESULT_OK) {
+ rustls_failf(data, rr, "rustls: failed to configure ECH");
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto cleanup;
+ }
+cleanup:
+ if(dns) {
+ Curl_resolv_unlink(data, &dns);
+ }
+ return result;
}
#endif /* USE_ECH */
#if defined(USE_ECH)
if(ECH_ENABLED(data)) {
- result = init_config_builder_ech(data, config_builder);
+ result = init_config_builder_ech(data, connssl, config_builder);
if(result != CURLE_OK && data->set.tls_ech & CURLECH_HARD) {
rustls_client_config_builder_free(config_builder);
return result;