@@ -869,6 +869,40 @@ Constants
869869
870870 .. versionadded :: 3.12
871871
872+ .. data :: OP_ECH_GREASE
873+
874+ Include a GREASE ECH extension in ClientHello messages when ECH is not
875+ being attempted. This can elicit an ECH retry configuration from a server.
876+
877+ Only available when :data: `HAS_ECH ` is ``True ``.
878+
879+ .. versionadded :: next
880+
881+ .. data :: OP_ECH_TRIALDECRYPT
882+
883+ Attempt server-side ECH decryption with all available ECH keys, rather
884+ than only those with a matching configuration identifier.
885+
886+ Only available when :data: `HAS_ECH ` is ``True ``.
887+
888+ .. versionadded :: next
889+
890+ .. data :: OP_ECH_IGNORE_CID
891+
892+ Use a random ECH configuration identifier in client connections.
893+
894+ Only available when :data: `HAS_ECH ` is ``True ``.
895+
896+ .. versionadded :: next
897+
898+ .. data :: OP_ECH_GREASE_RETRY_CONFIG
899+
900+ Include GREASE entries in the ECH retry configurations sent by a server.
901+
902+ Only available when :data: `HAS_ECH ` is ``True ``.
903+
904+ .. versionadded :: next
905+
872906.. data :: HAS_ALPN
873907
874908 Whether the OpenSSL library has built-in support for the *Application-Layer
@@ -964,6 +998,13 @@ Constants
964998
965999 .. versionadded :: 3.14
9661000
1001+ .. data :: HAS_ECH
1002+
1003+ Whether the OpenSSL library has built-in support for Encrypted Client
1004+ Hello (ECH). This requires OpenSSL 4.0 or later with ECH enabled.
1005+
1006+ .. versionadded :: next
1007+
9671008.. data :: CHANNEL_BINDING_TYPES
9681009
9691010 List of supported TLS channel binding types. Strings in this list
@@ -1039,6 +1080,12 @@ Constants
10391080
10401081 .. versionadded :: next
10411082
1083+ .. attribute :: ECHStatus.ECH_STATUS_GREASE_ECH
1084+
1085+ The client sent a GREASE ECH extension and received a retry configuration.
1086+
1087+ .. versionadded :: next
1088+
10421089.. data :: Purpose.SERVER_AUTH
10431090
10441091 Option for :func: `create_default_context ` and
@@ -1377,10 +1424,13 @@ SSL sockets also have the following additional methods and attributes:
13771424
13781425.. method :: SSLSocket.get_ech_retry_config()
13791426
1380- When the status returned by :meth: `SSLSocket.get_ech_status ` after completion of the
1381- handshake is :data: `ECHStatus.ECH_STATUS_GREASE_ECH `, this method returns the
1382- configuration value provided by the server to be used for a new connection using
1383- ECH.
1427+ Return the server's ECH retry configuration as :class: `bytes `, or empty
1428+ bytes if no retry configuration is available. When the status returned by
1429+ :meth: `SSLSocket.get_ech_status ` after the handshake is
1430+ :attr: `ECHStatus.ECH_STATUS_GREASE_ECH `, the configuration can be used
1431+ for a new connection using ECH.
1432+
1433+ Raise :exc: `NotImplementedError ` if :data: `HAS_ECH ` is ``False ``.
13841434
13851435 .. versionadded :: next
13861436
@@ -1389,6 +1439,8 @@ SSL sockets also have the following additional methods and attributes:
13891439 Gets the status of Encrypted Client Hello (ECH) processing. Returns an
13901440 :class: `ECHStatus ` instance.
13911441
1442+ Raise :exc: `NotImplementedError ` if :data: `HAS_ECH ` is ``False ``.
1443+
13921444 .. versionadded :: next
13931445
13941446.. method :: SSLSocket.selected_alpn_protocol()
@@ -1467,8 +1519,10 @@ SSL sockets also have the following additional methods and attributes:
14671519
14681520 Hostname of the server name used in the outer ClientHello when Encrypted Client
14691521 Hello (ECH) is used: :class: `str ` type, or ``None `` for server-side socket or
1470- if the outer server name was not specified in the constructor or the ECH
1471- configuration.
1522+ if no outer server name is available.
1523+
1524+ Raise :exc: `NotImplementedError ` if :data: `HAS_ECH ` is ``False `` and the
1525+ socket has an SSL wrapper.
14721526
14731527 .. versionadded :: next
14741528
@@ -1852,15 +1906,14 @@ to speed up repeated connections from the same clients.
18521906
18531907 Sets an Encrypted Client Hello (ECH) configuration, which may be discovered from
18541908 an HTTPS resource record in DNS or from :meth: `SSLSocket.get_ech_retry_config `.
1855- Multiple calls to this functions will accumulate the set of values available for
1856- a connection.
1909+ Each call replaces the context's previous configuration.
18571910
18581911 If the input value provided contains no suitable value (e.g. if it only contains
18591912 ECH configuration versions that are not supported), an :class: `SSLError ` will be
18601913 raised.
18611914
1862- The ech_config parameter should be a bytes-like object containing the raw ECH
1863- configuration .
1915+ The * ech_config * parameter should be a :term: ` bytes-like object ` containing
1916+ a binary-encoded ECHConfigList .
18641917
18651918 This method will raise :exc: `NotImplementedError ` if :data: `HAS_ECH ` is ``False ``.
18661919
@@ -1897,16 +1950,6 @@ to speed up repeated connections from the same clients.
18971950
18981951 .. versionadded :: next
18991952
1900- .. method :: SSLContext.set_outer_server_hostname(server_hostname)
1901-
1902- Specify which hostname the socket should advertise during the TLS
1903- handshake in the outer ClientHello when ECH is used.
1904-
1905- This method will raise :exc: `NotImplementedError ` if :data: `HAS_ECH ` is
1906- ``False ``.
1907-
1908- .. versionadded :: next
1909-
19101953.. attribute :: SSLContext.sni_callback
19111954
19121955 Register a callback function that will be called after the TLS Client Hello
@@ -3051,50 +3094,61 @@ of TLS/SSL. Some new TLS 1.3 features are not yet available.
30513094- TLS 1.3 features like early data, deferred TLS client cert request,
30523095 and rekeying are not supported yet.
30533096
3097+ .. _ssl-encrypted-client-hello :
3098+
30543099Encrypted Client Hello
30553100^^^^^^^^^^^^^^^^^^^^^^
30563101
30573102.. versionadded :: next
30583103
3059- Encrypted Client Hello (ECH) allows for encrypting values that have previously only been
3060- included unencrypted in the ClientHello records when establishing a TLS connection. To use
3061- ECH it is necessary to provide configuration values that contain a version, algorithm
3062- parameters, the public key to use for HPKE encryption and the "public_name" that is by
3063- default used for the unencrypted (outer) SNI when ECH is attempted. These configuration
3064- values may be discovered through DNS or through the "retry config" mechanism.
3104+ Encrypted Client Hello (ECH) encrypts values in the ClientHello record sent when
3105+ establishing a TLS connection. It requires an ECHConfigList containing algorithm
3106+ parameters, a public key, and a public name used in the unencrypted outer
3107+ ClientHello. ECH requires OpenSSL 4.0 or later with ECH enabled; check
3108+ :data: `HAS_ECH ` before using it.
30653109
3066- The following example assumes that you have discovered a set of ECH configuration values
3067- from DNS, or *ech_configs * may be an empty list to rely on the "retry config" mechanism::
3110+ Configuration values may be discovered through DNS or through the server's
3111+ retry configuration. The following example accepts a binary-encoded
3112+ ECHConfigList discovered through DNS. If none is supplied, it enables ECH
3113+ GREASE to request a retry configuration from the server::
30683114
30693115 import socket
30703116 import ssl
30713117
30723118
3073- def connect_with_tls_ech(hostname: str, ech_configs: List[str],
3074- use_retry_config: bool=True) -> ssl.SSLSocket:
3119+ def connect_with_tls_ech(hostname, ech_config=None, use_retry_config=True):
30753120 context = ssl.create_default_context()
3076- for ech_config in ech_configs :
3121+ if ech_config is not None :
30773122 context.set_ech_config(ech_config)
3078- with socket.create_connection((hostname, 443)) as sock:
3079- with context.wrap_socket(sock, server_hostname=hostname) as ssock:
3080- if (ssock.get_ech_status == ECHStatus.ECH_STATUS_GREASE_ECH
3081- and use_retry_config):
3082- return connect_with_ech(hostname, [ssock.get_ech_retry_config()],
3083- False)
3084- return ssock
3123+ else:
3124+ context.options |= ssl.OP_ECH_GREASE
3125+ sock = socket.create_connection((hostname, 443))
3126+ try:
3127+ ssock = context.wrap_socket(sock, server_hostname=hostname)
3128+ except BaseException:
3129+ sock.close()
3130+ raise
3131+ if (use_retry_config
3132+ and ssock.get_ech_status()
3133+ == ssl.ECHStatus.ECH_STATUS_GREASE_ECH):
3134+ try:
3135+ retry_config = ssock.get_ech_retry_config()
3136+ finally:
3137+ ssock.close()
3138+ return connect_with_tls_ech(hostname, retry_config, False)
3139+ return ssock
30853140
30863141 hostname = "www.python.org"
3087- ech_configs = [] # Replace with a call to a function to lookup
3088- # ECH configurations in DNS
3142+ ech_config = None # Replace with an ECHConfigList discovered through DNS.
30893143
3090- ssock = connect_with_tls_ech(hostname, ech_configs)
3144+ with connect_with_tls_ech(hostname, ech_config) as ssock:
3145+ print(ssock.get_ech_status())
30913146
30923147The following classes, methods, and attributes will be useful for using ECH:
30933148
30943149 - :class: `ECHStatus `
30953150 - :meth: `SSLContext.set_ech_config `
30963151 - :meth: `SSLContext.set_outer_alpn_protocols `
3097- - :meth: `SSLContext.set_outer_server_hostname `
30983152 - :meth: `SSLSocket.get_ech_status `
30993153 - :meth: `SSLSocket.get_ech_retry_config `
31003154
0 commit comments