@@ -1003,6 +1003,13 @@ Constants
1003
1003
1004
1004
.. versionadded :: 3.6
1005
1005
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
+
1006
1013
.. data :: Purpose.SERVER_AUTH
1007
1014
1008
1015
Option for :func: `create_default_context ` and
@@ -1307,6 +1314,22 @@ SSL sockets also have the following additional methods and attributes:
1307
1314
1308
1315
.. versionadded :: 3.3
1309
1316
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
+
1310
1333
.. method :: SSLSocket.selected_alpn_protocol()
1311
1334
1312
1335
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:
1379
1402
1380
1403
.. versionadded :: 3.2
1381
1404
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
+
1382
1414
.. attribute :: SSLSocket.server_side
1383
1415
1384
1416
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.
1680
1712
1681
1713
.. versionadded :: 3.5
1682
1714
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
+
1683
1733
.. method :: SSLContext.set_npn_protocols(protocols)
1684
1734
1685
1735
Specify which protocols the socket should advertise during the SSL/TLS
@@ -1699,6 +1749,28 @@ to speed up repeated connections from the same clients.
169
23D3
9
1749
1700
1750
NPN has been superseded by ALPN
1701
1751
1752
+ .. method :: SSLContext.set_outer_alpn_protocols(protocols)
1753
+
1754
+ Specify which protocols the socket should advertise during the TLS
1755
+ handsh
F438
ake 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
+
1702
1774
.. attribute :: SSLContext.sni_callback
1703
1775
1704
1776
Register a callback function that will be called after the TLS Client Hello
@@ -2594,6 +2666,8 @@ provided.
2594
2666
- :meth: `~SSLSocket.verify_client_post_handshake `
2595
2667
- :meth: `~SSLSocket.unwrap `
2596
2668
- :meth: `~SSLSocket.get_channel_binding `
2669
+ - :meth: `~SSLSocket.get_ech_retry_config `
2670
+ - :meth: `~SSLSocket.get_ech_status `
2597
2671
- :meth: `~SSLSocket.version `
2598
2672
2599
2673
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.
2813
2887
- TLS 1.3 features like early data, deferred TLS client cert request,
2814
2888
signature algorithm configuration, and rekeying are not supported yet.
2815
2889
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 `
2816
2936
2817
2937
.. seealso ::
2818
2938
0 commit comments