.\" -*- mode: troff; coding: utf-8 -*- .\" Automatically generated by Pod::Man 5.0102 (Pod::Simple 3.45) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>. .ie n \{\ . ds C` "" . ds C' "" 'br\} .el\{\ . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "SSL_SET1_ECHSTORE 3SSL" .TH SSL_SET1_ECHSTORE 3SSL 2026-06-09 4.0.1 OpenSSL .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH NAME SSL_set1_echstore, OSSL_ECHSTORE_new, OSSL_ECHSTORE_free, OSSL_ECHSTORE_new_config, OSSL_ECHSTORE_write_pem, OSSL_ECHSTORE_read_echconfiglist, OSSL_ECHSTORE_get1_info, OSSL_ECHSTORE_downselect, OSSL_ECHSTORE_set1_key_and_read_pem, OSSL_ECHSTORE_read_pem, OSSL_ECHSTORE_num_entries, OSSL_ECHSTORE_num_keys, OSSL_ECHSTORE_flush_keys, SSL_CTX_set1_echstore, SSL_CTX_get1_echstore, SSL_get1_echstore, SSL_ech_set1_server_names, SSL_ech_set1_outer_server_name, SSL_ech_set1_outer_alpn_protos, SSL_ech_get1_status, SSL_ech_set1_grease_suite, SSL_ech_set_grease_type, SSL_ech_set_callback, SSL_ech_get1_retry_config, SSL_CTX_ech_set1_outer_alpn_protos, SSL_CTX_ech_set_callback,SSL_set1_ech_config_list \&\- Encrypted Client Hello (ECH) functions .SH SYNOPSIS .IX Header "SYNOPSIS" .Vb 1 \& #include \& \& OSSL_ECHSTORE *OSSL_ECHSTORE_new(OSSL_LIB_CTX *libctx, const char *propq); \& void OSSL_ECHSTORE_free(OSSL_ECHSTORE *es); \& int OSSL_ECHSTORE_new_config(OSSL_ECHSTORE *es, \& uint16_t echversion, uint16_t max_name_length, \& const char *public_name, OSSL_HPKE_SUITE suite); \& int OSSL_ECHSTORE_write_pem(OSSL_ECHSTORE *es, int index, BIO *out); \& int OSSL_ECHSTORE_read_echconfiglist(OSSL_ECHSTORE *es, BIO *in); \& int OSSL_ECHSTORE_get1_info(OSSL_ECHSTORE *es, int index, time_t *loaded_secs, \& char **public_name, char **echconfig, \& int *has_private, int *for_retry); \& int OSSL_ECHSTORE_downselect(OSSL_ECHSTORE *es, int index); \& int OSSL_ECHSTORE_set1_key_and_read_pem(OSSL_ECHSTORE *es, EVP_PKEY *priv, \& BIO *in, int for_retry); \& int OSSL_ECHSTORE_read_pem(OSSL_ECHSTORE *es, BIO *in, int for_retry); \& int OSSL_ECHSTORE_num_entries(OSSL_ECHSTORE *es, int *numentries); \& int OSSL_ECHSTORE_num_keys(OSSL_ECHSTORE *es, int *numkeys); \& int OSSL_ECHSTORE_flush_keys(OSSL_ECHSTORE *es, time_t age); \& int SSL_CTX_set1_echstore(SSL_CTX *ctx, OSSL_ECHSTORE *es); \& int SSL_set1_echstore(SSL *s, OSSL_ECHSTORE *es); \& OSSL_ECHSTORE *SSL_CTX_get1_echstore(const SSL_CTX *ctx); \& OSSL_ECHSTORE *SSL_get1_echstore(const SSL *s); \& int SSL_ech_set1_server_names(SSL *s, const char *inner_name, \& const char *outer_name, int no_outer); \& int SSL_ech_set1_outer_server_name(SSL *s, const char *outer_name, int no_outer); \& int SSL_ech_set1_outer_alpn_protos(SSL *s, const unsigned char *protos, \& const size_t protos_len); \& int SSL_ech_get1_status(SSL *s, char **inner_sni, char **outer_sni); \& int SSL_ech_set1_grease_suite(SSL *s, const char *suite); \& int SSL_ech_set_grease_type(SSL *s, uint16_t type); \& void SSL_ech_set_callback(SSL *s, SSL_ech_cb_func f); \& int SSL_ech_get1_retry_config(SSL *s, unsigned char **ec, size_t *eclen); \& void SSL_CTX_ech_set_callback(SSL_CTX *ctx, SSL_ech_cb_func f); \& int SSL_CTX_ech_set1_outer_alpn_protos(SSL_CTX *ctx, \& const unsigned char *protos, \& const size_t protos_len); \& int SSL_set1_ech_config_list(SSL *ssl, const uint8_t *ecl, size_t ecl_len); .Ve .SH DESCRIPTION .IX Header "DESCRIPTION" The Encrypted Client Hello (ECH) APIs described here are built around the concept of an \fBOSSL_ECHSTORE\fR which contains ECH configuration information relevant for an \fBSSL_CTX\fR or \fBSSL\fR connection. .PP This release only supports ECH shared-mode and has no support for ECH split-mode. .SS "OSSL_ECHSTORE APIs" .IX Subsection "OSSL_ECHSTORE APIs" The externally opaque type \fBOSSL_ECHSTORE\fR allows applications to create and manage ECHConfigList values, ECH private keys and associated meta-data. The external APIs using \fBOSSL_ECHSTORE\fR are: .PP \&\fBOSSL_ECHSTORE_new()\fR and \fBOSSL_ECHSTORE_free()\fR create and free the internal storage required. .PP \&\fBOSSL_ECHSTORE_new_config()\fR allows the caller to create a new private key value and a related "singleton" ECHConfigList structure. ("Singleton" meaning the ECHConfigList only contains one public key.) The \fIechversion\fR is the ECHConfig version to use, which is typically \&\fBOSSL_ECH_CURRENT_VERSION\fR with a value of 0xfe0d. The \fImax_name_length\fR specifies the maximum known DNS name length that will be present in an ECH extension (if known) and is used for ECH padding but should typically be zero, to indicate no known maximum. The \fIpublic_name\fR is the DNS name to use in the ECHConfig \fIpublic_name\fR field, and the \fIsuite\fR specifies the \&\fBOSSL_HPKE_suite\fR to use (see \fBOSSL_HPKE_CTX_new\fR\|(3) for details.) .PP \&\fBOSSL_ECHSTORE_write_pem()\fR allows the caller to produce an ECH PEM data structure (conforming to the ECH PEM file format) from the \fBOSSL_ECHSTORE\fR entry identified by the \fIindex\fR. (An \fIindex\fR of \fBOSSL_ECHSTORE_LAST\fR will select the last entry. An \fIindex\fR of \fBOSSL_ECHSTORE_ALL\fR will output all public values, and no private values, otherwise the \fIindex\fR selects a specific entry with zero selecting the first entry.) The output will be written to the \fIout\fR \&\fBBIO\fR. .PP The \fBOSSL_ECHSTORE\fR APIs above will typically be used via the "openssl ech" command line tool. .PP \&\fBOSSL_ECHSTORE_read_echconfiglist()\fR reads from the \fIin\fR \fBBIO\fR and parses a base64\-encoded ECHConfigList value normally found in the "ech=" SvcParamKey present in an SVCB or HTTPS RR retrieved from the DNS. The resulting set of ECHConfig values, are associated with the \fIes\fR store, and can then be associated with an \fBSSL_CTX\fR or \fBSSL\fR structure for TLS client connections. .PP Input \fBBIO\fR values (such a \fIin\fR above) must not use unterminated \fBBIO\fR's. .PP \&\fBOSSL_ECHSTORE_get1_info()\fR queries the store provided by \fIes\fR and finds the entry within the store specified by \fIindex\fR. The number of seconds since that entry was first generated or loaded/decoded is stored in \fIloaded_secs\fR, and the related public name is stored in \fI*public_name\fR. This function also outputs a string useful for logging or display (as described in the "String form of ECHConfig" section) and stores that in \fI*echconfig\fR. It is the callers responsibility to free the strings returned in \fIpublic_name\fR and \&\fIechconfig\fR after they have been returned. If the specified entry has a private key associated with it then \fIhas_private\fR will be set to 1, otherwise it will be set to 0. Similarly if the ECHConfig for this entry will be included in "retry-configs" then the \fIfor_retry\fR will be set to 1 or zero if that ECHConfig will not be included in retry-configs. .PP The ECH fallback scheme involving retry-configs is described in Section 6.1.1 of RFC 9849. .PP \&\fBOSSL_ECHSTORE_downselect()\fR provides the caller a way to select one particular ECHConfig value based on the zero-based \fIindex\fR from those stored in the \&\fIes\fR, discarding the rest. This can be used by a client (via \fBopenssl\-ech\fR\|(1) and \fBopenssl\-s_client\fR\|(1) or equivalent) to pick a specific ECHConfig to use in a TLS connection. .PP \&\fBOSSL_ECHSTORE_set1_key_and_read_pem()\fR and \fBOSSL_ECHSTORE_read_pem()\fR can be used to load a private key value and associated ECHConfigList from the \fBBIO\fR \fIin\fR into an \fBOSSL_ECHSTORE\fR structure. The former function pairs a previously-loaded private key (in \fBEVP_PKEY\fR format) with an associated base64\-encoded ECHConfigList in the \fIin\fR \fBBIO\fR. The latter function reads both from an ECH PEM file. Those can be used (by servers) to enable ECH for an \&\fBSSL_CTX\fR or \fBSSL\fR connection. In addition to loading those values, the application can also indicate via \fIfor_retry\fR which ECHConfig values are to be included in the \fIretry_configs\fR fallback scheme defined by the ECH protocol. .PP An ECH PEM file may contain a private key and an ECHConfigList with more than one ECHConfig, for example if different public keys, \fIpublic_name\fR values, or AEAD/KDF settings are to be supported. When such a file is read, the resulting \&\fBOSSL_ECHSTORE\fR will contain one entry for each ECHConfig in the ECHConfigList, so will be presented to applications as a set of "singleton" ECHConfig values, with the private key associated with each matching public key value. .PP \&\fBOSSL_ECHSTORE_num_entries()\fR and \fBOSSL_ECHSTORE_num_keys()\fR allow an application to see how many ECH configs (in \fInumentries\fR) and private keys (in \&\fInumkeys\fR) are present in the \fIes\fR \fBOSSL_ECHSTORE\fR store. .PP \&\fBOSSL_ECHSTORE_flush_keys()\fR allows a server to flush keys from \fIes\fR that were loaded more than \fIage\fR seconds ago. The general model is that a server can maintain an \fBOSSL_ECHSTORE\fR into which it periodically loads the "latest" set of keys, e.g. hourly, and also discards the keys that are too old, e.g. more than 3 hours old. This allows for more robust private key management even if public key distribution suffers temporary failures. .PP \&\fBSSL_CTX_set1_echstore()\fR and \fBSSL_set1_echstore()\fR allow clients and servers to associate \fIes\fR (an \fBOSSL_ECHSTORE\fR) with an \fBSSL_CTX\fR or \fBSSL\fR structure. ECH will be enabled for the relevant \fBSSL_CTX\fR or \fBSSL\fR connection when these functions succeed. Any previously associated \fBOSSL_ECHSTORE\fR will be freed via \&\fBOSSL_ECHSTORE_free()\fR. Internally, \fBOSSL_ECHSTORE\fR values within an \fBSSL_CTX\fR or \fBSSL\fR connection are deep-copied, and are not refcounted. .PP \&\fBSSL_CTX_get1_echstore()\fR and \fBSSL_get1_echstore()\fR provide access to the \&\fBOSSL_ECHSTORE\fR associated with an \fBSSL_CTX\fR or \fBSSL\fR connection. The returned \fBOSSL_ECHSTORE\fR can be modified and then re-associated with an \&\fBSSL_CTX\fR or \fBSSL\fR connection. .SS "Client ECH Controls" .IX Subsection "Client ECH Controls" \&\fBSSL_set1_ech_config_list()\fR allows clients to setup ECH by associating an ECHConfigList, \fIecl\fR with an \fBSSL\fR connection \fIs\fR. This is compatible with current BoringSSL APIs, allowing for smaller code changes for clients that support OpenSSL or BoringSSL. Note that the input \fIecl\fR here for OpenSSL can be either base64 or binary encoded, but for BoringSSL it must be binary encoded. .PP \&\fBSSL_ech_set1_server_names()\fR and \fBSSL_ech_set1_outer_server_name()\fR allow clients to more directly control the values to be used for inner and outer Server Name Indication (SNI) values for an \fBSSL\fR connection, \fIs\fR. The \fIinner_name\fR provided will be used as with \fBSSL_set_tlsext_host_name\fR\|(3) to populate the SNI value for the inner ClientHello. The \fIouter_name\fR, if non-NULL, can over-ride the public_name field of the ECHConfig used for the connection. The \&\fIno_outer\fR input allows a client to emit an outer ClientHello with no SNI at all. Providing a NULL for the \fIouter_name\fR means to send the \fIpublic_name\fR provided from the ECHConfigList unless the \fIno_outer\fR provided has the value 1. .PP If a client has called \fBSSL_CTX_set_alpn_protos\fR\|(3) or \&\fBSSL_set_alpn_protos\fR\|(3) then the ALPN value will be the same in the inner and outer ClientHello messages. \fBSSL_ech_set1_outer_alpn_protos()\fR and \&\fBSSL_CTX_ech_set1_outer_alpn_protos()\fR allow clients to set a specific value for the ALPN sent in the outer ClientHello of the \fBSSL\fR connection, \fIs\fR. The \&\fIprotos\fR and \fIprotos_len\fR inputs must be provided as for \&\fBSSL_set_alpn_protos\fR\|(3). .PP If a client attempts ECH but that fails, or sends an ECH-GREASE'd ClientHello, to an ECH-supporting server, then that server may return a set of ECH retry-config values that the client could choose to use in a subsequent connection. The client can detect this situation if \fBSSL_ech_get1_status()\fR for the \fBSSL\fR connection \fIs\fR, returns a status of \fBSSL_ECH_STATUS_GREASE_ECH\fR, and can then access the ECH retry config values via \fBSSL_ech_get1_retry_config()\fR where the \fIec\fR value returned will contain a binary-encoded ECHConfigList of length \fIeclen\fR. .PP If a client makes a real attempt at ECH that fails then the server can also return retry config values, and those can be used if they were authenticated under the outer SNI used for the session. In this case the TLS session fails returning the error \fBSSL_R_ECH_REQUIRED\fR, and the ECH status of \&\fBSSL_ECH_STATUS_FAILED_ECH\fR indicates that retry config values can be accessed using \fBSSL_ech_get1_retry_config()\fR. The application can then choose to use those in a subsequent attempt to establish a TLS session with the server. If the TLS session fails for some other reason (e.g. a bad server Finished message), then the retry config values will not be returned to the application. .PP "GREASEing" (defined in RFC8701) is a mechanism intended to discourage protocol ossification that can be used for ECH. .PP \&\fBSSL_ech_set1_grease_suite()\fR allows a client to GREASE ECH for the \fBSSL\fR connection \fIs\fR, using a specific \fBOSSL_HPKE_SUITE\fR as the value for \fIsuite\fR (see \fBOSSL_HPKE_get_grease_value\fR\|(3)). \fBSSL_ech_set_grease_type()\fR allows a client to add a GREASE'd ECH for the \fBSSL\fR connection \fIs\fR, using the specified ClientHello extension number \fItype\fR. .PP Clients and servers can query the status of ECH for a \fBSSL\fR connection \fIs\fR, using the \fBSSL_ech_get1_status()\fR function. As SNI handling is core to ECH this will also return the \fIinner_sni\fR and \fIouter_sni\fR values to be used or that were used as well as a status code as the return value. These name values must be freed by the caller. The various status values returned by this function are as described in "Constants". .SS "Callback Functions" .IX Subsection "Callback Functions" Applications can set a callback function that will be called when the outcome from an attempt at ECH has been determined. On the server, that happens early, as part of construction of the ServerHello message. On the client, the callback will happen after the SeverHello has been processed. In the event of HelloRetryRequest, the callback will only be triggered when processing the second ServerHello. The callback function will be triggered even if the client is only GREASEing. .PP The callback function prototype is: .PP .Vb 1 \& typedef unsigned int (*SSL_ech_cb_func)(SSL *s, const char *str); .Ve .PP To set a callback function for the \fBSSL\fR connection \fIs\fR, use \&\fBSSL_ech_set_callback()\fR or \fBSSL_CTX_ech_set_callback()\fR for a \fBSSL_CTX\fR \fIctx\fR \- the \fIf\fR input should match the above prototype. .PP When the callback function is called, the \fIstr\fR will point at a string intended for logging describing the state of ECH processing. Applications should not attempt to parse that string as the value depends on compile time settings, local configuration and the specific processing that happened prior to the callback. Applications that need to branch based on the outcome of ECH processing should instead make a call to \&\fBSSL_ech_get1_status()\fR from within their callback function. .PP An example string \fIstr\fR as seen on a client might be: .PP .Vb 11 \& ech_attempted=1 \& ech_attempted_type=0xfe0d \& ech_atttempted_cid=0x5d \& ech_done=1 \& ech_grease=0 \& ech_returned_len=0 \& ech_backend=0 \& ech_success=1 \& 2 ECHConfig values loaded \& cfg(0): [fe0d,5d,cover.defo.ie,[0020,0001,0001],190984309c1a24cb944c005eb79d9c72ca9a4a979194b553dfd0bffc6b5c152d,00,00] \& cfg(1): [fe0d,fd,cover.defo.ie,[0020,0001,0001],46dd4e2c81bb15ef9d194c99b86983844e2a1387e4fb7e7d3b8d368c8e1b4d2a,00,00] .Ve .SS Constants .IX Subsection "Constants" Some externally visible limits: .IP "\fBOSSL_ECH_MAX_PAYLOAD_LEN\fR 1500, maximum length of an ECH ciphertext to en/decode" 4 .IX Item "OSSL_ECH_MAX_PAYLOAD_LEN 1500, maximum length of an ECH ciphertext to en/decode" .PD 0 .IP "\fBOSSL_ECH_MIN_ECHCONFIG_LEN\fR 32, minimum length of an encoded ECHConfig" 4 .IX Item "OSSL_ECH_MIN_ECHCONFIG_LEN 32, minimum length of an encoded ECHConfig" .IP "\fBOSSL_ECH_MAX_ECHCONFIG_LEN\fR 1500, maximum length of an encoded ECHConfig" 4 .IX Item "OSSL_ECH_MAX_ECHCONFIG_LEN 1500, maximum length of an encoded ECHConfig" .IP "\fBOSSL_ECH_MAX_ECHCONFIGEXT_LEN\fR 512, maximum length of an ECHConfig extension" 4 .IX Item "OSSL_ECH_MAX_ECHCONFIGEXT_LEN 512, maximum length of an ECHConfig extension" .IP "\fBOSSL_ECH_MAX_MAXNAMELEN\fR 255, maximum for ECHConfig max name length" 4 .IX Item "OSSL_ECH_MAX_MAXNAMELEN 255, maximum for ECHConfig max name length" .IP "\fBOSSL_ECH_MAX_PUBLICNAME\fR 255, maximum length of an ECHConfig public name" 4 .IX Item "OSSL_ECH_MAX_PUBLICNAME 255, maximum length of an ECHConfig public name" .IP "\fBOSSL_ECH_MAX_ALPN_LEN\fR 255, maximum overall length of an ALPN" 4 .IX Item "OSSL_ECH_MAX_ALPN_LEN 255, maximum overall length of an ALPN" .IP "\fBOSSL_ECH_OUTERS_MAX\fR 20, maximum number of extensions compressed via outer-exts" 4 .IX Item "OSSL_ECH_OUTERS_MAX 20, maximum number of extensions compressed via outer-exts" .IP "\fBOSSL_ECH_ALLEXTS_MAX\fR 32, maximum total number of extensions allowed" 4 .IX Item "OSSL_ECH_ALLEXTS_MAX 32, maximum total number of extensions allowed" .PD .PP ECH version \- the only supported version is 0xfe0d currently. .IP "\fBOSSL_ECH_RFC9849_VERSION\fR 0xfe0d, official ECHConfig version" 4 .IX Item "OSSL_ECH_RFC9849_VERSION 0xfe0d, official ECHConfig version" .PD 0 .IP "\fBOSSL_ECH_CURRENT_VERSION\fR OSSL_ECH_RFC9849_VERSION" 4 .IX Item "OSSL_ECH_CURRENT_VERSION OSSL_ECH_RFC9849_VERSION" .PD .PP Values for \fIfor_retry\fR .IP "\fBSSL_ECH_USE_FOR_RETRY\fR 1. use corresponding ECHConfig values" 4 .IX Item "SSL_ECH_USE_FOR_RETRY 1. use corresponding ECHConfig values" .PD 0 .IP "\fBSSL_ECH_NOT_FOR_RETRY\fR 0. don't use corresponding ECHConfig values" 4 .IX Item "SSL_ECH_NOT_FOR_RETRY 0. don't use corresponding ECHConfig values" .PD .PP Indexing an OSSL_ECHSTORE .IP "\fBOSSL_ECHSTORE_LAST\fR, \-1 select the last entry in the store" 4 .IX Item "OSSL_ECHSTORE_LAST, -1 select the last entry in the store" .PD 0 .IP "\fBOSSL_ECHSTORE_ALL\fR, \-2 select all entries in the store, e.g. to print public values" 4 .IX Item "OSSL_ECHSTORE_ALL, -2 select all entries in the store, e.g. to print public values" .PD .SS "String form of ECHConfig" .IX Subsection "String form of ECHConfig" \&\fBOSSL_ECHSTORE_get1_info()\fR returns the string form of the ECH public name plus a string describing the content of the ECHConfig for example: .PP .Vb 1 \& [fe0d,4d,example.com,[0020,0001,0002],c103d20dddce9b4445829bf01f5b533b728bfa0ebe3a97da33574bc096bb846e,00,00] .Ve .PP In the order presented in the example above, the \fIversion\fR is 0xfe0d, the \&\fIconfig_id\fR is 0x4d, the \fIpublic_name\fR is "example.com", there is one ciphersuite with a \fIkem-id\fR of 0x20, \fIkdf-id\fR is 0x01 and \fIaead-id\fR is 0x02; the \fIpublic_key\fR is the hexadecimal string "c1...6e", the \fImax-name-length\fR is 0x00 and the \fIextensions\fR length is 0x00 as no ECHConfig extensions are present. .SH "RETURN VALUES" .IX Header "RETURN VALUES" \&\fBSSL_set1_echstore()\fR, \fBSSL_set1_ech_config_list()\fR, \fBOSSL_ECHSTORE_new_config()\fR, \&\fBOSSL_ECHSTORE_write_pem()\fR, \fBOSSL_ECHSTORE_read_echconfiglist()\fR, \&\fBOSSL_ECHSTORE_get1_info()\fR, \fBOSSL_ECHSTORE_downselect()\fR, \&\fBOSSL_ECHSTORE_set1_key_and_read_pem()\fR, \fBOSSL_ECHSTORE_read_pem()\fR, \&\fBOSSL_ECHSTORE_num_keys()\fR, \fBOSSL_ECHSTORE_num_entries()\fR, \&\fBOSSL_ECHSTORE_flush_keys()\fR, \fBSSL_CTX_set1_echstore()\fR, \&\fBSSL_ech_set_server_names()\fR, \fBSSL_ech_set_outer_server_name()\fR, \&\fBSSL_ech_set_outer_alpn_protos()\fR, \&\fBSSL_ech_set_grease_suite()\fR, \fBSSL_ech_set_grease_type()\fR, \&\fBSSL_ech_get_retry_config()\fR and \fBSSL_CTX_ech_set1_outer_alpn_protos()\fR all return zero on error and one on success. .PP \&\fBSSL_ech_get1_status()\fR returns one of the following values: .IP "\fBSSL_ECH_STATUS_BACKEND\fR 4, ECH backend: saw an ech_is_inner" 4 .IX Item "SSL_ECH_STATUS_BACKEND 4, ECH backend: saw an ech_is_inner" .PD 0 .IP "\fBSSL_ECH_STATUS_GREASE_ECH\fR 3, GREASEd and got an ECH in return" 4 .IX Item "SSL_ECH_STATUS_GREASE_ECH 3, GREASEd and got an ECH in return" .IP "\fBSSL_ECH_STATUS_GREASE\fR 2, ECH GREASE happened" 4 .IX Item "SSL_ECH_STATUS_GREASE 2, ECH GREASE happened" .IP "\fBSSL_ECH_STATUS_SUCCESS\fR 1, Success" 4 .IX Item "SSL_ECH_STATUS_SUCCESS 1, Success" .IP "\fBSSL_ECH_STATUS_FAILED\fR 0, Some internal or protocol error" 4 .IX Item "SSL_ECH_STATUS_FAILED 0, Some internal or protocol error" .IP "\fBSSL_ECH_STATUS_BAD_CALL\fR \-100, Some in/out arguments were NULL" 4 .IX Item "SSL_ECH_STATUS_BAD_CALL -100, Some in/out arguments were NULL" .IP "\fBSSL_ECH_STATUS_NOT_TRIED\fR \-101, ECH wasn't attempted" 4 .IX Item "SSL_ECH_STATUS_NOT_TRIED -101, ECH wasn't attempted" .IP "\fBSSL_ECH_STATUS_BAD_NAME\fR \-102, ECH ok but server or client cert bad" 4 .IX Item "SSL_ECH_STATUS_BAD_NAME -102, ECH ok but server or client cert bad" .IP "\fBSSL_ECH_STATUS_NOT_CONFIGURED\fR \-103, ECH wasn't configured" 4 .IX Item "SSL_ECH_STATUS_NOT_CONFIGURED -103, ECH wasn't configured" .IP "\fBSSL_ECH_STATUS_FAILED_ECH\fR \-105, We tried, failed and got an ECH, from a verified name" 4 .IX Item "SSL_ECH_STATUS_FAILED_ECH -105, We tried, failed and got an ECH, from a verified name" .IP "\fBSSL_ECH_STATUS_FAILED_ECH_BAD_NAME\fR \-106, We tried, failed and got an ECH, from a bad name" 4 .IX Item "SSL_ECH_STATUS_FAILED_ECH_BAD_NAME -106, We tried, failed and got an ECH, from a bad name" .PD .PP \&\fBSSL_ech_set_callback()\fR, \fBSSL_CTX_ech_set_callback()\fR, \fBOSSL_ECHSTORE_free()\fR have no return value. .PP \&\fBSSL_CTX_get1_echstore()\fR, \fBSSL_get1_echstore()\fR and \fBOSSL_ECHSTORE_new()\fR return a pointer to an \fBOSSL_ECHSTORE\fR. .PP Note that \fBSSL_CTX_ech_set1_outer_alpn_protos()\fR and \&\fBSSL_ech_set1_outer_alpn_protos()\fR return zero on error and 1 on success. This is in contrast to \fBSSL_CTX_set_alpn_protos\fR\|(3) and \fBSSL_set_alpn_protos\fR\|(3) which (unusually for OpenSSL) return 0 on success and 1 on error. .SH "SEE ALSO" .IX Header "SEE ALSO" .IP "Encrypted ClientHello specification: " 4 .IX Item "Encrypted ClientHello specification: " .PD 0 .IP "ECH PEM file format specification: " 4 .IX Item "ECH PEM file format specification: " .IP "RFC8701: " 4 .IX Item "RFC8701: " .PD .PP ECH command line options are described in the manual pages for \&\fBopenssl\-s_client\fR\|(1), \fBopenssl\-s_server\fR\|(1) and \fBopenssl\-ech\fR\|(1). .SH HISTORY .IX Header "HISTORY" The functionality described here was added in OpenSSL 4.0. .SH COPYRIGHT .IX Header "COPYRIGHT" Copyright 2025\-2026 The OpenSSL Project Authors. All Rights Reserved. .PP Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy in the file LICENSE in the source distribution or at .