CINXE.COM

PEP 543 – A Unified TLS API for Python | peps.python.org

<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="color-scheme" content="light dark"> <title>PEP 543 – A Unified TLS API for Python | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0543/"> <link rel="stylesheet" href="../_static/style.css" type="text/css"> <link rel="stylesheet" href="../_static/mq.css" type="text/css"> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light"> <link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark"> <link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss"> <meta property="og:title" content='PEP 543 – A Unified TLS API for Python | peps.python.org'> <meta property="og:description" content="This PEP would define a standard TLS interface in the form of a collection of abstract base classes. This interface would allow Python implementations and third-party libraries to provide bindings to TLS libraries other than OpenSSL that can be used by ..."> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0543/"> <meta property="og:site_name" content="Python Enhancement Proposals (PEPs)"> <meta property="og:image" content="https://peps.python.org/_static/og-image.png"> <meta property="og:image:alt" content="Python PEPs"> <meta property="og:image:width" content="200"> <meta property="og:image:height" content="200"> <meta name="description" content="This PEP would define a standard TLS interface in the form of a collection of abstract base classes. This interface would allow Python implementations and third-party libraries to provide bindings to TLS libraries other than OpenSSL that can be used by ..."> <meta name="theme-color" content="#3776ab"> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all"> <title>Following system colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="9"></circle> <path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path> </svg> </symbol> <symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all"> <title>Selected dark colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path> </svg> </symbol> <symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all"> <title>Selected light colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="5"></circle> <line x1="12" y1="1" x2="12" y2="3"></line> <line x1="12" y1="21" x2="12" y2="23"></line> <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line> <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line> <line x1="1" y1="12" x2="3" y2="12"></line> <line x1="21" y1="12" x2="23" y2="12"></line> <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line> <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line> </svg> </symbol> </svg> <script> document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto" </script> <section id="pep-page-section"> <header> <h1>Python Enhancement Proposals</h1> <ul class="breadcrumbs"> <li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> &raquo; </li> <li><a href="../pep-0000/">PEP Index</a> &raquo; </li> <li>PEP 543</li> </ul> <button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())"> <svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg> <svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg> <svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg> <span class="visually-hidden">Toggle light / dark / auto colour theme</span> </button> </header> <article> <section id="pep-content"> <h1 class="page-title">PEP 543 – A Unified TLS API for Python</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Cory Benfield &lt;cory&#32;&#97;t&#32;lukasa.co.uk&gt;, Christian Heimes &lt;christian&#32;&#97;t&#32;python.org&gt;</dd> <dt class="field-even">Status<span class="colon">:</span></dt> <dd class="field-even"><abbr title="Removed from consideration by sponsor or authors">Withdrawn</abbr></dd> <dt class="field-odd">Type<span class="colon">:</span></dt> <dd class="field-odd"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd> <dt class="field-even">Created<span class="colon">:</span></dt> <dd class="field-even">17-Oct-2016</dd> <dt class="field-odd">Python-Version<span class="colon">:</span></dt> <dd class="field-odd">3.7</dd> <dt class="field-even">Post-History<span class="colon">:</span></dt> <dd class="field-even">11-Jan-2017, 19-Jan-2017, 02-Feb-2017, 09-Feb-2017</dd> <dt class="field-odd">Superseded-By<span class="colon">:</span></dt> <dd class="field-odd"><a class="reference external" href="../pep-0748/">748</a></dd> </dl> <hr class="docutils" /> <section id="contents"> <details><summary>Table of Contents</summary><ul class="simple"> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#resolution">Resolution</a></li> <li><a class="reference internal" href="#rationale">Rationale</a><ul> <li><a class="reference internal" href="#problems">Problems</a></li> </ul> </li> <li><a class="reference internal" href="#proposal">Proposal</a><ul> <li><a class="reference internal" href="#interfaces">Interfaces</a><ul> <li><a class="reference internal" href="#configuration">Configuration</a></li> <li><a class="reference internal" href="#context">Context</a></li> <li><a class="reference internal" href="#buffer">Buffer</a></li> <li><a class="reference internal" href="#socket">Socket</a></li> <li><a class="reference internal" href="#cipher-suites">Cipher Suites</a><ul> <li><a class="reference internal" href="#openssl">OpenSSL</a></li> <li><a class="reference internal" href="#securetransport">SecureTransport</a></li> <li><a class="reference internal" href="#schannel">SChannel</a></li> <li><a class="reference internal" href="#network-security-services-nss">Network Security Services (NSS)</a></li> <li><a class="reference internal" href="#proposed-interface">Proposed Interface</a></li> </ul> </li> <li><a class="reference internal" href="#protocol-negotiation">Protocol Negotiation</a></li> <li><a class="reference internal" href="#tls-versions">TLS Versions</a></li> <li><a class="reference internal" href="#errors">Errors</a></li> <li><a class="reference internal" href="#certificates">Certificates</a></li> <li><a class="reference internal" href="#private-keys">Private Keys</a></li> <li><a class="reference internal" href="#trust-store">Trust Store</a></li> <li><a class="reference internal" href="#runtime-access">Runtime Access</a></li> </ul> </li> </ul> </li> <li><a class="reference internal" href="#changes-to-the-standard-library">Changes to the Standard Library</a><ul> <li><a class="reference internal" href="#migration-of-the-ssl-module">Migration of the ssl module</a></li> </ul> </li> <li><a class="reference internal" href="#future">Future</a></li> <li><a class="reference internal" href="#credits">Credits</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> </details></section> <section id="abstract"> <h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2> <p>This PEP would define a standard TLS interface in the form of a collection of abstract base classes. This interface would allow Python implementations and third-party libraries to provide bindings to TLS libraries other than OpenSSL that can be used by tools that expect the interface provided by the Python standard library, with the goal of reducing the dependence of the Python ecosystem on OpenSSL.</p> </section> <section id="resolution"> <h2><a class="toc-backref" href="#resolution" role="doc-backlink">Resolution</a></h2> <p>2020-06-25: With contemporary agreement with one author, and past agreement with another, this PEP is withdrawn due to changes in the APIs of the underlying operating systems.</p> </section> <section id="rationale"> <h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2> <p>In the 21st century it has become increasingly clear that robust and user-friendly TLS support is an extremely important part of the ecosystem of any popular programming language. For most of its lifetime, this role in the Python ecosystem has primarily been served by the <a class="reference external" href="https://docs.python.org/3/library/ssl.html">ssl module</a>, which provides a Python API to the <a class="reference external" href="https://www.openssl.org/">OpenSSL library</a>.</p> <p>Because the <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module is distributed with the Python standard library, it has become the overwhelmingly most-popular method for handling TLS in Python. An extraordinary majority of Python libraries, both in the standard library and on the Python Package Index, rely on the <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module for their TLS connectivity.</p> <p>Unfortunately, the preeminence of the <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module has had a number of unforeseen side-effects that have had the effect of tying the entire Python ecosystem tightly to OpenSSL. This has forced Python users to use OpenSSL even in situations where it may provide a worse user experience than alternative TLS implementations, which imposes a cognitive burden and makes it hard to provide “platform-native” experiences.</p> <section id="problems"> <h3><a class="toc-backref" href="#problems" role="doc-backlink">Problems</a></h3> <p>The fact that the <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module is built into the standard library has meant that all standard-library Python networking libraries are entirely reliant on the OpenSSL that the Python implementation has been linked against. This leads to the following issues:</p> <ul> <li>It is difficult to take advantage of new, higher-security TLS without recompiling Python to get a new OpenSSL. While there are third-party bindings to OpenSSL (e.g. <a class="reference external" href="https://pypi.org/project/pyOpenSSL/">pyOpenSSL</a>), these need to be shimmed into a format that the standard library understands, forcing projects that want to use them to maintain substantial compatibility layers.</li> <li>For Windows distributions of Python, they need to be shipped with a copy of OpenSSL. This puts the CPython development team in the position of being OpenSSL redistributors, potentially needing to ship security updates to the Windows Python distributions when OpenSSL vulnerabilities are released.</li> <li>For macOS distributions of Python, they need either to be shipped with a copy of OpenSSL or linked against the system OpenSSL library. Apple has formally deprecated linking against the system OpenSSL library, and even if they had not, that library version has been unsupported by upstream for nearly one year as of the time of writing. The CPython development team has started shipping newer OpenSSLs with the Python available from python.org, but this has the same problem as with Windows.</li> <li>Many systems, including but not limited to Windows and macOS, do not make their system certificate stores available to OpenSSL. This forces users to either obtain their trust roots from elsewhere (e.g. <a class="reference external" href="https://pypi.org/project/certifi/">certifi</a>) or to attempt to export their system trust stores in some form.<p>Relying on <a class="reference external" href="https://pypi.org/project/certifi/">certifi</a> is less than ideal, as most system administrators do not expect to receive security-critical software updates from PyPI. Additionally, it is not easy to extend the <a class="reference external" href="https://pypi.org/project/certifi/">certifi</a> trust bundle to include custom roots, or to centrally manage trust using the <a class="reference external" href="https://pypi.org/project/certifi/">certifi</a> model.</p> <p>Even in situations where the system certificate stores are made available to OpenSSL in some form, the experience is still sub-standard, as OpenSSL will perform different validation checks than the platform-native TLS implementation. This can lead to users experiencing different behaviour on their browsers or other platform-native tools than they experience in Python, with little or no recourse to resolve the problem.</p> </li> <li>Users may wish to integrate with TLS libraries other than OpenSSL for many other reasons, such as OpenSSL missing features (e.g. TLS 1.3 support), or because OpenSSL is simply too large and unwieldy for the platform (e.g. for embedded Python). Those users are left with the requirement to use third-party networking libraries that can interact with their preferred TLS library or to shim their preferred library into the OpenSSL-specific <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module API.</li> </ul> <p>Additionally, the <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module as implemented today limits the ability of CPython itself to add support for alternative TLS backends, or remove OpenSSL support entirely, should either of these become necessary or useful. The <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module exposes too many OpenSSL-specific function calls and features to easily map to an alternative TLS backend.</p> </section> </section> <section id="proposal"> <h2><a class="toc-backref" href="#proposal" role="doc-backlink">Proposal</a></h2> <p>This PEP proposes to introduce a few new Abstract Base Classes in Python 3.7 to provide TLS functionality that is not so strongly tied to OpenSSL. It also proposes to update standard library modules to use only the interface exposed by these abstract base classes wherever possible. There are three goals here:</p> <ol class="arabic simple"> <li>To provide a common API surface for both core and third-party developers to target their TLS implementations to. This allows TLS developers to provide interfaces that can be used by most Python code, and allows network developers to have an interface that they can target that will work with a wide range of TLS implementations.</li> <li>To provide an API that has few or no OpenSSL-specific concepts leak through. The <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module today has a number of warts caused by leaking OpenSSL concepts through to the API: the new ABCs would remove those specific concepts.</li> <li>To provide a path for the core development team to make OpenSSL one of many possible TLS backends, rather than requiring that it be present on a system in order for Python to have TLS support.</li> </ol> <p>The proposed interface is laid out below.</p> <section id="interfaces"> <h3><a class="toc-backref" href="#interfaces" role="doc-backlink">Interfaces</a></h3> <p>There are several interfaces that require standardisation. Those interfaces are:</p> <ol class="arabic simple"> <li>Configuring TLS, currently implemented by the <a class="reference external" href="https://docs.python.org/3/library/ssl.html#ssl.SSLContext">SSLContext</a> class in the <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module.</li> <li>Providing an in-memory buffer for doing in-memory encryption or decryption with no actual I/O (necessary for asynchronous I/O models), currently implemented by the <a class="reference external" href="https://docs.python.org/3/library/ssl.html#ssl.SSLObject">SSLObject</a> class in the <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module.</li> <li>Wrapping a socket object, currently implemented by the <a class="reference external" href="https://docs.python.org/3/library/ssl.html#ssl.SSLSocket">SSLSocket</a> class in the <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module.</li> <li>Applying TLS configuration to the wrapping objects in (2) and (3). Currently this is also implemented by the <a class="reference external" href="https://docs.python.org/3/library/ssl.html#ssl.SSLContext">SSLContext</a> class in the <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module.</li> <li>Specifying TLS cipher suites. There is currently no code for doing this in the standard library: instead, the standard library uses OpenSSL cipher suite strings.</li> <li>Specifying application-layer protocols that can be negotiated during the TLS handshake.</li> <li>Specifying TLS versions.</li> <li>Reporting errors to the caller, currently implemented by the <a class="reference external" href="https://docs.python.org/3/library/ssl.html#ssl.SSLError">SSLError</a> class in the <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module.</li> <li>Specifying certificates to load, either as client or server certificates.</li> <li>Specifying which trust database should be used to validate certificates presented by a remote peer.</li> <li>Finding a way to get hold of these interfaces at run time.</li> </ol> <p>For the sake of simplicity, this PEP proposes to take a unified approach to (2) and (3) (that is, buffers and sockets). The Python socket API is a sizeable one, and implementing a wrapped socket that has the same behaviour as a regular Python socket is a subtle and tricky thing to do. However, it is entirely possible to implement a <em>generic</em> wrapped socket in terms of wrapped buffers: that is, it is possible to write a wrapped socket (3) that will work for any implementation that provides (2). For this reason, this PEP proposes to provide an ABC for wrapped buffers (2) but a concrete class for wrapped sockets (3).</p> <p>This decision has the effect of making it impossible to bind a small number of TLS libraries to this ABC, because those TLS libraries <em>cannot</em> provide a wrapped buffer implementation. The most notable of these at this time appears to be Amazon’s <a class="reference external" href="https://github.com/awslabs/s2n">s2n</a>, which currently does not provide an I/O abstraction layer. However, even this library consider this a missing feature and are <a class="reference external" href="https://github.com/awslabs/s2n/issues/358">working to add it</a>. For this reason, it is safe to assume that a concrete implementation of (3) in terms of (2) will be a substantial effort-saving device and a great tool for correctness. Therefore, this PEP proposes doing just that.</p> <p>Obviously, (5) doesn’t require an abstract base class: instead, it requires a richer API for configuring supported cipher suites that can be easily updated with supported cipher suites for different implementations.</p> <p>(9) is a thorny problem, because in an ideal world the private keys associated with these certificates would never end up in-memory in the Python process (that is, the TLS library would collaborate with a Hardware Security Module (HSM) to provide the private key in such a way that it cannot be extracted from process memory). Thus, we need to provide an extensible model of providing certificates that allows concrete implementations the ability to provide this higher level of security, while also allowing a lower bar for those implementations that cannot. This lower bar would be the same as the status quo: that is, the certificate may be loaded from an in-memory buffer or from a file on disk.</p> <p>(10) also represents an issue because different TLS implementations vary wildly in how they allow users to select trust stores. Some implementations have specific trust store formats that only they can use (such as the OpenSSL CA directory format that is created by <code class="docutils literal notranslate"><span class="pre">c_rehash</span></code>), and others may not allow you to specify a trust store that does not include their default trust store.</p> <p>For this reason, we need to provide a model that assumes very little about the form that trust stores take. The “Trust Store” section below goes into more detail about how this is achieved.</p> <p>Finally, this API will split the responsibilities currently assumed by the <a class="reference external" href="https://docs.python.org/3/library/ssl.html#ssl.SSLContext">SSLContext</a> object: specifically, the responsibility for holding and managing configuration and the responsibility for using that configuration to build wrapper objects.</p> <p>This is necessarily primarily for supporting functionality like Server Name Indication (SNI). In OpenSSL (and thus in the <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module), the server has the ability to modify the TLS configuration in response to the client telling the server what hostname it is trying to reach. This is mostly used to change certificate chain so as to present the correct TLS certificate chain for the given hostname. The specific mechanism by which this is done is by returning a new <a class="reference external" href="https://docs.python.org/3/library/ssl.html#ssl.SSLContext">SSLContext</a> object with the appropriate configuration.</p> <p>This is not a model that maps well to other TLS implementations. Instead, we need to make it possible to provide a return value from the SNI callback that can be used to indicate what configuration changes should be made. This means providing an object that can hold TLS configuration. This object needs to be applied to specific TLSWrappedBuffer, and TLSWrappedSocket objects.</p> <p>For this reason, we split the responsibility of <a class="reference external" href="https://docs.python.org/3/library/ssl.html#ssl.SSLContext">SSLContext</a> into two separate objects. The <code class="docutils literal notranslate"><span class="pre">TLSConfiguration</span></code> object is an object that acts as container for TLS configuration: the <code class="docutils literal notranslate"><span class="pre">ClientContext</span></code> and <code class="docutils literal notranslate"><span class="pre">ServerContext</span></code> objects are objects that are instantiated with a <code class="docutils literal notranslate"><span class="pre">TLSConfiguration</span></code> object. All three objects would be immutable.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>The following API declarations uniformly use type hints to aid reading. Some of these type hints cannot actually be used in practice because they are circularly referential. Consider them more a guideline than a reflection of the final code in the module.</p> </div> <section id="configuration"> <h4><a class="toc-backref" href="#configuration" role="doc-backlink">Configuration</a></h4> <p>The <code class="docutils literal notranslate"><span class="pre">TLSConfiguration</span></code> concrete class defines an object that can hold and manage TLS configuration. The goals of this class are as follows:</p> <ol class="arabic simple"> <li>To provide a method of specifying TLS configuration that avoids the risk of errors in typing (this excludes the use of a simple dictionary).</li> <li>To provide an object that can be safely compared to other configuration objects to detect changes in TLS configuration, for use with the SNI callback.</li> </ol> <p>This class is not an ABC, primarily because it is not expected to have implementation-specific behaviour. The responsibility for transforming a <code class="docutils literal notranslate"><span class="pre">TLSConfiguration</span></code> object into a useful set of configuration for a given TLS implementation belongs to the Context objects discussed below.</p> <p>This class has one other notable property: it is immutable. This is a desirable trait for a few reasons. The most important one is that it allows these objects to be used as dictionary keys, which is potentially extremely valuable for certain TLS backends and their SNI configuration. On top of this, it frees implementations from needing to worry about their configuration objects being changed under their feet, which allows them to avoid needing to carefully synchronize changes between their concrete data structures and the configuration object.</p> <p>This object is extendable: that is, future releases of Python may add configuration fields to this object as they become useful. For backwards-compatibility purposes, new fields are only appended to this object. Existing fields will never be removed, renamed, or reordered.</p> <p>The <code class="docutils literal notranslate"><span class="pre">TLSConfiguration</span></code> object would be defined by the following code:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">ServerNameCallback</span> <span class="o">=</span> <span class="n">Callable</span><span class="p">[[</span><span class="n">TLSBufferObject</span><span class="p">,</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">],</span> <span class="n">TLSConfiguration</span><span class="p">],</span> <span class="n">Any</span><span class="p">]</span> <span class="n">_configuration_fields</span> <span class="o">=</span> <span class="p">[</span> <span class="s1">&#39;validate_certificates&#39;</span><span class="p">,</span> <span class="s1">&#39;certificate_chain&#39;</span><span class="p">,</span> <span class="s1">&#39;ciphers&#39;</span><span class="p">,</span> <span class="s1">&#39;inner_protocols&#39;</span><span class="p">,</span> <span class="s1">&#39;lowest_supported_version&#39;</span><span class="p">,</span> <span class="s1">&#39;highest_supported_version&#39;</span><span class="p">,</span> <span class="s1">&#39;trust_store&#39;</span><span class="p">,</span> <span class="s1">&#39;sni_callback&#39;</span><span class="p">,</span> <span class="p">]</span> <span class="n">_DEFAULT_VALUE</span> <span class="o">=</span> <span class="nb">object</span><span class="p">()</span> <span class="k">class</span><span class="w"> </span><span class="nc">TLSConfiguration</span><span class="p">(</span><span class="n">namedtuple</span><span class="p">(</span><span class="s1">&#39;TLSConfiguration&#39;</span><span class="p">,</span> <span class="n">_configuration_fields</span><span class="p">)):</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> An immutable TLS Configuration object. This object has the following</span> <span class="sd"> properties:</span> <span class="sd"> :param validate_certificates bool: Whether to validate the TLS</span> <span class="sd"> certificates. This switch operates at a very broad scope: either</span> <span class="sd"> validation is enabled, in which case all forms of validation are</span> <span class="sd"> performed including hostname validation if possible, or validation</span> <span class="sd"> is disabled, in which case no validation is performed.</span> <span class="sd"> Not all backends support having their certificate validation</span> <span class="sd"> disabled. If a backend does not support having their certificate</span> <span class="sd"> validation disabled, attempting to set this property to ``False``</span> <span class="sd"> will throw a ``TLSError`` when this object is passed into a</span> <span class="sd"> context object.</span> <span class="sd"> :param certificate_chain Tuple[Tuple[Certificate],PrivateKey]: The</span> <span class="sd"> certificate, intermediate certificate, and the corresponding</span> <span class="sd"> private key for the leaf certificate. These certificates will be</span> <span class="sd"> offered to the remote peer during the handshake if required.</span> <span class="sd"> The first Certificate in the list must be the leaf certificate. All</span> <span class="sd"> subsequent certificates will be offered as intermediate additional</span> <span class="sd"> certificates.</span> <span class="sd"> :param ciphers Tuple[Union[CipherSuite, int]]:</span> <span class="sd"> The available ciphers for TLS connections created with this</span> <span class="sd"> configuration, in priority order.</span> <span class="sd"> :param inner_protocols Tuple[Union[NextProtocol, bytes]]:</span> <span class="sd"> Protocols that connections created with this configuration should</span> <span class="sd"> advertise as supported during the TLS handshake. These may be</span> <span class="sd"> advertised using either or both of ALPN or NPN. This list of</span> <span class="sd"> protocols should be ordered by preference.</span> <span class="sd"> :param lowest_supported_version TLSVersion:</span> <span class="sd"> The minimum version of TLS that should be allowed on TLS</span> <span class="sd"> connections using this configuration.</span> <span class="sd"> :param highest_supported_version TLSVersion:</span> <span class="sd"> The maximum version of TLS that should be allowed on TLS</span> <span class="sd"> connections using this configuration.</span> <span class="sd"> :param trust_store TrustStore:</span> <span class="sd"> The trust store that connections using this configuration will use</span> <span class="sd"> to validate certificates.</span> <span class="sd"> :param sni_callback Optional[ServerNameCallback]:</span> <span class="sd"> A callback function that will be called after the TLS Client Hello</span> <span class="sd"> handshake message has been received by the TLS server when the TLS</span> <span class="sd"> client specifies a server name indication.</span> <span class="sd"> Only one callback can be set per ``TLSConfiguration``. If the</span> <span class="sd"> ``sni_callback`` is ``None`` then the callback is disabled. If the</span> <span class="sd"> ``TLSConfiguration`` is used for a ``ClientContext`` then this</span> <span class="sd"> setting will be ignored.</span> <span class="sd"> The ``callback`` function will be called with three arguments: the</span> <span class="sd"> first will be the ``TLSBufferObject`` for the connection; the</span> <span class="sd"> second will be a string that represents the server name that the</span> <span class="sd"> client is intending to communicate (or ``None`` if the TLS Client</span> <span class="sd"> Hello does not contain a server name); and the third argument will</span> <span class="sd"> be the original ``TLSConfiguration`` that configured the</span> <span class="sd"> connection. The server name argument will be the IDNA *decoded*</span> <span class="sd"> server name.</span> <span class="sd"> The ``callback`` must return a ``TLSConfiguration`` to allow</span> <span class="sd"> negotiation to continue. Other return values signal errors.</span> <span class="sd"> Attempting to control what error is signaled by the underlying TLS</span> <span class="sd"> implementation is not specified in this API, but is up to the</span> <span class="sd"> concrete implementation to handle.</span> <span class="sd"> The Context will do its best to apply the ``TLSConfiguration``</span> <span class="sd"> changes from its original configuration to the incoming connection.</span> <span class="sd"> This will usually include changing the certificate chain, but may</span> <span class="sd"> also include changes to allowable ciphers or any other</span> <span class="sd"> configuration settings.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="vm">__slots__</span> <span class="o">=</span> <span class="p">()</span> <span class="k">def</span><span class="w"> </span><span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">validate_certificates</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">certificate_chain</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Tuple</span><span class="p">[</span><span class="n">Tuple</span><span class="p">[</span><span class="n">Certificate</span><span class="p">],</span> <span class="n">PrivateKey</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">ciphers</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Tuple</span><span class="p">[</span><span class="n">Union</span><span class="p">[</span><span class="n">CipherSuite</span><span class="p">,</span> <span class="nb">int</span><span class="p">]]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">inner_protocols</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Tuple</span><span class="p">[</span><span class="n">Union</span><span class="p">[</span><span class="n">NextProtocol</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">]]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">lowest_supported_version</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">TLSVersion</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">highest_supported_version</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">TLSVersion</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">trust_store</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">TrustStore</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">sni_callback</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">ServerNameCallback</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">):</span> <span class="k">if</span> <span class="n">validate_certificates</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="n">validate_certificates</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">ciphers</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="n">ciphers</span> <span class="o">=</span> <span class="n">DEFAULT_CIPHER_LIST</span> <span class="k">if</span> <span class="n">inner_protocols</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="n">inner_protocols</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">if</span> <span class="n">lowest_supported_version</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="n">lowest_supported_version</span> <span class="o">=</span> <span class="n">TLSVersion</span><span class="o">.</span><span class="n">TLSv1</span> <span class="k">if</span> <span class="n">highest_supported_version</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="n">highest_supported_version</span> <span class="o">=</span> <span class="n">TLSVersion</span><span class="o">.</span><span class="n">MAXIMUM_SUPPORTED</span> <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__new__</span><span class="p">(</span> <span class="bp">cls</span><span class="p">,</span> <span class="n">validate_certificates</span><span class="p">,</span> <span class="n">certificate_chain</span><span class="p">,</span> <span class="n">ciphers</span><span class="p">,</span> <span class="n">inner_protocols</span><span class="p">,</span> <span class="n">lowest_supported_version</span><span class="p">,</span> <span class="n">highest_supported_version</span><span class="p">,</span> <span class="n">trust_store</span><span class="p">,</span> <span class="n">sni_callback</span> <span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="nf">update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">validate_certificates</span><span class="o">=</span><span class="n">_DEFAULT_VALUE</span><span class="p">,</span> <span class="n">certificate_chain</span><span class="o">=</span><span class="n">_DEFAULT_VALUE</span><span class="p">,</span> <span class="n">ciphers</span><span class="o">=</span><span class="n">_DEFAULT_VALUE</span><span class="p">,</span> <span class="n">inner_protocols</span><span class="o">=</span><span class="n">_DEFAULT_VALUE</span><span class="p">,</span> <span class="n">lowest_supported_version</span><span class="o">=</span><span class="n">_DEFAULT_VALUE</span><span class="p">,</span> <span class="n">highest_supported_version</span><span class="o">=</span><span class="n">_DEFAULT_VALUE</span><span class="p">,</span> <span class="n">trust_store</span><span class="o">=</span><span class="n">_DEFAULT_VALUE</span><span class="p">,</span> <span class="n">sni_callback</span><span class="o">=</span><span class="n">_DEFAULT_VALUE</span><span class="p">):</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Create a new ``TLSConfiguration``, overriding some of the settings</span> <span class="sd"> on the original configuration with the new settings.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="k">if</span> <span class="n">validate_certificates</span> <span class="ow">is</span> <span class="n">_DEFAULT_VALUE</span><span class="p">:</span> <span class="n">validate_certificates</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">validate_certificates</span> <span class="k">if</span> <span class="n">certificate_chain</span> <span class="ow">is</span> <span class="n">_DEFAULT_VALUE</span><span class="p">:</span> <span class="n">certificate_chain</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">certificate_chain</span> <span class="k">if</span> <span class="n">ciphers</span> <span class="ow">is</span> <span class="n">_DEFAULT_VALUE</span><span class="p">:</span> <span class="n">ciphers</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">ciphers</span> <span class="k">if</span> <span class="n">inner_protocols</span> <span class="ow">is</span> <span class="n">_DEFAULT_VALUE</span><span class="p">:</span> <span class="n">inner_protocols</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">inner_protocols</span> <span class="k">if</span> <span class="n">lowest_supported_version</span> <span class="ow">is</span> <span class="n">_DEFAULT_VALUE</span><span class="p">:</span> <span class="n">lowest_supported_version</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">lowest_supported_version</span> <span class="k">if</span> <span class="n">highest_supported_version</span> <span class="ow">is</span> <span class="n">_DEFAULT_VALUE</span><span class="p">:</span> <span class="n">highest_supported_version</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">highest_supported_version</span> <span class="k">if</span> <span class="n">trust_store</span> <span class="ow">is</span> <span class="n">_DEFAULT_VALUE</span><span class="p">:</span> <span class="n">trust_store</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">trust_store</span> <span class="k">if</span> <span class="n">sni_callback</span> <span class="ow">is</span> <span class="n">_DEFAULT_VALUE</span><span class="p">:</span> <span class="n">sni_callback</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">sni_callback</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="p">(</span> <span class="n">validate_certificates</span><span class="p">,</span> <span class="n">certificate_chain</span><span class="p">,</span> <span class="n">ciphers</span><span class="p">,</span> <span class="n">inner_protocols</span><span class="p">,</span> <span class="n">lowest_supported_version</span><span class="p">,</span> <span class="n">highest_supported_version</span><span class="p">,</span> <span class="n">trust_store</span><span class="p">,</span> <span class="n">sni_callback</span> <span class="p">)</span> </pre></div> </div> </section> <section id="context"> <h4><a class="toc-backref" href="#context" role="doc-backlink">Context</a></h4> <p>We define two Context abstract base classes. These ABCs define objects that allow configuration of TLS to be applied to specific connections. They can be thought of as factories for <code class="docutils literal notranslate"><span class="pre">TLSWrappedSocket</span></code> and <code class="docutils literal notranslate"><span class="pre">TLSWrappedBuffer</span></code> objects.</p> <p>Unlike the current <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module, we provide two context classes instead of one. Specifically, we provide the <code class="docutils literal notranslate"><span class="pre">ClientContext</span></code> and <code class="docutils literal notranslate"><span class="pre">ServerContext</span></code> classes. This simplifies the APIs (for example, there is no sense in the server providing the <code class="docutils literal notranslate"><span class="pre">server_hostname</span></code> parameter to <code class="docutils literal notranslate"><span class="pre">ssl.SSLContext.wrap_socket</span></code>, but because there is only one context class that parameter is still available), and ensures that implementations know as early as possible which side of a TLS connection they will serve. Additionally, it allows implementations to opt-out of one or either side of the connection. For example, SecureTransport on macOS is not really intended for server use and has an enormous amount of functionality missing for server-side use. This would allow SecureTransport implementations to simply not define a concrete subclass of <code class="docutils literal notranslate"><span class="pre">ServerContext</span></code> to signal their lack of support.</p> <p>One of the other major differences to the current <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module is that a number of flags and options have been removed. Most of these are self-evident, but it is worth noting that <code class="docutils literal notranslate"><span class="pre">auto_handshake</span></code> has been removed from <code class="docutils literal notranslate"><span class="pre">wrap_socket</span></code>. This was removed because it fundamentally represents an odd design wart that saves very minimal effort at the cost of a complexity increase both for users and implementers. This PEP requires that all users call <code class="docutils literal notranslate"><span class="pre">do_handshake</span></code> explicitly after connecting.</p> <p>As much as possible implementers should aim to make these classes immutable: that is, they should prefer not to allow users to mutate their internal state directly, instead preferring to create new contexts from new TLSConfiguration objects. Obviously, the ABCs cannot enforce this constraint, and so they do not attempt to.</p> <p>The <code class="docutils literal notranslate"><span class="pre">Context</span></code> abstract base class has the following class definition:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">TLSBufferObject</span> <span class="o">=</span> <span class="n">Union</span><span class="p">[</span><span class="n">TLSWrappedSocket</span><span class="p">,</span> <span class="n">TLSWrappedBuffer</span><span class="p">]</span> <span class="k">class</span><span class="w"> </span><span class="nc">_BaseContext</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">ABCMeta</span><span class="p">):</span> <span class="nd">@abstractmethod</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">configuration</span><span class="p">:</span> <span class="n">TLSConfiguration</span><span class="p">):</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Create a new context object from a given TLS configuration.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="nd">@property</span> <span class="nd">@abstractmethod</span> <span class="k">def</span><span class="w"> </span><span class="nf">configuration</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">TLSConfiguration</span><span class="p">:</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Returns the TLS configuration that was used to create the context.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="k">class</span><span class="w"> </span><span class="nc">ClientContext</span><span class="p">(</span><span class="n">_BaseContext</span><span class="p">):</span> <span class="k">def</span><span class="w"> </span><span class="nf">wrap_socket</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">socket</span><span class="p">:</span> <span class="n">socket</span><span class="o">.</span><span class="n">socket</span><span class="p">,</span> <span class="n">server_hostname</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">TLSWrappedSocket</span><span class="p">:</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Wrap an existing Python socket object ``socket`` and return a</span> <span class="sd"> ``TLSWrappedSocket`` object. ``socket`` must be a ``SOCK_STREAM``</span> <span class="sd"> socket: all other socket types are unsupported.</span> <span class="sd"> The returned SSL socket is tied to the context, its settings and</span> <span class="sd"> certificates. The socket object originally passed to this method</span> <span class="sd"> should not be used again: attempting to use it in any way will lead</span> <span class="sd"> to undefined behaviour, especially across different TLS</span> <span class="sd"> implementations. To get the original socket object back once it has</span> <span class="sd"> been wrapped in TLS, see the ``unwrap`` method of the</span> <span class="sd"> TLSWrappedSocket.</span> <span class="sd"> The parameter ``server_hostname`` specifies the hostname of the</span> <span class="sd"> service which we are connecting to. This allows a single server to</span> <span class="sd"> host multiple SSL-based services with distinct certificates, quite</span> <span class="sd"> similarly to HTTP virtual hosts. This is also used to validate the</span> <span class="sd"> TLS certificate for the given hostname. If hostname validation is</span> <span class="sd"> not desired, then pass ``None`` for this parameter. This parameter</span> <span class="sd"> has no default value because opting-out of hostname validation is</span> <span class="sd"> dangerous, and should not be the default behaviour.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="n">buffer</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">wrap_buffers</span><span class="p">(</span><span class="n">server_hostname</span><span class="p">)</span> <span class="k">return</span> <span class="n">TLSWrappedSocket</span><span class="p">(</span><span class="n">socket</span><span class="p">,</span> <span class="n">buffer</span><span class="p">)</span> <span class="nd">@abstractmethod</span> <span class="k">def</span><span class="w"> </span><span class="nf">wrap_buffers</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">server_hostname</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">TLSWrappedBuffer</span><span class="p">:</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Create an in-memory stream for TLS, using memory buffers to store</span> <span class="sd"> incoming and outgoing ciphertext. The TLS routines will read</span> <span class="sd"> received TLS data from one buffer, and write TLS data that needs to</span> <span class="sd"> be emitted to another buffer.</span> <span class="sd"> The implementation details of how this buffering works are up to</span> <span class="sd"> the individual TLS implementation. This allows TLS libraries that</span> <span class="sd"> have their own specialised support to continue to do so, while</span> <span class="sd"> allowing those without to use whatever Python objects they see fit.</span> <span class="sd"> The ``server_hostname`` parameter has the same meaning as in</span> <span class="sd"> ``wrap_socket``.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="k">class</span><span class="w"> </span><span class="nc">ServerContext</span><span class="p">(</span><span class="n">_BaseContext</span><span class="p">):</span> <span class="k">def</span><span class="w"> </span><span class="nf">wrap_socket</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">socket</span><span class="p">:</span> <span class="n">socket</span><span class="o">.</span><span class="n">socket</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">TLSWrappedSocket</span><span class="p">:</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Wrap an existing Python socket object ``socket`` and return a</span> <span class="sd"> ``TLSWrappedSocket`` object. ``socket`` must be a ``SOCK_STREAM``</span> <span class="sd"> socket: all other socket types are unsupported.</span> <span class="sd"> The returned SSL socket is tied to the context, its settings and</span> <span class="sd"> certificates. The socket object originally passed to this method</span> <span class="sd"> should not be used again: attempting to use it in any way will lead</span> <span class="sd"> to undefined behaviour, especially across different TLS</span> <span class="sd"> implementations. To get the original socket object back once it has</span> <span class="sd"> been wrapped in TLS, see the ``unwrap`` method of the</span> <span class="sd"> TLSWrappedSocket.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="n">buffer</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">wrap_buffers</span><span class="p">()</span> <span class="k">return</span> <span class="n">TLSWrappedSocket</span><span class="p">(</span><span class="n">socket</span><span class="p">,</span> <span class="n">buffer</span><span class="p">)</span> <span class="nd">@abstractmethod</span> <span class="k">def</span><span class="w"> </span><span class="nf">wrap_buffers</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">TLSWrappedBuffer</span><span class="p">:</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Create an in-memory stream for TLS, using memory buffers to store</span> <span class="sd"> incoming and outgoing ciphertext. The TLS routines will read</span> <span class="sd"> received TLS data from one buffer, and write TLS data that needs to</span> <span class="sd"> be emitted to another buffer.</span> <span class="sd"> The implementation details of how this buffering works are up to</span> <span class="sd"> the individual TLS implementation. This allows TLS libraries that</span> <span class="sd"> have their own specialised support to continue to do so, while</span> <span class="sd"> allowing those without to use whatever Python objects they see fit.</span> <span class="sd"> &quot;&quot;&quot;</span> </pre></div> </div> </section> <section id="buffer"> <h4><a class="toc-backref" href="#buffer" role="doc-backlink">Buffer</a></h4> <p>The buffer-wrapper ABC will be defined by the <code class="docutils literal notranslate"><span class="pre">TLSWrappedBuffer</span></code> ABC, which has the following definition:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">TLSWrappedBuffer</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">ABCMeta</span><span class="p">):</span> <span class="nd">@abstractmethod</span> <span class="k">def</span><span class="w"> </span><span class="nf">read</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">amt</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bytes</span><span class="p">:</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Read up to ``amt`` bytes of data from the input buffer and return</span> <span class="sd"> the result as a ``bytes`` instance.</span> <span class="sd"> Once EOF is reached, all further calls to this method return the</span> <span class="sd"> empty byte string ``b&#39;&#39;``.</span> <span class="sd"> May read &quot;short&quot;: that is, fewer bytes may be returned than were</span> <span class="sd"> requested.</span> <span class="sd"> Raise ``WantReadError`` or ``WantWriteError`` if there is</span> <span class="sd"> insufficient data in either the input or output buffer and the</span> <span class="sd"> operation would have caused data to be written or read.</span> <span class="sd"> May raise ``RaggedEOF`` if the connection has been closed without a</span> <span class="sd"> graceful TLS shutdown. Whether this is an exception that should be</span> <span class="sd"> ignored or not is up to the specific application.</span> <span class="sd"> As at any time a re-negotiation is possible, a call to ``read()``</span> <span class="sd"> can also cause write operations.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="nd">@abstractmethod</span> <span class="k">def</span><span class="w"> </span><span class="nf">readinto</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">buffer</span><span class="p">:</span> <span class="n">Any</span><span class="p">,</span> <span class="n">amt</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Read up to ``amt`` bytes of data from the input buffer into</span> <span class="sd"> ``buffer``, which must be an object that implements the buffer</span> <span class="sd"> protocol. Returns the number of bytes read.</span> <span class="sd"> Once EOF is reached, all further calls to this method return the</span> <span class="sd"> empty byte string ``b&#39;&#39;``.</span> <span class="sd"> Raises ``WantReadError`` or ``WantWriteError`` if there is</span> <span class="sd"> insufficient data in either the input or output buffer and the</span> <span class="sd"> operation would have caused data to be written or read.</span> <span class="sd"> May read &quot;short&quot;: that is, fewer bytes may be read than were</span> <span class="sd"> requested.</span> <span class="sd"> May raise ``RaggedEOF`` if the connection has been closed without a</span> <span class="sd"> graceful TLS shutdown. Whether this is an exception that should be</span> <span class="sd"> ignored or not is up to the specific application.</span> <span class="sd"> As at any time a re-negotiation is possible, a call to</span> <span class="sd"> ``readinto()`` can also cause write operations.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="nd">@abstractmethod</span> <span class="k">def</span><span class="w"> </span><span class="nf">write</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">buf</span><span class="p">:</span> <span class="n">Any</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Write ``buf`` in encrypted form to the output buffer and return the</span> <span class="sd"> number of bytes written. The ``buf`` argument must be an object</span> <span class="sd"> supporting the buffer interface.</span> <span class="sd"> Raise ``WantReadError`` or ``WantWriteError`` if there is</span> <span class="sd"> insufficient data in either the input or output buffer and the</span> <span class="sd"> operation would have caused data to be written or read. In either</span> <span class="sd"> case, users should endeavour to resolve that situation and then</span> <span class="sd"> re-call this method. When re-calling this method users *should*</span> <span class="sd"> re-use the exact same ``buf`` object, as some backends require that</span> <span class="sd"> the exact same buffer be used.</span> <span class="sd"> This operation may write &quot;short&quot;: that is, fewer bytes may be</span> <span class="sd"> written than were in the buffer.</span> <span class="sd"> As at any time a re-negotiation is possible, a call to ``write()``</span> <span class="sd"> can also cause read operations.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="nd">@abstractmethod</span> <span class="k">def</span><span class="w"> </span><span class="nf">do_handshake</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Performs the TLS handshake. Also performs certificate validation</span> <span class="sd"> and hostname verification.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="nd">@abstractmethod</span> <span class="k">def</span><span class="w"> </span><span class="nf">cipher</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Union</span><span class="p">[</span><span class="n">CipherSuite</span><span class="p">,</span> <span class="nb">int</span><span class="p">]]:</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Returns the CipherSuite entry for the cipher that has been</span> <span class="sd"> negotiated on the connection. If no connection has been negotiated,</span> <span class="sd"> returns ``None``. If the cipher negotiated is not defined in</span> <span class="sd"> CipherSuite, returns the 16-bit integer representing that cipher</span> <span class="sd"> directly.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="nd">@abstractmethod</span> <span class="k">def</span><span class="w"> </span><span class="nf">negotiated_protocol</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Union</span><span class="p">[</span><span class="n">NextProtocol</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">]]:</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Returns the protocol that was selected during the TLS handshake.</span> <span class="sd"> This selection may have been made using ALPN, NPN, or some future</span> <span class="sd"> negotiation mechanism.</span> <span class="sd"> If the negotiated protocol is one of the protocols defined in the</span> <span class="sd"> ``NextProtocol`` enum, the value from that enum will be returned.</span> <span class="sd"> Otherwise, the raw bytestring of the negotiated protocol will be</span> <span class="sd"> returned.</span> <span class="sd"> If ``Context.set_inner_protocols()`` was not called, if the other</span> <span class="sd"> party does not support protocol negotiation, if this socket does</span> <span class="sd"> not support any of the peer&#39;s proposed protocols, or if the</span> <span class="sd"> handshake has not happened yet, ``None`` is returned.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="nd">@property</span> <span class="nd">@abstractmethod</span> <span class="k">def</span><span class="w"> </span><span class="nf">context</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Context</span><span class="p">:</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> The ``Context`` object this buffer is tied to.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="nd">@abstractproperty</span> <span class="k">def</span><span class="w"> </span><span class="nf">negotiated_tls_version</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Optional</span><span class="p">[</span><span class="n">TLSVersion</span><span class="p">]:</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> The version of TLS that has been negotiated on this connection.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="nd">@abstractmethod</span> <span class="k">def</span><span class="w"> </span><span class="nf">shutdown</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Performs a clean TLS shut down. This should generally be used</span> <span class="sd"> whenever possible to signal to the remote peer that the content is</span> <span class="sd"> finished.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="nd">@abstractmethod</span> <span class="k">def</span><span class="w"> </span><span class="nf">receive_from_network</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Receives some TLS data from the network and stores it in an</span> <span class="sd"> internal buffer.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="nd">@abstractmethod</span> <span class="k">def</span><span class="w"> </span><span class="nf">peek_outgoing</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">amt</span><span class="p">):</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Returns the next ``amt`` bytes of data that should be written to</span> <span class="sd"> the network from the outgoing data buffer, without removing it from</span> <span class="sd"> the internal buffer.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="nd">@abstractmethod</span> <span class="k">def</span><span class="w"> </span><span class="nf">consume_outgoing</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">amt</span><span class="p">):</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Discard the next ``amt`` bytes from the outgoing data buffer. This</span> <span class="sd"> should be used when ``amt`` bytes have been sent on the network, to</span> <span class="sd"> signal that the data no longer needs to be buffered.</span> <span class="sd"> &quot;&quot;&quot;</span> </pre></div> </div> </section> <section id="socket"> <h4><a class="toc-backref" href="#socket" role="doc-backlink">Socket</a></h4> <p>The socket-wrapper class will be a concrete class that accepts two items in its constructor: a regular socket object, and a <code class="docutils literal notranslate"><span class="pre">TLSWrappedBuffer</span></code> object. This object will be too large to recreate in this PEP, but will be submitted as part of the work to build the module.</p> <p>The wrapped socket will implement all of the socket API, though it will have stub implementations of methods that only work for sockets with types other than <code class="docutils literal notranslate"><span class="pre">SOCK_STREAM</span></code> (e.g. <code class="docutils literal notranslate"><span class="pre">sendto</span></code>/<code class="docutils literal notranslate"><span class="pre">recvfrom</span></code>). That limitation can be lifted as-and-when support for DTLS is added to this module.</p> <p>In addition, the socket class will include the following <em>extra</em> methods on top of the regular socket methods:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">TLSWrappedSocket</span><span class="p">:</span> <span class="k">def</span><span class="w"> </span><span class="nf">do_handshake</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Performs the TLS handshake. Also performs certificate validation</span> <span class="sd"> and hostname verification. This must be called after the socket has</span> <span class="sd"> connected (either via ``connect`` or ``accept``), before any other</span> <span class="sd"> operation is performed on the socket.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="k">def</span><span class="w"> </span><span class="nf">cipher</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Union</span><span class="p">[</span><span class="n">CipherSuite</span><span class="p">,</span> <span class="nb">int</span><span class="p">]]:</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Returns the CipherSuite entry for the cipher that has been</span> <span class="sd"> negotiated on the connection. If no connection has been negotiated,</span> <span class="sd"> returns ``None``. If the cipher negotiated is not defined in</span> <span class="sd"> CipherSuite, returns the 16-bit integer representing that cipher</span> <span class="sd"> directly.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="k">def</span><span class="w"> </span><span class="nf">negotiated_protocol</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Union</span><span class="p">[</span><span class="n">NextProtocol</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">]]:</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Returns the protocol that was selected during the TLS handshake.</span> <span class="sd"> This selection may have been made using ALPN, NPN, or some future</span> <span class="sd"> negotiation mechanism.</span> <span class="sd"> If the negotiated protocol is one of the protocols defined in the</span> <span class="sd"> ``NextProtocol`` enum, the value from that enum will be returned.</span> <span class="sd"> Otherwise, the raw bytestring of the negotiated protocol will be</span> <span class="sd"> returned.</span> <span class="sd"> If ``Context.set_inner_protocols()`` was not called, if the other</span> <span class="sd"> party does not support protocol negotiation, if this socket does</span> <span class="sd"> not support any of the peer&#39;s proposed protocols, or if the</span> <span class="sd"> handshake has not happened yet, ``None`` is returned.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="nd">@property</span> <span class="k">def</span><span class="w"> </span><span class="nf">context</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Context</span><span class="p">:</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> The ``Context`` object this socket is tied to.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="k">def</span><span class="w"> </span><span class="nf">negotiated_tls_version</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Optional</span><span class="p">[</span><span class="n">TLSVersion</span><span class="p">]:</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> The version of TLS that has been negotiated on this connection.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="k">def</span><span class="w"> </span><span class="nf">unwrap</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">socket</span><span class="o">.</span><span class="n">socket</span><span class="p">:</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Cleanly terminate the TLS connection on this wrapped socket. Once</span> <span class="sd"> called, this ``TLSWrappedSocket`` can no longer be used to transmit</span> <span class="sd"> data. Returns the socket that was wrapped with TLS.</span> <span class="sd"> &quot;&quot;&quot;</span> </pre></div> </div> </section> <section id="cipher-suites"> <h4><a class="toc-backref" href="#cipher-suites" role="doc-backlink">Cipher Suites</a></h4> <p>Supporting cipher suites in a truly library-agnostic fashion is a remarkably difficult undertaking. Different TLS implementations often have <em>radically</em> different APIs for specifying cipher suites, but more problematically these APIs frequently differ in capability as well as in style. Some examples are shown below:</p> <section id="openssl"> <h5><a class="toc-backref" href="#openssl" role="doc-backlink">OpenSSL</a></h5> <p>OpenSSL uses a well-known cipher string format. This format has been adopted as a configuration language by most products that use OpenSSL, including Python. This format is relatively easy to read, but has a number of downsides: it is a string, which makes it remarkably easy to provide bad inputs; it lacks much detailed validation, meaning that it is possible to configure OpenSSL in a way that doesn’t allow it to negotiate any cipher at all; and it allows specifying cipher suites in a number of different ways that make it tricky to parse. The biggest problem with this format is that there is no formal specification for it, meaning that the only way to parse a given string the way OpenSSL would is to get OpenSSL to parse it.</p> <p>OpenSSL’s cipher strings can look like this:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="s1">&#39;ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:DH+CHACHA20:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!eNULL:!MD5&#39;</span> </pre></div> </div> <p>This string demonstrates some of the complexity of the OpenSSL format. For example, it is possible for one entry to specify multiple cipher suites: the entry <code class="docutils literal notranslate"><span class="pre">ECDH+AESGCM</span></code> means “all ciphers suites that include both elliptic-curve Diffie-Hellman key exchange and AES in Galois Counter Mode”. More explicitly, that will expand to four cipher suites:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="s2">&quot;ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256&quot;</span> </pre></div> </div> <p>That makes parsing a complete OpenSSL cipher string extremely tricky. Add to the fact that there are other meta-characters, such as “!” (exclude all cipher suites that match this criterion, even if they would otherwise be included: “!MD5” means that no cipher suites using the MD5 hash algorithm should be included), “-” (exclude matching ciphers if they were already included, but allow them to be re-added later if they get included again), and “+” (include the matching ciphers, but place them at the end of the list), and you get an <em>extremely</em> complex format to parse. On top of this complexity it should be noted that the actual result depends on the OpenSSL version, as an OpenSSL cipher string is valid so long as it contains at least one cipher that OpenSSL recognises.</p> <p>OpenSSL also uses different names for its ciphers than the names used in the relevant specifications. See the manual page for <code class="docutils literal notranslate"><span class="pre">ciphers(1)</span></code> for more details.</p> <p>The actual API inside OpenSSL for the cipher string is simple:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">char</span> <span class="o">*</span><span class="n">cipher_list</span> <span class="o">=</span> <span class="o">&lt;</span><span class="n">some</span> <span class="n">cipher</span> <span class="nb">list</span><span class="o">&gt;</span><span class="p">;</span> <span class="nb">int</span> <span class="n">rc</span> <span class="o">=</span> <span class="n">SSL_CTX_set_cipher_list</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">cipher_list</span><span class="p">);</span> </pre></div> </div> <p>This means that any format that is used by this module must be able to be converted to an OpenSSL cipher string for use with OpenSSL.</p> </section> <section id="securetransport"> <h5><a class="toc-backref" href="#securetransport" role="doc-backlink">SecureTransport</a></h5> <p>SecureTransport is the macOS system TLS library. This library is substantially more restricted than OpenSSL in many ways, as it has a much more restricted class of users. One of these substantial restrictions is in controlling supported cipher suites.</p> <p>Ciphers in SecureTransport are represented by a C <code class="docutils literal notranslate"><span class="pre">enum</span></code>. This enum has one entry per cipher suite, with no aggregate entries, meaning that it is not possible to reproduce the meaning of an OpenSSL cipher string like “ECDH+AESGCM” without hand-coding which categories each enum member falls into.</p> <p>However, the names of most of the enum members are in line with the formal names of the cipher suites: that is, the cipher suite that OpenSSL calls “ECDHE-ECDSA-AES256-GCM-SHA384” is called “TLS_ECDHE_ECDHSA_WITH_AES_256_GCM_SHA384” in SecureTransport.</p> <p>The API for configuring cipher suites inside SecureTransport is simple:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">SSLCipherSuite</span> <span class="n">ciphers</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="n">TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384</span><span class="p">,</span> <span class="o">...</span><span class="p">};</span> <span class="n">OSStatus</span> <span class="n">status</span> <span class="o">=</span> <span class="n">SSLSetEnabledCiphers</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">ciphers</span><span class="p">,</span> <span class="n">sizeof</span><span class="p">(</span><span class="n">ciphers</span><span class="p">));</span> </pre></div> </div> </section> <section id="schannel"> <h5><a class="toc-backref" href="#schannel" role="doc-backlink">SChannel</a></h5> <p>SChannel is the Windows system TLS library.</p> <p>SChannel has extremely restrictive support for controlling available TLS cipher suites, and additionally adopts a third method of expressing what TLS cipher suites are supported.</p> <p>Specifically, SChannel defines a set of <code class="docutils literal notranslate"><span class="pre">ALG_ID</span></code> constants (C unsigned ints). Each of these constants does not refer to an entire cipher suite, but instead an individual algorithm. Some examples are <code class="docutils literal notranslate"><span class="pre">CALG_3DES</span></code> and <code class="docutils literal notranslate"><span class="pre">CALG_AES_256</span></code>, which refer to the bulk encryption algorithm used in a cipher suite, <code class="docutils literal notranslate"><span class="pre">CALG_DH_EPHEM</span></code> and <code class="docutils literal notranslate"><span class="pre">CALG_RSA_KEYX</span></code> which refer to part of the key exchange algorithm used in a cipher suite, <code class="docutils literal notranslate"><span class="pre">CALG_SHA1</span></code> and <code class="docutils literal notranslate"><span class="pre">CALG_MD5</span></code> which refer to the message authentication code used in a cipher suite, and <code class="docutils literal notranslate"><span class="pre">CALG_ECDSA</span></code> and <code class="docutils literal notranslate"><span class="pre">CALG_RSA_SIGN</span></code> which refer to the signing portions of the key exchange algorithm.</p> <p>This can be thought of as the half of OpenSSL’s functionality that SecureTransport doesn’t have: SecureTransport only allows specifying exact cipher suites, while SChannel only allows specifying <em>parts</em> of the cipher suite, while OpenSSL allows both.</p> <p>Determining which cipher suites are allowed on a given connection is done by providing a pointer to an array of these <code class="docutils literal notranslate"><span class="pre">ALG_ID</span></code> constants. This means that any suitable API must allow the Python code to determine which <code class="docutils literal notranslate"><span class="pre">ALG_ID</span></code> constants must be provided.</p> </section> <section id="network-security-services-nss"> <h5><a class="toc-backref" href="#network-security-services-nss" role="doc-backlink">Network Security Services (NSS)</a></h5> <p>NSS is Mozilla’s crypto and TLS library. It’s used in Firefox, Thunderbird, and as alternative to OpenSSL in multiple libraries, e.g. curl.</p> <p>By default, NSS comes with secure configuration of allowed ciphers. On some platforms such as Fedora, the list of enabled ciphers is globally configured in a system policy. Generally, applications should not modify cipher suites unless they have specific reasons to do so.</p> <p>NSS has both process global and per-connection settings for cipher suites. It does not have a concept of SSLContext like OpenSSL. A SSLContext-like behavior can be easily emulated. Specifically, ciphers can be enabled or disabled globally with <code class="docutils literal notranslate"><span class="pre">SSL_CipherPrefSetDefault(PRInt32</span> <span class="pre">cipher,</span> <span class="pre">PRBool</span> <span class="pre">enabled)</span></code>, and <code class="docutils literal notranslate"><span class="pre">SSL_CipherPrefSet(PRFileDesc</span> <span class="pre">*fd,</span> <span class="pre">PRInt32</span> <span class="pre">cipher,</span> <span class="pre">PRBool</span> <span class="pre">enabled)</span></code> for a connection. The cipher <code class="docutils literal notranslate"><span class="pre">PRInt32</span></code> number is a signed 32bit integer that directly corresponds to an registered IANA id, e.g. <code class="docutils literal notranslate"><span class="pre">0x1301</span></code> is <code class="docutils literal notranslate"><span class="pre">TLS_AES_128_GCM_SHA256</span></code>. Contrary to OpenSSL, the preference order of ciphers is fixed and cannot be modified at runtime.</p> <p>Like SecureTransport, NSS has no API for aggregated entries. Some consumers of NSS have implemented custom mappings from OpenSSL cipher names and rules to NSS ciphers, e.g. <code class="docutils literal notranslate"><span class="pre">mod_nss</span></code>.</p> </section> <section id="proposed-interface"> <h5><a class="toc-backref" href="#proposed-interface" role="doc-backlink">Proposed Interface</a></h5> <p>The proposed interface for the new module is influenced by the combined set of limitations of the above implementations. Specifically, as every implementation <em>except</em> OpenSSL requires that each individual cipher be provided, there is no option but to provide that lowest-common denominator approach.</p> <p>The simplest approach is to provide an enumerated type that includes a large subset of the cipher suites defined for TLS. The values of the enum members will be their two-octet cipher identifier as used in the TLS handshake, stored as a 16 bit integer. The names of the enum members will be their IANA-registered cipher suite names.</p> <p>As of now, the <a class="reference external" href="https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4">IANA cipher suite registry</a> contains over 320 cipher suites. A large portion of the cipher suites are irrelevant for TLS connections to network services. Other suites specify deprecated and insecure algorithms that are no longer provided by recent versions of implementations. The enum does not contain ciphers with:</p> <ul class="simple"> <li>key exchange: NULL, Kerberos (KRB5), pre-shared key (PSK), secure remote transport (TLS-SRP)</li> <li>authentication: NULL, anonymous, export grade, Kerberos (KRB5), pre-shared key (PSK), secure remote transport (TLS-SRP), DSA cert (DSS)</li> <li>encryption: NULL, ARIA, DES, RC2, export grade 40bit</li> <li>PRF: MD5</li> <li>SCSV cipher suites</li> </ul> <p>3DES, RC4, SEED, and IDEA are included for legacy applications. Further more five additional cipher suites from the TLS 1.3 draft (draft-ietf-tls-tls13-18) are included, too. TLS 1.3 does not share any cipher suites with TLS 1.2 and earlier. The resulting enum will contain roughly 110 suites.</p> <p>Because of these limitations, and because the enum doesn’t contain every defined cipher, and also to allow for forward-looking applications, all parts of this API that accept <code class="docutils literal notranslate"><span class="pre">CipherSuite</span></code> objects will also accept raw 16-bit integers directly.</p> <p>Rather than populate this enum by hand, we have a <a class="reference external" href="https://github.com/tiran/tlsdb/blob/master/tlspep_ciphersuite.py">TLS enum script</a> that builds it from Christian Heimes’ <a class="reference external" href="https://github.com/tiran/tlsdb/blob/master/tlsdb.json">tlsdb JSON file</a> (warning: large file) and <a class="reference external" href="https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4">IANA cipher suite registry</a>. The TLSDB also opens up the possibility of extending the API with additional querying function, such as determining which TLS versions support which ciphers, if that functionality is found to be useful or necessary.</p> <p>If users find this approach to be onerous, a future extension to this API can provide helpers that can reintroduce OpenSSL’s aggregation functionality.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">CipherSuite</span><span class="p">(</span><span class="n">IntEnum</span><span class="p">):</span> <span class="n">TLS_RSA_WITH_RC4_128_SHA</span> <span class="o">=</span> <span class="mh">0x0005</span> <span class="n">TLS_RSA_WITH_IDEA_CBC_SHA</span> <span class="o">=</span> <span class="mh">0x0007</span> <span class="n">TLS_RSA_WITH_3DES_EDE_CBC_SHA</span> <span class="o">=</span> <span class="mh">0x000a</span> <span class="n">TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA</span> <span class="o">=</span> <span class="mh">0x0010</span> <span class="n">TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA</span> <span class="o">=</span> <span class="mh">0x0016</span> <span class="n">TLS_RSA_WITH_AES_128_CBC_SHA</span> <span class="o">=</span> <span class="mh">0x002f</span> <span class="n">TLS_DH_RSA_WITH_AES_128_CBC_SHA</span> <span class="o">=</span> <span class="mh">0x0031</span> <span class="n">TLS_DHE_RSA_WITH_AES_128_CBC_SHA</span> <span class="o">=</span> <span class="mh">0x0033</span> <span class="n">TLS_RSA_WITH_AES_256_CBC_SHA</span> <span class="o">=</span> <span class="mh">0x0035</span> <span class="n">TLS_DH_RSA_WITH_AES_256_CBC_SHA</span> <span class="o">=</span> <span class="mh">0x0037</span> <span class="n">TLS_DHE_RSA_WITH_AES_256_CBC_SHA</span> <span class="o">=</span> <span class="mh">0x0039</span> <span class="n">TLS_RSA_WITH_AES_128_CBC_SHA256</span> <span class="o">=</span> <span class="mh">0x003c</span> <span class="n">TLS_RSA_WITH_AES_256_CBC_SHA256</span> <span class="o">=</span> <span class="mh">0x003d</span> <span class="n">TLS_DH_RSA_WITH_AES_128_CBC_SHA256</span> <span class="o">=</span> <span class="mh">0x003f</span> <span class="n">TLS_RSA_WITH_CAMELLIA_128_CBC_SHA</span> <span class="o">=</span> <span class="mh">0x0041</span> <span class="n">TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA</span> <span class="o">=</span> <span class="mh">0x0043</span> <span class="n">TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA</span> <span class="o">=</span> <span class="mh">0x0045</span> <span class="n">TLS_DHE_RSA_WITH_AES_128_CBC_SHA256</span> <span class="o">=</span> <span class="mh">0x0067</span> <span class="n">TLS_DH_RSA_WITH_AES_256_CBC_SHA256</span> <span class="o">=</span> <span class="mh">0x0069</span> <span class="n">TLS_DHE_RSA_WITH_AES_256_CBC_SHA256</span> <span class="o">=</span> <span class="mh">0x006b</span> <span class="n">TLS_RSA_WITH_CAMELLIA_256_CBC_SHA</span> <span class="o">=</span> <span class="mh">0x0084</span> <span class="n">TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA</span> <span class="o">=</span> <span class="mh">0x0086</span> <span class="n">TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA</span> <span class="o">=</span> <span class="mh">0x0088</span> <span class="n">TLS_RSA_WITH_SEED_CBC_SHA</span> <span class="o">=</span> <span class="mh">0x0096</span> <span class="n">TLS_DH_RSA_WITH_SEED_CBC_SHA</span> <span class="o">=</span> <span class="mh">0x0098</span> <span class="n">TLS_DHE_RSA_WITH_SEED_CBC_SHA</span> <span class="o">=</span> <span class="mh">0x009a</span> <span class="n">TLS_RSA_WITH_AES_128_GCM_SHA256</span> <span class="o">=</span> <span class="mh">0x009c</span> <span class="n">TLS_RSA_WITH_AES_256_GCM_SHA384</span> <span class="o">=</span> <span class="mh">0x009d</span> <span class="n">TLS_DHE_RSA_WITH_AES_128_GCM_SHA256</span> <span class="o">=</span> <span class="mh">0x009e</span> <span class="n">TLS_DHE_RSA_WITH_AES_256_GCM_SHA384</span> <span class="o">=</span> <span class="mh">0x009f</span> <span class="n">TLS_DH_RSA_WITH_AES_128_GCM_SHA256</span> <span class="o">=</span> <span class="mh">0x00a0</span> <span class="n">TLS_DH_RSA_WITH_AES_256_GCM_SHA384</span> <span class="o">=</span> <span class="mh">0x00a1</span> <span class="n">TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256</span> <span class="o">=</span> <span class="mh">0x00ba</span> <span class="n">TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256</span> <span class="o">=</span> <span class="mh">0x00bc</span> <span class="n">TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256</span> <span class="o">=</span> <span class="mh">0x00be</span> <span class="n">TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256</span> <span class="o">=</span> <span class="mh">0x00c0</span> <span class="n">TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256</span> <span class="o">=</span> <span class="mh">0x00c2</span> <span class="n">TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256</span> <span class="o">=</span> <span class="mh">0x00c4</span> <span class="n">TLS_AES_128_GCM_SHA256</span> <span class="o">=</span> <span class="mh">0x1301</span> <span class="n">TLS_AES_256_GCM_SHA384</span> <span class="o">=</span> <span class="mh">0x1302</span> <span class="n">TLS_CHACHA20_POLY1305_SHA256</span> <span class="o">=</span> <span class="mh">0x1303</span> <span class="n">TLS_AES_128_CCM_SHA256</span> <span class="o">=</span> <span class="mh">0x1304</span> <span class="n">TLS_AES_128_CCM_8_SHA256</span> <span class="o">=</span> <span class="mh">0x1305</span> <span class="n">TLS_ECDH_ECDSA_WITH_RC4_128_SHA</span> <span class="o">=</span> <span class="mh">0xc002</span> <span class="n">TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA</span> <span class="o">=</span> <span class="mh">0xc003</span> <span class="n">TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA</span> <span class="o">=</span> <span class="mh">0xc004</span> <span class="n">TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA</span> <span class="o">=</span> <span class="mh">0xc005</span> <span class="n">TLS_ECDHE_ECDSA_WITH_RC4_128_SHA</span> <span class="o">=</span> <span class="mh">0xc007</span> <span class="n">TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA</span> <span class="o">=</span> <span class="mh">0xc008</span> <span class="n">TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA</span> <span class="o">=</span> <span class="mh">0xc009</span> <span class="n">TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA</span> <span class="o">=</span> <span class="mh">0xc00a</span> <span class="n">TLS_ECDH_RSA_WITH_RC4_128_SHA</span> <span class="o">=</span> <span class="mh">0xc00c</span> <span class="n">TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA</span> <span class="o">=</span> <span class="mh">0xc00d</span> <span class="n">TLS_ECDH_RSA_WITH_AES_128_CBC_SHA</span> <span class="o">=</span> <span class="mh">0xc00e</span> <span class="n">TLS_ECDH_RSA_WITH_AES_256_CBC_SHA</span> <span class="o">=</span> <span class="mh">0xc00f</span> <span class="n">TLS_ECDHE_RSA_WITH_RC4_128_SHA</span> <span class="o">=</span> <span class="mh">0xc011</span> <span class="n">TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA</span> <span class="o">=</span> <span class="mh">0xc012</span> <span class="n">TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA</span> <span class="o">=</span> <span class="mh">0xc013</span> <span class="n">TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA</span> <span class="o">=</span> <span class="mh">0xc014</span> <span class="n">TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256</span> <span class="o">=</span> <span class="mh">0xc023</span> <span class="n">TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384</span> <span class="o">=</span> <span class="mh">0xc024</span> <span class="n">TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256</span> <span class="o">=</span> <span class="mh">0xc025</span> <span class="n">TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384</span> <span class="o">=</span> <span class="mh">0xc026</span> <span class="n">TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256</span> <span class="o">=</span> <span class="mh">0xc027</span> <span class="n">TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384</span> <span class="o">=</span> <span class="mh">0xc028</span> <span class="n">TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256</span> <span class="o">=</span> <span class="mh">0xc029</span> <span class="n">TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384</span> <span class="o">=</span> <span class="mh">0xc02a</span> <span class="n">TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256</span> <span class="o">=</span> <span class="mh">0xc02b</span> <span class="n">TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384</span> <span class="o">=</span> <span class="mh">0xc02c</span> <span class="n">TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256</span> <span class="o">=</span> <span class="mh">0xc02d</span> <span class="n">TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384</span> <span class="o">=</span> <span class="mh">0xc02e</span> <span class="n">TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256</span> <span class="o">=</span> <span class="mh">0xc02f</span> <span class="n">TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384</span> <span class="o">=</span> <span class="mh">0xc030</span> <span class="n">TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256</span> <span class="o">=</span> <span class="mh">0xc031</span> <span class="n">TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384</span> <span class="o">=</span> <span class="mh">0xc032</span> <span class="n">TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256</span> <span class="o">=</span> <span class="mh">0xc072</span> <span class="n">TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384</span> <span class="o">=</span> <span class="mh">0xc073</span> <span class="n">TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256</span> <span class="o">=</span> <span class="mh">0xc074</span> <span class="n">TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384</span> <span class="o">=</span> <span class="mh">0xc075</span> <span class="n">TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256</span> <span class="o">=</span> <span class="mh">0xc076</span> <span class="n">TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384</span> <span class="o">=</span> <span class="mh">0xc077</span> <span class="n">TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256</span> <span class="o">=</span> <span class="mh">0xc078</span> <span class="n">TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384</span> <span class="o">=</span> <span class="mh">0xc079</span> <span class="n">TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256</span> <span class="o">=</span> <span class="mh">0xc07a</span> <span class="n">TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384</span> <span class="o">=</span> <span class="mh">0xc07b</span> <span class="n">TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256</span> <span class="o">=</span> <span class="mh">0xc07c</span> <span class="n">TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384</span> <span class="o">=</span> <span class="mh">0xc07d</span> <span class="n">TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256</span> <span class="o">=</span> <span class="mh">0xc07e</span> <span class="n">TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384</span> <span class="o">=</span> <span class="mh">0xc07f</span> <span class="n">TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256</span> <span class="o">=</span> <span class="mh">0xc086</span> <span class="n">TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384</span> <span class="o">=</span> <span class="mh">0xc087</span> <span class="n">TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256</span> <span class="o">=</span> <span class="mh">0xc088</span> <span class="n">TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384</span> <span class="o">=</span> <span class="mh">0xc089</span> <span class="n">TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256</span> <span class="o">=</span> <span class="mh">0xc08a</span> <span class="n">TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384</span> <span class="o">=</span> <span class="mh">0xc08b</span> <span class="n">TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256</span> <span class="o">=</span> <span class="mh">0xc08c</span> <span class="n">TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384</span> <span class="o">=</span> <span class="mh">0xc08d</span> <span class="n">TLS_RSA_WITH_AES_128_CCM</span> <span class="o">=</span> <span class="mh">0xc09c</span> <span class="n">TLS_RSA_WITH_AES_256_CCM</span> <span class="o">=</span> <span class="mh">0xc09d</span> <span class="n">TLS_DHE_RSA_WITH_AES_128_CCM</span> <span class="o">=</span> <span class="mh">0xc09e</span> <span class="n">TLS_DHE_RSA_WITH_AES_256_CCM</span> <span class="o">=</span> <span class="mh">0xc09f</span> <span class="n">TLS_RSA_WITH_AES_128_CCM_8</span> <span class="o">=</span> <span class="mh">0xc0a0</span> <span class="n">TLS_RSA_WITH_AES_256_CCM_8</span> <span class="o">=</span> <span class="mh">0xc0a1</span> <span class="n">TLS_DHE_RSA_WITH_AES_128_CCM_8</span> <span class="o">=</span> <span class="mh">0xc0a2</span> <span class="n">TLS_DHE_RSA_WITH_AES_256_CCM_8</span> <span class="o">=</span> <span class="mh">0xc0a3</span> <span class="n">TLS_ECDHE_ECDSA_WITH_AES_128_CCM</span> <span class="o">=</span> <span class="mh">0xc0ac</span> <span class="n">TLS_ECDHE_ECDSA_WITH_AES_256_CCM</span> <span class="o">=</span> <span class="mh">0xc0ad</span> <span class="n">TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8</span> <span class="o">=</span> <span class="mh">0xc0ae</span> <span class="n">TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8</span> <span class="o">=</span> <span class="mh">0xc0af</span> <span class="n">TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256</span> <span class="o">=</span> <span class="mh">0xcca8</span> <span class="n">TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256</span> <span class="o">=</span> <span class="mh">0xcca9</span> <span class="n">TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256</span> <span class="o">=</span> <span class="mh">0xccaa</span> </pre></div> </div> <p>Enum members can be mapped to OpenSSL cipher names:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">ssl</span> <span class="gp">&gt;&gt;&gt; </span><span class="n">ctx</span> <span class="o">=</span> <span class="n">ssl</span><span class="o">.</span><span class="n">SSLContext</span><span class="p">(</span><span class="n">ssl</span><span class="o">.</span><span class="n">PROTOCOL_TLS</span><span class="p">)</span> <span class="gp">&gt;&gt;&gt; </span><span class="n">ctx</span><span class="o">.</span><span class="n">set_ciphers</span><span class="p">(</span><span class="s1">&#39;ALL:COMPLEMENTOFALL&#39;</span><span class="p">)</span> <span class="gp">&gt;&gt;&gt; </span><span class="n">ciphers</span> <span class="o">=</span> <span class="p">{</span><span class="n">c</span><span class="p">[</span><span class="s1">&#39;id&#39;</span><span class="p">]</span> <span class="o">&amp;</span> <span class="mh">0xffff</span><span class="p">:</span> <span class="n">c</span><span class="p">[</span><span class="s1">&#39;name&#39;</span><span class="p">]</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">ctx</span><span class="o">.</span><span class="n">get_ciphers</span><span class="p">()}</span> <span class="gp">&gt;&gt;&gt; </span><span class="n">ciphers</span><span class="p">[</span><span class="n">CipherSuite</span><span class="o">.</span><span class="n">TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256</span><span class="p">]</span> <span class="go">&#39;ECDHE-RSA-AES128-GCM-SHA256&#39;</span> </pre></div> </div> <p>For SecureTransport, these enum members directly refer to the values of the cipher suite constants. For example, SecureTransport defines the cipher suite enum member <code class="docutils literal notranslate"><span class="pre">TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384</span></code> as having the value <code class="docutils literal notranslate"><span class="pre">0xC02C</span></code>. Not coincidentally, that is identical to its value in the above enum. This makes mapping between SecureTransport and the above enum very easy indeed.</p> <p>For SChannel there is no easy direct mapping, due to the fact that SChannel configures ciphers, instead of cipher suites. This represents an ongoing concern with SChannel, which is that it is very difficult to configure in a specific manner compared to other TLS implementations.</p> <p>For the purposes of this PEP, any SChannel implementation will need to determine which ciphers to choose based on the enum members. This may be more open than the actual cipher suite list actually wants to allow, or it may be more restrictive, depending on the choices of the implementation. This PEP recommends that it be more restrictive, but of course this cannot be enforced.</p> </section> </section> <section id="protocol-negotiation"> <h4><a class="toc-backref" href="#protocol-negotiation" role="doc-backlink">Protocol Negotiation</a></h4> <p>Both NPN and ALPN allow for protocol negotiation as part of the HTTP/2 handshake. While NPN and ALPN are, at their fundamental level, built on top of bytestrings, string-based APIs are frequently problematic as they allow for errors in typing that can be hard to detect.</p> <p>For this reason, this module would define a type that protocol negotiation implementations can pass and be passed. This type would wrap a bytestring to allow for aliases for well-known protocols. This allows us to avoid the problems inherent in typos for well-known protocols, while allowing the full extensibility of the protocol negotiation layer if needed by letting users pass byte strings directly.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">NextProtocol</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span> <span class="n">H2</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">&#39;h2&#39;</span> <span class="n">H2C</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">&#39;h2c&#39;</span> <span class="n">HTTP1</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">&#39;http/1.1&#39;</span> <span class="n">WEBRTC</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">&#39;webrtc&#39;</span> <span class="n">C_WEBRTC</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">&#39;c-webrtc&#39;</span> <span class="n">FTP</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">&#39;ftp&#39;</span> <span class="n">STUN</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">&#39;stun.nat-discovery&#39;</span> <span class="n">TURN</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">&#39;stun.turn&#39;</span> </pre></div> </div> </section> <section id="tls-versions"> <h4><a class="toc-backref" href="#tls-versions" role="doc-backlink">TLS Versions</a></h4> <p>It is often useful to be able to restrict the versions of TLS you’re willing to support. There are many security advantages in refusing to use old versions of TLS, and some misbehaving servers will mishandle TLS clients advertising support for newer versions.</p> <p>The following enumerated type can be used to gate TLS versions. Forward-looking applications should almost never set a maximum TLS version unless they absolutely must, as a TLS backend that is newer than the Python that uses it may support TLS versions that are not in this enumerated type.</p> <p>Additionally, this enumerated type defines two additional flags that can always be used to request either the lowest or highest TLS version supported by an implementation.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">TLSVersion</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span> <span class="n">MINIMUM_SUPPORTED</span> <span class="o">=</span> <span class="n">auto</span><span class="p">()</span> <span class="n">SSLv2</span> <span class="o">=</span> <span class="n">auto</span><span class="p">()</span> <span class="n">SSLv3</span> <span class="o">=</span> <span class="n">auto</span><span class="p">()</span> <span class="n">TLSv1</span> <span class="o">=</span> <span class="n">auto</span><span class="p">()</span> <span class="n">TLSv1_1</span> <span class="o">=</span> <span class="n">auto</span><span class="p">()</span> <span class="n">TLSv1_2</span> <span class="o">=</span> <span class="n">auto</span><span class="p">()</span> <span class="n">TLSv1_3</span> <span class="o">=</span> <span class="n">auto</span><span class="p">()</span> <span class="n">MAXIMUM_SUPPORTED</span> <span class="o">=</span> <span class="n">auto</span><span class="p">()</span> </pre></div> </div> </section> <section id="errors"> <h4><a class="toc-backref" href="#errors" role="doc-backlink">Errors</a></h4> <p>This module would define four base classes for use with error handling. Unlike many of the other classes defined here, these classes are not abstract, as they have no behaviour. They exist simply to signal certain common behaviours. Backends should subclass these exceptions in their own packages, but needn’t define any behaviour for them.</p> <p>In general, concrete implementations should subclass these exceptions rather than throw them directly. This makes it moderately easier to determine which concrete TLS implementation is in use during debugging of unexpected errors. However, this is not mandatory.</p> <p>The definitions of the errors are below:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">TLSError</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> The base exception for all TLS related errors from any backend.</span> <span class="sd"> Catching this error should be sufficient to catch *all* TLS errors,</span> <span class="sd"> regardless of what backend is used.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="k">class</span><span class="w"> </span><span class="nc">WantWriteError</span><span class="p">(</span><span class="n">TLSError</span><span class="p">):</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> A special signaling exception used only when non-blocking or</span> <span class="sd"> buffer-only I/O is used. This error signals that the requested</span> <span class="sd"> operation cannot complete until more data is written to the network,</span> <span class="sd"> or until the output buffer is drained.</span> <span class="sd"> This error is should only be raised when it is completely impossible</span> <span class="sd"> to write any data. If a partial write is achievable then this should</span> <span class="sd"> not be raised.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="k">class</span><span class="w"> </span><span class="nc">WantReadError</span><span class="p">(</span><span class="n">TLSError</span><span class="p">):</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> A special signaling exception used only when non-blocking or</span> <span class="sd"> buffer-only I/O is used. This error signals that the requested</span> <span class="sd"> operation cannot complete until more data is read from the network, or</span> <span class="sd"> until more data is available in the input buffer.</span> <span class="sd"> This error should only be raised when it is completely impossible to</span> <span class="sd"> write any data. If a partial write is achievable then this should not</span> <span class="sd"> be raised.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="k">class</span><span class="w"> </span><span class="nc">RaggedEOF</span><span class="p">(</span><span class="n">TLSError</span><span class="p">):</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> A special signaling exception used when a TLS connection has been</span> <span class="sd"> closed gracelessly: that is, when a TLS CloseNotify was not received</span> <span class="sd"> from the peer before the underlying TCP socket reached EOF. This is a</span> <span class="sd"> so-called &quot;ragged EOF&quot;.</span> <span class="sd"> This exception is not guaranteed to be raised in the face of a ragged</span> <span class="sd"> EOF: some implementations may not be able to detect or report the</span> <span class="sd"> ragged EOF.</span> <span class="sd"> This exception is not always a problem. Ragged EOFs are a concern only</span> <span class="sd"> when protocols are vulnerable to length truncation attacks. Any</span> <span class="sd"> protocol that can detect length truncation attacks at the application</span> <span class="sd"> layer (e.g. HTTP/1.1 and HTTP/2) is not vulnerable to this kind of</span> <span class="sd"> attack and so can ignore this exception.</span> <span class="sd"> &quot;&quot;&quot;</span> </pre></div> </div> </section> <section id="certificates"> <h4><a class="toc-backref" href="#certificates" role="doc-backlink">Certificates</a></h4> <p>This module would define an abstract X509 certificate class. This class would have almost no behaviour, as the goal of this module is not to provide all possible relevant cryptographic functionality that could be provided by X509 certificates. Instead, all we need is the ability to signal the source of a certificate to a concrete implementation.</p> <p>For that reason, this certificate implementation defines only constructors. In essence, the certificate object in this module could be as abstract as a handle that can be used to locate a specific certificate.</p> <p>Concrete implementations may choose to provide alternative constructors, e.g. to load certificates from HSMs. If a common interface emerges for doing this, this module may be updated to provide a standard constructor for this use-case as well.</p> <p>Concrete implementations should aim to have Certificate objects be hashable if at all possible. This will help ensure that TLSConfiguration objects used with an individual concrete implementation are also hashable.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">Certificate</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">ABCMeta</span><span class="p">):</span> <span class="nd">@abstractclassmethod</span> <span class="k">def</span><span class="w"> </span><span class="nf">from_buffer</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">buffer</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">):</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Creates a Certificate object from a byte buffer. This byte buffer</span> <span class="sd"> may be either PEM-encoded or DER-encoded. If the buffer is PEM</span> <span class="sd"> encoded it *must* begin with the standard PEM preamble (a series of</span> <span class="sd"> dashes followed by the ASCII bytes &quot;BEGIN CERTIFICATE&quot; and another</span> <span class="sd"> series of dashes). In the absence of that preamble, the</span> <span class="sd"> implementation may assume that the certificate is DER-encoded</span> <span class="sd"> instead.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="nd">@abstractclassmethod</span> <span class="k">def</span><span class="w"> </span><span class="nf">from_file</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">path</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">,</span> <span class="n">AnyStr</span><span class="p">]):</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Creates a Certificate object from a file on disk. This method may</span> <span class="sd"> be a convenience method that wraps ``open`` and ``from_buffer``,</span> <span class="sd"> but some TLS implementations may be able to provide more-secure or</span> <span class="sd"> faster methods of loading certificates that do not involve Python</span> <span class="sd"> code.</span> <span class="sd"> &quot;&quot;&quot;</span> </pre></div> </div> </section> <section id="private-keys"> <h4><a class="toc-backref" href="#private-keys" role="doc-backlink">Private Keys</a></h4> <p>This module would define an abstract private key class. Much like the Certificate class, this class has almost no behaviour in order to give as much freedom as possible to the concrete implementations to treat keys carefully.</p> <p>This class has all the caveats of the <code class="docutils literal notranslate"><span class="pre">Certificate</span></code> class.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">PrivateKey</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">ABCMeta</span><span class="p">):</span> <span class="nd">@abstractclassmethod</span> <span class="k">def</span><span class="w"> </span><span class="nf">from_buffer</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">buffer</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">,</span> <span class="n">password</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Union</span><span class="p">[</span><span class="n">Callable</span><span class="p">[[],</span> <span class="n">Union</span><span class="p">[</span><span class="nb">bytes</span><span class="p">,</span> <span class="nb">bytearray</span><span class="p">]],</span> <span class="nb">bytes</span><span class="p">,</span> <span class="nb">bytearray</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">):</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Creates a PrivateKey object from a byte buffer. This byte buffer</span> <span class="sd"> may be either PEM-encoded or DER-encoded. If the buffer is PEM</span> <span class="sd"> encoded it *must* begin with the standard PEM preamble (a series of</span> <span class="sd"> dashes followed by the ASCII bytes &quot;BEGIN&quot;, the key type, and</span> <span class="sd"> another series of dashes). In the absence of that preamble, the</span> <span class="sd"> implementation may assume that the certificate is DER-encoded</span> <span class="sd"> instead.</span> <span class="sd"> The key may additionally be encrypted. If it is, the ``password``</span> <span class="sd"> argument can be used to decrypt the key. The ``password`` argument</span> <span class="sd"> may be a function to call to get the password for decrypting the</span> <span class="sd"> private key. It will only be called if the private key is encrypted</span> <span class="sd"> and a password is necessary. It will be called with no arguments,</span> <span class="sd"> and it should return either bytes or bytearray containing the</span> <span class="sd"> password. Alternatively a bytes, or bytearray value may be supplied</span> <span class="sd"> directly as the password argument. It will be ignored if the</span> <span class="sd"> private key is not encrypted and no password is needed.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="nd">@abstractclassmethod</span> <span class="k">def</span><span class="w"> </span><span class="nf">from_file</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">path</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">,</span> <span class="nb">str</span><span class="p">],</span> <span class="n">password</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Union</span><span class="p">[</span><span class="n">Callable</span><span class="p">[[],</span> <span class="n">Union</span><span class="p">[</span><span class="nb">bytes</span><span class="p">,</span> <span class="nb">bytearray</span><span class="p">]],</span> <span class="nb">bytes</span><span class="p">,</span> <span class="nb">bytearray</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">):</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Creates a PrivateKey object from a file on disk. This method may</span> <span class="sd"> be a convenience method that wraps ``open`` and ``from_buffer``,</span> <span class="sd"> but some TLS implementations may be able to provide more-secure or</span> <span class="sd"> faster methods of loading certificates that do not involve Python</span> <span class="sd"> code.</span> <span class="sd"> The ``password`` parameter behaves exactly as the equivalent</span> <span class="sd"> parameter on ``from_buffer``.</span> <span class="sd"> &quot;&quot;&quot;</span> </pre></div> </div> </section> <section id="trust-store"> <h4><a class="toc-backref" href="#trust-store" role="doc-backlink">Trust Store</a></h4> <p>As discussed above, loading a trust store represents an issue because different TLS implementations vary wildly in how they allow users to select trust stores. For this reason, we need to provide a model that assumes very little about the form that trust stores take.</p> <p>This problem is the same as the one that the Certificate and PrivateKey types need to solve. For this reason, we use the exact same model, by creating an opaque type that can encapsulate the various means that TLS backends may open a trust store.</p> <p>A given TLS implementation is not required to implement all of the constructors. However, it is strongly recommended that a given TLS implementation provide the <code class="docutils literal notranslate"><span class="pre">system</span></code> constructor if at all possible, as this is the most common validation trust store that is used. Concrete implementations may also add their own constructors.</p> <p>Concrete implementations should aim to have TrustStore objects be hashable if at all possible. This will help ensure that TLSConfiguration objects used with an individual concrete implementation are also hashable.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">TrustStore</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">ABCMeta</span><span class="p">):</span> <span class="nd">@abstractclassmethod</span> <span class="k">def</span><span class="w"> </span><span class="nf">system</span><span class="p">(</span><span class="bp">cls</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">TrustStore</span><span class="p">:</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Returns a TrustStore object that represents the system trust</span> <span class="sd"> database.</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="nd">@abstractclassmethod</span> <span class="k">def</span><span class="w"> </span><span class="nf">from_pem_file</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">path</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">,</span> <span class="nb">str</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">TrustStore</span><span class="p">:</span> <span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> <span class="sd"> Initializes a trust store from a single file full of PEMs.</span> <span class="sd"> &quot;&quot;&quot;</span> </pre></div> </div> </section> <section id="runtime-access"> <h4><a class="toc-backref" href="#runtime-access" role="doc-backlink">Runtime Access</a></h4> <p>A not-uncommon use case for library users is to want to allow the library to control the TLS configuration, but to want to select what backend is in use. For example, users of Requests may want to be able to select between OpenSSL or a platform-native solution on Windows and macOS, or between OpenSSL and NSS on some Linux platforms. These users, however, may not care about exactly how their TLS configuration is done.</p> <p>This poses a problem: given an arbitrary concrete implementation, how can a library work out how to load certificates into the trust store? There are two options: either all concrete implementations can be required to fit into a specific naming scheme, or we can provide an API that makes it possible to grab these objects.</p> <p>This PEP proposes that we use the second approach. This grants the greatest freedom to concrete implementations to structure their code as they see fit, requiring only that they provide a single object that has the appropriate properties in place. Users can then pass this “backend” object to libraries that support it, and those libraries can take care of configuring and using the concrete implementation.</p> <p>All concrete implementations must provide a method of obtaining a <code class="docutils literal notranslate"><span class="pre">Backend</span></code> object. The <code class="docutils literal notranslate"><span class="pre">Backend</span></code> object can be a global singleton or can be created by a callable if there is an advantage in doing that.</p> <p>The <code class="docutils literal notranslate"><span class="pre">Backend</span></code> object has the following definition:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Backend</span> <span class="o">=</span> <span class="n">namedtuple</span><span class="p">(</span> <span class="s1">&#39;Backend&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;client_context&#39;</span><span class="p">,</span> <span class="s1">&#39;server_context&#39;</span><span class="p">,</span> <span class="s1">&#39;certificate&#39;</span><span class="p">,</span> <span class="s1">&#39;private_key&#39;</span><span class="p">,</span> <span class="s1">&#39;trust_store&#39;</span><span class="p">]</span> <span class="p">)</span> </pre></div> </div> <p>Each of the properties must provide the concrete implementation of the relevant ABC. This ensures that code like this will work for any backend:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">trust_store</span> <span class="o">=</span> <span class="n">backend</span><span class="o">.</span><span class="n">trust_store</span><span class="o">.</span><span class="n">system</span><span class="p">()</span> </pre></div> </div> </section> </section> </section> <section id="changes-to-the-standard-library"> <h2><a class="toc-backref" href="#changes-to-the-standard-library" role="doc-backlink">Changes to the Standard Library</a></h2> <p>The portions of the standard library that interact with TLS should be revised to use these ABCs. This will allow them to function with other TLS backends. This includes the following modules:</p> <ul class="simple"> <li>asyncio</li> <li>ftplib</li> <li>http</li> <li>imaplib</li> <li>nntplib</li> <li>poplib</li> <li>smtplib</li> <li>urllib</li> </ul> <section id="migration-of-the-ssl-module"> <h3><a class="toc-backref" href="#migration-of-the-ssl-module" role="doc-backlink">Migration of the ssl module</a></h3> <p>Naturally, we will need to extend the <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module itself to conform to these ABCs. This extension will take the form of new classes, potentially in an entirely new module. This will allow applications that take advantage of the current <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module to continue to do so, while enabling the new APIs for applications and libraries that want to use them.</p> <p>In general, migrating from the <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module to the new ABCs is not expected to be one-to-one. This is normally acceptable: most tools that use the <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module hide it from the user, and so refactoring to use the new module should be invisible.</p> <p>However, a specific problem comes from libraries or applications that leak exceptions from the <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module, either as part of their defined API or by accident (which is easily done). Users of those tools may have written code that tolerates and handles exceptions from the <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module being raised: migrating to the ABCs presented here would potentially cause the exceptions defined above to be thrown instead, and existing <code class="docutils literal notranslate"><span class="pre">except</span></code> blocks will not catch them.</p> <p>For this reason, part of the migration of the <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module would require that the exceptions in the <code class="docutils literal notranslate"><span class="pre">ssl</span></code> module alias those defined above. That is, they would require the following statements to all succeed:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">assert</span> <span class="n">ssl</span><span class="o">.</span><span class="n">SSLError</span> <span class="ow">is</span> <span class="n">tls</span><span class="o">.</span><span class="n">TLSError</span> <span class="k">assert</span> <span class="n">ssl</span><span class="o">.</span><span class="n">SSLWantReadError</span> <span class="ow">is</span> <span class="n">tls</span><span class="o">.</span><span class="n">WantReadError</span> <span class="k">assert</span> <span class="n">ssl</span><span class="o">.</span><span class="n">SSLWantWriteError</span> <span class="ow">is</span> <span class="n">tls</span><span class="o">.</span><span class="n">WantWriteError</span> </pre></div> </div> <p>The exact mechanics of how this will be done are beyond the scope of this PEP, as they are made more complex due to the fact that the current <code class="docutils literal notranslate"><span class="pre">ssl</span></code> exceptions are defined in C code, but more details can be found in <a class="reference external" href="https://mail.python.org/pipermail/security-sig/2017-January/000213.html">an email sent to the Security-SIG by Christian Heimes</a>.</p> </section> </section> <section id="future"> <h2><a class="toc-backref" href="#future" role="doc-backlink">Future</a></h2> <p>Major future TLS features may require revisions of these ABCs. These revisions should be made cautiously: many backends may not be able to move forward swiftly, and will be invalidated by changes in these ABCs. This is acceptable, but wherever possible features that are specific to individual implementations should not be added to the ABCs. The ABCs should restrict themselves to high-level descriptions of IETF-specified features.</p> <p>However, well-justified extensions to this API absolutely should be made. The focus of this API is to provide a unifying lowest-common-denominator configuration option for the Python community. TLS is not a static target, and as TLS evolves so must this API.</p> </section> <section id="credits"> <h2><a class="toc-backref" href="#credits" role="doc-backlink">Credits</a></h2> <p>This document has received extensive review from a number of individuals in the community who have substantially helped shape it. Detailed review was provided by:</p> <ul class="simple"> <li>Alex Chan</li> <li>Alex Gaynor</li> <li>Antoine Pitrou</li> <li>Ashwini Oruganti</li> <li>Donald Stufft</li> <li>Ethan Furman</li> <li>Glyph</li> <li>Hynek Schlawack</li> <li>Jim J Jewett</li> <li>Nathaniel J. Smith</li> <li>Alyssa Coghlan</li> <li>Paul Kehrer</li> <li>Steve Dower</li> <li>Steven Fackler</li> <li>Wes Turner</li> <li>Will Bond</li> </ul> <p>Further review was provided by the Security-SIG and python-ideas mailing lists.</p> </section> <section id="copyright"> <h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2> <p>This document has been placed in the public domain.</p> </section> </section> <hr class="docutils" /> <p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0543.rst">https://github.com/python/peps/blob/main/peps/pep-0543.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0543.rst">2025-02-01 08:59:27 GMT</a></p> </article> <nav id="pep-sidebar"> <h2>Contents</h2> <ul> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#resolution">Resolution</a></li> <li><a class="reference internal" href="#rationale">Rationale</a><ul> <li><a class="reference internal" href="#problems">Problems</a></li> </ul> </li> <li><a class="reference internal" href="#proposal">Proposal</a><ul> <li><a class="reference internal" href="#interfaces">Interfaces</a><ul> <li><a class="reference internal" href="#configuration">Configuration</a></li> <li><a class="reference internal" href="#context">Context</a></li> <li><a class="reference internal" href="#buffer">Buffer</a></li> <li><a class="reference internal" href="#socket">Socket</a></li> <li><a class="reference internal" href="#cipher-suites">Cipher Suites</a><ul> <li><a class="reference internal" href="#openssl">OpenSSL</a></li> <li><a class="reference internal" href="#securetransport">SecureTransport</a></li> <li><a class="reference internal" href="#schannel">SChannel</a></li> <li><a class="reference internal" href="#network-security-services-nss">Network Security Services (NSS)</a></li> <li><a class="reference internal" href="#proposed-interface">Proposed Interface</a></li> </ul> </li> <li><a class="reference internal" href="#protocol-negotiation">Protocol Negotiation</a></li> <li><a class="reference internal" href="#tls-versions">TLS Versions</a></li> <li><a class="reference internal" href="#errors">Errors</a></li> <li><a class="reference internal" href="#certificates">Certificates</a></li> <li><a class="reference internal" href="#private-keys">Private Keys</a></li> <li><a class="reference internal" href="#trust-store">Trust Store</a></li> <li><a class="reference internal" href="#runtime-access">Runtime Access</a></li> </ul> </li> </ul> </li> <li><a class="reference internal" href="#changes-to-the-standard-library">Changes to the Standard Library</a><ul> <li><a class="reference internal" href="#migration-of-the-ssl-module">Migration of the ssl module</a></li> </ul> </li> <li><a class="reference internal" href="#future">Future</a></li> <li><a class="reference internal" href="#credits">Credits</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> <br> <a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0543.rst">Page Source (GitHub)</a> </nav> </section> <script src="../_static/colour_scheme.js"></script> <script src="../_static/wrap_tables.js"></script> <script src="../_static/sticky_banner.js"></script> </body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10