[Security-sig] Unified TLS API for Python: Round 2

Nick Coghlan ncoghlan at gmail.com
Sat Jan 21 08:07:25 EST 2017


On 20 January 2017 at 04:29, Cory Benfield <cory at lukasa.co.uk> wrote:
> Please let me know what you think.
>
> The version of the draft PEP, from commit ce74bc60, is reproduced below.

Thanks Cory, this is looking really good. I don't have anything to add
on the security design front, but do have a few comments/questions on
the API design and explanation front.

> Configuration
> ~~~~~~~~~~~~~
>
> The ``TLSConfiguration`` concrete class defines an object that can hold and
> manage TLS configuration. The goals of this class are as follows:
>
> 1. To provide a method of specifying TLS configuration that avoids the risk of
>    errors in typing (this excludes the use of a simple dictionary).
> 2. 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.
>
> This class is not an ABC, primarily because it is not expected to have
> implementation-specific behaviour. The responsibility for transforming a
> ``TLSConfiguration`` object into a useful set of configuration for a given TLS
> implementation belongs to the Context objects discussed below.
>
> 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.
>
> The ``TLSConfiguration`` object would be defined by the following code:
>
>     ServerNameCallback = Callable[[TLSBufferObject, Optional[str], TLSConfiguration], Any]
>
>
>     _configuration_fields = [
>         'validate_certificates',
>         'certificate_chain',
>         'ciphers',
>         'inner_protocols',
>         'lowest_supported_version',
>         'highest_supported_version',
>         'trust_store',
>         'sni_callback',
>     ]
>
>
>     _DEFAULT_VALUE = object()
>
>
>     class TLSConfiguration(namedtuple('TLSConfiguration', _configuration_fields)):

I agree with Wes that the backwards compatibility guarantees around
adding new configuration fields should be clarified.

I think it will suffice to say that "new fields are only appended,
existing fields are never removed, renamed, or reordered". That means
that:

- tuple unpacking will be forward compatible as long as you use *args at the end
- numeric lookup will be forward compatible

That doesn't make either of them a good idea (vs just using attribute
lookups), but it does provide an indication to future maintainers that
such code shouldn't be gratuitously broken either.

> Context
> ~~~~~~~
>
> The ``Context`` abstract base class defines an object that allows configuration
> of TLS. It can be thought of as a factory for ``TLSWrappedSocket`` and
> ``TLSWrappedBuffer`` objects.
>
> 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.
>
> The ``Context`` abstract base class has the following class definition::

This intro section talks about a combined "Context" objection, but the
implementation has been split into ServerContext and ClientContext.

That split could also use some explanation in the background section of the PEP.

> Proposed Interface
> ^^^^^^^^^^^^^^^^^^
>
> The proposed interface for the new module is influenced by the combined set of
> limitations of the above implementations. Specifically, as every implementation
> *except* OpenSSL requires that each individual cipher be provided, there is no
> option but to provide that lowest-common denominator approach.

The second sentence here doesn't match the description of SChannel
cipher configuration, so I'm not clear on how the proposed interface
would map to an SChannel backend.

> Errors
> ~~~~~~
>
> This module would define three base classes for use with error handling. Unlike
> 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.
>
> 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.

This is the one part of the PEP that I think may need to discuss
transition strategies for libraries and frameworks that currently let
ssl module exceptions escape to their users: how do they do that in a
way that's transparent to API consumers that currently capture the ssl
module exceptions?

Cheers,
Nick.



-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Security-SIG mailing list