@@ -1003,6 +1003,13 @@ Constants
10031003
10041004 .. versionadded :: 3.6
10051005
1006+ .. class :: ECHStatus
1007+
1008+ :class: `enum.IntEnum ` collection of Encrypted Client Hello (ECH) statuses
1009+ returned by :meth: `SSLSocket.get_ech_status `.
1010+
1011+ .. versionadded :: next
1012+
10061013.. data :: Purpose.SERVER_AUTH
10071014
10081015 Option for :func: `create_default_context ` and
@@ -1307,6 +1314,22 @@ SSL sockets also have the following additional methods and attributes:
13071314
13081315 .. versionadded :: 3.3
13091316
1317+ .. method :: SSLSocket.get_ech_retry_config()
1318+
1319+ When the status returned by :meth: `SSLSocket.get_ech_status ` after completion of the
1320+ handshake is :data: `ECHStatus.ECH_STATUS_GREASE_ECH `, this method returns the
1321+ configuration value provided by the server to be used for a new connection using
1322+ ECH.
1323+
1324+ .. versionadded :: next
1325+
1326+ .. method :: SSLSocket.get_ech_status()
1327+
1328+ Gets the status of Encrypted Client Hello (ECH) processing. Returns an
1329+ :class: `ECHStatus ` instance.
1330+
1331+ .. versionadded :: next
1332+
13101333.. method :: SSLSocket.selected_alpn_protocol()
13111334
13121335 Return the protocol that was selected during the TLS handshake. If
@@ -1379,6 +1402,15 @@ SSL sockets also have the following additional methods and attributes:
13791402
13801403 .. versionadded :: 3.2
13811404
1405+ .. attribute :: SSLSocket.outer_server_hostname
1406+
1407+ Hostname of the server name used in the outer ClientHello when Encrypted Client
1408+ Hello (ECH) is used: :class: `str ` type, or ``None `` for server-side socket or
1409+ if the outer server name was not specified in the constructor or the ECH
1410+ configuration.
1411+
1412+ .. versionadded :: next
1413+
13821414.. attribute :: SSLSocket.server_side
13831415
13841416 A boolean which is ``True `` for server-side sockets and ``False `` for
@@ -1680,6 +1712,24 @@ to speed up repeated connections from the same clients.
16801712
16811713 .. versionadded :: 3.5
16821714
1715+ .. method :: SSLContext.set_ech_config(ech_config)
1716+
1717+ Sets an Encrypted Client Hello (ECH) configuration, which may be discovered from
1718+ an HTTPS resource record in DNS or from :meth: `SSLSocket.get_ech_retry_config `.
1719+ Multiple calls to this functions will accumulate the set of values available for
1720+ a connection.
1721+
1722+ If the input value provided contains no suitable value (e.g. if it only contains
1723+ ECH configuration versions that are not supported), an :class: `SSLError ` will be
1724+ raised.
1725+
1726+ The ech_config parameter should be a bytes-like object containing the raw ECH
1727+ configuration.
1728+
1729+ This method will raise :exc: `NotImplementedError ` if :data: `HAS_ECH ` is ``False ``.
1730+
1731+ .. versionadded :: next
1732+
16831733.. method :: SSLContext.set_npn_protocols(protocols)
16841734
16851735 Specify which protocols the socket should advertise during the SSL/TLS
@@ -1699,6 +1749,28 @@ to speed up repeated connections from the same clients.
16991749
17001750 NPN has been superseded by ALPN
17011751
1752+ .. method :: SSLContext.set_outer_alpn_protocols(protocols)
1753+
1754+ Specify which protocols the socket should advertise during the TLS
1755+ handshake in the outer ClientHello when ECH is used. The *protocols *
1756+ argument accepts the same values as for
1757+ :meth: `~SSLContext.set_alpn_protocols `.
1758+
1759+ This method will raise :exc: `NotImplementedError ` if :data: `HAS_ECH ` is
1760+ ``False ``.
1761+
1762+ .. versionadded :: next
1763+
1764+ .. method :: SSLContext.set_outer_server_hostname(server_hostname)
1765+
1766+ Specify which hostname the socket should advertise during the TLS
1767+ handshake in the outer ClientHello when ECH is used.
1768+
1769+ This method will raise :exc: `NotImplementedError ` if :data: `HAS_ECH ` is
1770+ ``False ``.
1771+
1772+ .. versionadded :: next
1773+
17021774.. attribute :: SSLContext.sni_callback
17031775
17041776 Register a callback function that will be called after the TLS Client Hello
@@ -2594,6 +2666,8 @@ provided.
25942666 - :meth: `~SSLSocket.verify_client_post_handshake `
25952667 - :meth: `~SSLSocket.unwrap `
25962668 - :meth: `~SSLSocket.get_channel_binding `
2669+ - :meth: `~SSLSocket.get_ech_retry_config `
2670+ - :meth: `~SSLSocket.get_ech_status `
25972671 - :meth: `~SSLSocket.version `
25982672
25992673 When compared to :class: `SSLSocket `, this object lacks the following
@@ -2813,6 +2887,52 @@ of TLS/SSL. Some new TLS 1.3 features are not yet available.
28132887- TLS 1.3 features like early data, deferred TLS client cert request,
28142888 signature algorithm configuration, and rekeying are not supported yet.
28152889
2890+ Encrypted Client Hello
2891+ ^^^^^^^^^^^^^^^^^^^^^^
2892+
2893+ .. versionadded :: next
2894+
2895+ Encrypted Client Hello (ECH) allows for encrypting values that have previously only been
2896+ included unencrypted in the ClientHello records when establishing a TLS connection. To use
2897+ ECH it is necessary to provide configuration values that contain a version, algorithm
2898+ parameters, the public key to use for HPKE encryption and the "public_name" that is by
2899+ default used for the unencrypted (outer) SNI when ECH is attempted. These configuration
2900+ values may be discovered through DNS or through the "retry config" mechanism.
2901+
2902+ The following example assumes that you have discovered a set of ECH configuration values
2903+ from DNS, or *ech_configs * may be an empty list to rely on the "retry config" mechanism::
2904+
2905+ import socket
2906+ import ssl
2907+
2908+
2909+ def connect_with_tls_ech(hostname: str, ech_configs: List[str],
2910+ use_retry_config: bool=True) -> ssl.SSLSocket:
2911+ context = ssl.create_default_context()
2912+ for ech_config in ech_configs:
2913+ context.set_ech_config(ech_config)
2914+ with socket.create_connection((hostname, 443)) as sock:
2915+ with context.wrap_socket(sock, server_hostname=hostname) as ssock:
2916+ if (ssock.get_ech_status == ECHStatus.ECH_STATUS_GREASE_ECH
2917+ and use_retry_config):
2918+ return connect_with_ech(hostname, [ssock.get_ech_retry_config()],
2919+ False)
2920+ return ssock
2921+
2922+ hostname = "www.python.org"
2923+ ech_configs = [] # Replace with a call to a function to lookup
2924+ # ECH configurations in DNS
2925+
2926+ ssock = connect_with_tls_ech(hostname, ech_configs)
2927+
2928+ The following classes, methods, and attributes will be useful for using ECH:
2929+
2930+ - :class: `ECHStatus `
2931+ - :meth: `SSLContext.set_ech_config `
2932+ - :meth: `SSLContext.set_outer_alpn_protocols `
2933+ - :meth: `SSLContext.set_outer_server_hostname `
2934+ - :meth: `SSLSocket.get_ech_status `
2935+ - :meth: `SSLSocket.get_ech_retry_config `
28162936
28172937.. seealso ::
28182938
0 commit comments