From 08b69e050540fe529cc835ac3665f59236868bb0 Mon Sep 17 00:00:00 2001 From: Julien Castiaux Date: Wed, 29 Apr 2026 01:59:54 +0200 Subject: [PATCH 1/5] PEP 748: ConfigurationError typo --- peps/pep-0748.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peps/pep-0748.rst b/peps/pep-0748.rst index 333c24fe432..4cd422baad6 100644 --- a/peps/pep-0748.rst +++ b/peps/pep-0748.rst @@ -1072,7 +1072,7 @@ The definitions of the errors are below: class ConfigurationError(TLSError): - """An special exception that implementations can use when the provided + """A special exception that implementations can use when the provided configuration uses features not supported by that implementation.""" From b3229ec84b803a0b4240c1287b66eb3f9c33bf1e Mon Sep 17 00:00:00 2001 From: Julien Castiaux Date: Wed, 29 Apr 2026 02:01:21 +0200 Subject: [PATCH 2/5] PEP 748: ConfigurationError is only for unsupported features --- peps/pep-0748.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/peps/pep-0748.rst b/peps/pep-0748.rst index 4cd422baad6..c5584a3bb3c 100644 --- a/peps/pep-0748.rst +++ b/peps/pep-0748.rst @@ -1073,7 +1073,9 @@ The definitions of the errors are below: class ConfigurationError(TLSError): """A special exception that implementations can use when the provided - configuration uses features not supported by that implementation.""" + configuration uses features not supported by that implementation. Do not + use this exception when the provided configuration is invalid, use + standard exceptions instead.""" Certificates From 6d41ae76dbec07fc51c3048eb7a8ab739c3600a6 Mon Sep 17 00:00:00 2001 From: Julien Castiaux Date: Tue, 28 Apr 2026 23:01:19 +0200 Subject: [PATCH 3/5] PEP 748: materialize the server configuration Ease reading the diff of the next commits. --- peps/pep-0748.rst | 65 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/peps/pep-0748.rst b/peps/pep-0748.rst index c5584a3bb3c..774144a581f 100644 --- a/peps/pep-0748.rst +++ b/peps/pep-0748.rst @@ -252,6 +252,9 @@ backwards-compatibility purposes, new fields are only appended to these objects. Existing fields will never be removed, renamed, or reordered. They are split between client and server to minimize API confusion. +Client Configuration +^^^^^^^^^^^^^^^^^^^^ + The ``TLSClientConfiguration`` class would be defined by the following code: .. code-block:: python @@ -309,8 +312,66 @@ The ``TLSClientConfiguration`` class would be defined by the following code: def trust_store(self) -> TrustStore | None: return self._trust_store -The ``TLSServerConfiguration`` object is similar to the client one, except that -it takes a ``Sequence[SigningChain]`` as the ``certificate_chain`` parameter. +Server Configuration +^^^^^^^^^^^^^^^^^^^^ + +The ``TLSServerConfiguration`` class would be defined by the following code: + +.. code-block:: python + + class TLSServerConfiguration: + __slots__ = ( + "_certificate_chain", + "_ciphers", + "_inner_protocols", + "_lowest_supported_version", + "_highest_supported_version", + "_trust_store", + ) + + def __init__( + self, + certificate_chain: Sequence[SigningChain] | None = None, + ciphers: Sequence[CipherSuite] | None = None, + inner_protocols: Sequence[NextProtocol | bytes] | None = None, + lowest_supported_version: TLSVersion | None = None, + highest_supported_version: TLSVersion | None = None, + trust_store: TrustStore | None = None, + ) -> None: + if inner_protocols is None: + inner_protocols = [] + + self._certificate_chain = certificate_chain + self._ciphers = ciphers + self._inner_protocols = inner_protocols + self._lowest_supported_version = lowest_supported_version + self._highest_supported_version = highest_supported_version + self._trust_store = trust_store + + @property + def certificate_chain(self) -> Sequence[SigningChain] | None: + return self._certificate_chain + + @property + def ciphers(self) -> Sequence[CipherSuite | int] | None: + return self._ciphers + + @property + def inner_protocols(self) -> Sequence[NextProtocol | bytes]: + return self._inner_protocols + + @property + def lowest_supported_version(self) -> TLSVersion | None: + return self._lowest_supported_version + + @property + def highest_supported_version(self) -> TLSVersion | None: + return self._highest_supported_version + + @property + def trust_store(self) -> TrustStore | None: + return self._trust_store + Context ~~~~~~~ From 6e61445101d6657d90de403ed722395b6d2ec4c7 Mon Sep 17 00:00:00 2001 From: Julien Castiaux Date: Tue, 28 Apr 2026 23:03:18 +0200 Subject: [PATCH 4/5] PEP 748: disambiguate config trust_store=None Client-side `trust_store=None` means `TrustStore.system()` but server-side it means "skip client authentication". One could think it means "skip server authentication" when used client-side, so let's not support `None` at all client-side and instead default to `TrustStore.system()`. --- peps/pep-0748.rst | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/peps/pep-0748.rst b/peps/pep-0748.rst index 774144a581f..2146efb4596 100644 --- a/peps/pep-0748.rst +++ b/peps/pep-0748.rst @@ -276,7 +276,7 @@ The ``TLSClientConfiguration`` class would be defined by the following code: inner_protocols: Sequence[NextProtocol | bytes] | None = None, lowest_supported_version: TLSVersion | None = None, highest_supported_version: TLSVersion | None = None, - trust_store: TrustStore | None = None, + trust_store: TrustStore = TrustStore.system(), ) -> None: if inner_protocols is None: inner_protocols = [] @@ -309,9 +309,13 @@ The ``TLSClientConfiguration`` class would be defined by the following code: return self._highest_supported_version @property - def trust_store(self) -> TrustStore | None: + def trust_store(self) -> TrustStore: return self._trust_store +A ``trust_store`` is mandatory and is used to validate the server certificates. +It uses the system's trust store by default. Insecure connections are only +possible via the :ref:`insecure` module. + Server Configuration ^^^^^^^^^^^^^^^^^^^^ @@ -372,6 +376,9 @@ The ``TLSServerConfiguration`` class would be defined by the following code: def trust_store(self) -> TrustStore | None: return self._trust_store +A ``trust_store`` is optional. Setting one enables client authentication and +uses the trust store to validate the client certificates. Leaving it ``None`` +disables client authentication. Context ~~~~~~~ @@ -1503,6 +1510,8 @@ Note that this function only needs to verify that supported constructors were used for the certificates, private keys, and trust store. It does not need to parse or retrieve the objects to validate them further. +.. _insecure: + Insecure Usage -------------- From ea0b73f34c78b034e0ace18b5d7738e5efc2d125 Mon Sep 17 00:00:00 2001 From: Julien Castiaux Date: Tue, 28 Apr 2026 23:02:16 +0200 Subject: [PATCH 5/5] PEP 748: certificate_chain is mandatory server-side TLS 1.3 and secure TLS 1.2 both require a certificate and private key server-side. Making the parameter mandatory makes it explicit that one is required. It still is optional client-side. --- peps/pep-0748.rst | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/peps/pep-0748.rst b/peps/pep-0748.rst index 2146efb4596..54b8b9f1adc 100644 --- a/peps/pep-0748.rst +++ b/peps/pep-0748.rst @@ -316,6 +316,11 @@ A ``trust_store`` is mandatory and is used to validate the server certificates. It uses the system's trust store by default. Insecure connections are only possible via the :ref:`insecure` module. +When ``certificate_chain`` is set, it is a single signing chain comprising a +leaf client certificate including its corresponding private key and optionally a +list of intermediate certificates. These certificates will be offered to the +server during the handshake if required. + Server Configuration ^^^^^^^^^^^^^^^^^^^^ @@ -335,7 +340,7 @@ The ``TLSServerConfiguration`` class would be defined by the following code: def __init__( self, - certificate_chain: Sequence[SigningChain] | None = None, + certificate_chain: Sequence[SigningChain], ciphers: Sequence[CipherSuite] | None = None, inner_protocols: Sequence[NextProtocol | bytes] | None = None, lowest_supported_version: TLSVersion | None = None, @@ -353,7 +358,7 @@ The ``TLSServerConfiguration`` class would be defined by the following code: self._trust_store = trust_store @property - def certificate_chain(self) -> Sequence[SigningChain] | None: + def certificate_chain(self) -> Sequence[SigningChain]: return self._certificate_chain @property @@ -376,6 +381,11 @@ The ``TLSServerConfiguration`` class would be defined by the following code: def trust_store(self) -> TrustStore | None: return self._trust_store +Server authentication is mandatory, at least one signing chain comprising a leaf +server certificate including its corresponding private key and optionally a list +of intermediate certificates. It is possible to set more than a single signing +chain to support multiple virtual hosts. + A ``trust_store`` is optional. Setting one enables client authentication and uses the trust store to validate the client certificates. Leaving it ``None`` disables client authentication.