@@ -1032,6 +1032,13 @@ Constants
10321032
10331033 .. versionadded :: 3.6
10341034
1035+ .. class :: ECHStatus
1036+
1037+ :class: `enum.IntEnum ` collection of Encrypted Client Hello (ECH) statuses
1038+ returned by :meth: `SSLSocket.get_ech_status `.
1039+
1040+ .. versionadded :: next
1041+
10351042.. data :: Purpose.SERVER_AUTH
10361043
10371044 Option for :func: `create_default_context ` and
@@ -1368,6 +1375,22 @@ SSL sockets also have the following additional methods and attributes:
13681375
13691376 .. versionadded :: 3.3
13701377
1378+ .. method :: SSLSocket.get_ech_retry_config()
1379+
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.
1384+
1385+ .. versionadded :: next
1386+
1387+ .. method :: SSLSocket.get_ech_status()
1388+
1389+ Gets the status of Encrypted Client Hello (ECH) processing. Returns an
1390+ :class: `ECHStatus ` instance.
1391+
1392+ .. versionadded :: next
1393+
13711394.. method :: SSLSocket.selected_alpn_protocol()
13721395
13731396 Return the protocol that was selected during the TLS handshake. If
@@ -1440,6 +1463,15 @@ SSL sockets also have the following additional methods and attributes:
14401463
14411464 .. versionadded :: 3.2
14421465
1466+ .. attribute :: SSLSocket.outer_server_hostname
1467+
1468+ Hostname of the server name used in the outer ClientHello when Encrypted Client
1469+ 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.
1472+
1473+ .. versionadded :: next
1474+
14431475.. attribute :: SSLSocket.server_side
14441476
14451477 A boolean which is ``True `` for server-side sockets and ``False `` for
@@ -1816,6 +1848,24 @@ to speed up repeated connections from the same clients.
18161848
18171849 .. versionadded :: 3.5
18181850
1851+ .. method :: SSLContext.set_ech_config(ech_config)
1852+
1853+ Sets an Encrypted Client Hello (ECH) configuration, which may be discovered from
1854+ 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.
1857+
1858+ If the input value provided contains no suitable value (e.g. if it only contains
1859+ ECH configuration versions that are not supported), an :class: `SSLError ` will be
1860+ raised.
1861+
1862+ The ech_config parameter should be a bytes-like object containing the raw ECH
1863+ configuration.
1864+
1865+ This method will raise :exc: `NotImplementedError ` if :data: `HAS_ECH ` is ``False ``.
1866+
1867+ .. versionadded :: next
1868+
18191869.. method :: SSLContext.set_npn_protocols(npn_protocols)
18201870
18211871 Specify which protocols the socket should advertise during the SSL/TLS
@@ -1835,6 +1885,28 @@ to speed up repeated connections from the same clients.
18351885
18361886 NPN has been superseded by ALPN
18371887
1888+ .. method :: SSLContext.set_outer_alpn_protocols(protocols)
1889+
1890+ Specify which protocols the socket should advertise during the TLS
1891+ handshake in the outer ClientHello when ECH is used. The *protocols *
1892+ argument accepts the same values as for
1893+ :meth: `~SSLContext.set_alpn_protocols `.
1894+
1895+ This method will raise :exc: `NotImplementedError ` if :data: `HAS_ECH ` is
1896+ ``False ``.
1897+
1898+ .. versionadded :: next
1899+
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+
18381910.. attribute :: SSLContext.sni_callback
18391911
18401912 Register a callback function that will be called after the TLS Client Hello
@@ -2753,6 +2825,8 @@ provided.
27532825 - :meth: `~SSLSocket.verify_client_post_handshake `
27542826 - :meth: `~SSLSocket.unwrap `
27552827 - :meth: `~SSLSocket.get_channel_binding `
2828+ - :meth: `~SSLSocket.get_ech_retry_config `
2829+ - :meth: `~SSLSocket.get_ech_status `
27562830 - :meth: `~SSLSocket.version `
27572831
27582832 When compared to :class: `SSLSocket `, this object lacks the following
@@ -2977,6 +3051,52 @@ of TLS/SSL. Some new TLS 1.3 features are not yet available.
29773051- TLS 1.3 features like early data, deferred TLS client cert request,
29783052 and rekeying are not supported yet.
29793053
3054+ Encrypted Client Hello
3055+ ^^^^^^^^^^^^^^^^^^^^^^
3056+
3057+ .. versionadded :: next
3058+
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.
3065+
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::
3068+
3069+ import socket
3070+ import ssl
3071+
3072+
3073+ def connect_with_tls_ech(hostname: str, ech_configs: List[str],
3074+ use_retry_config: bool=True) -> ssl.SSLSocket:
3075+ context = ssl.create_default_context()
3076+ for ech_config in ech_configs:
3077+ 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
3085+
3086+ hostname = "www.python.org"
3087+ ech_configs = [] # Replace with a call to a function to lookup
3088+ # ECH configurations in DNS
3089+
3090+ ssock = connect_with_tls_ech(hostname, ech_configs)
3091+
3092+ The following classes, methods, and attributes will be useful for using ECH:
3093+
3094+ - :class: `ECHStatus `
3095+ - :meth: `SSLContext.set_ech_config `
3096+ - :meth: `SSLContext.set_outer_alpn_protocols `
3097+ - :meth: `SSLContext.set_outer_server_hostname `
3098+ - :meth: `SSLSocket.get_ech_status `
3099+ - :meth: `SSLSocket.get_ech_retry_config `
29803100
29813101.. seealso ::
29823102
0 commit comments