CURLOPT_ECH(3)

πŸ’… CURLOPT_ECH(3) πŸ’…

okay so bestie, welcome to the libcurl manual, this one's all about CURLOPT_ECH β€” the config knob for Encrypted Client Hello πŸŽ€βœ¨


🌸 NAME 🌸

CURLOPT_ECH β€” configuration for Encrypted Client Hello πŸ¦‹


✨ SYNOPSIS ✨

#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_ECH, char *config);

πŸ’– DESCRIPTION πŸ’–

okay first thing: ECH is only compatible with TLSv1.3. no cap, that's the rule πŸ”₯

This is an experimental feature, and it needs a special build of OpenSSL, because ECH is not yet supported in OpenSSL releases. meanwhile the latest BoringSSL, wolfSSL and Rustls-ffi releases do support ECH, so like… pick your fighter πŸ’…

There's also a known issue with using wolfSSL β€” it does not support ECH when the HelloRetryRequest mechanism is used. πŸ™ˆ just so you know.

So you pass a string that specifies configuration details for ECH. In all cases, if ECH is attempted, it may fail for various reasons. 😭 The keywords supported are:

  • false β€” turns off ECH. bye bye πŸ‘‹
  • grease β€” instructs client to emit a GREASE ECH extension. (heads up: the connection fails if ECH is attempted but fails.) πŸ’€
  • true β€” instructs client to attempt ECH, if possible, but to not fail if attempting ECH is not possible. soft launch energy ✨
  • hard β€” instructs client to attempt ECH and fail if attempting ECH is not possible. main character commitment, no backup plan πŸ”₯
  • ecl:<base64-value> β€” if the string starts with ecl: then the remainder of the string should be a base64-encoded ECHConfigList that is used for ECH rather than attempting to download such a value from the DNS. straight to the source, we love to see it πŸŽ€
  • pn:<name> β€” if the string starts with pn: then the remainder of the string should be a DNS/hostname that is used to over-ride the public_name field of the ECHConfigList that is used for ECH. glow-up for the public name πŸ’…

bestie, the good news: the application does not have to keep the string around after setting this option. set it and forget it 🫢

Using this option multiple times makes the last set string override the previous ones. and set it to NULL or "false" to disable its use again. so simple, iconic 😌


πŸ¦‹ DEFAULT πŸ¦‹

NULL, meaning ECH is disabled. she's off, she's resting 🧚


🌈 PROTOCOLS 🌈

This functionality affects all TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. ⭐

This option works only with the following TLS backends: OpenSSL, Rustls and wolfSSL πŸ‘‘


πŸ“ EXAMPLE πŸ“

int main(void)
{
  CURL *curl = curl_easy_init();

  const char *config = \
    "ecl:AED+DQA87wAgACB/RuzUCsW3uBbSFI7mzD63TUXpI8sGDTnFTbFCDpa+" \
    "CAAEAAEAAQANY292ZXIuZGVmby5pZQAA";
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_ECH, config);
    curl_easy_perform(curl);
  }
}

πŸ’œ AVAILABILITY πŸ’œ

Added in curl 8.8.0 πŸŽ‰ (yes we're so back)


πŸ‘‘ RETURN VALUE πŸ‘‘

curl_easy_setopt(3) returns a CURLcode indicating success or error.

CURLE_OK (0) means everything was OK 😌✨, non-zero means an error occurred 😭, see libcurl-errors(3).


πŸ’€ SEE ALSO πŸ’€


k that's the whole thing bestie, go encrypt those hellos πŸ’–βœ¨πŸ’…

this lil page came from libcurl, dated 2026-10-12 β€” periodt, iykyk πŸ¦‹πŸŽ€

πŸ“¦ where this page comes from