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

Nick Coghlan ncoghlan at gmail.com
Thu Jan 26 09:23:45 EST 2017


On 26 January 2017 at 10:50, Cory Benfield <cory at lukasa.co.uk> wrote:
>
>> On 26 Jan 2017, at 07:49, Nick Coghlan <ncoghlan at gmail.com> wrote:
>>
>> Option 4: tls.TLSError, tls.WantReadError, tls.WantWriteError are
>> defined as inheriting from ssl.SSLError, ssl.SSLWantReadError, and
>> ssl.SSLWantWriteError *if* the latter are defined
>>
>> Option 5: as with Option 4, but the "ssl" module is also changed such
>> that it *always* defines at least ssl.SSLError, ssl.SSLWantReadError,
>> and ssl.SSLWantWriteError (and perhaps some of the other APIs that can
>> be emulated atop the new tls abstraction), even if OpenSSL itself is
>> unavailable
>
> Here’s my problem with this:
>
> try:
>     socket.recv(8192)
> except tls.WantWriteError:
>     socket.write(some_buffer)
>
> This code does not work with the legacy ssl module, because isinstance(ssl.SSLWantWriteError, tls.WantWriteError) is false. This means that we need to write a shim over the legacy ssl module that wraps *all* API calls, catches all exceptions and then translates them into subclasses of the tls error classes. That seems entirely batty to me.

OK, so we have two competing problems here:

1. How do we write *new* API client code that is agnostic to whether
or not the security implementation is traditional ssl or a new tls
backend?
2. How does a library that exports the ssl exceptions migrate to using
a tls backend instead, without having to catch and rewrap tls
exceptions in the legacy ones?

Meeting both constraints at the same time would require exception
*aliases* rather than one set of exceptions inheriting from the other,
such that we get:

    assert tls.TLSError is ssl.SSLError
    assert tls.WantWriteError is ssl.SSLWantWriteError
    assert tls.WantReadError is ssl.SSLWantReadError

In an ideal world, that could be handled just by having the ssl module
import the new tls module and alias the exceptions accordingly.
Talking to Christian about it, things might be a little messier in
practice due to the way the _ssl/ssl C/Python split works, but there
shouldn't be any insurmountable barriers to going down the exception
aliasing path in 3.7+.

Backports to older versions would still need to contend with these
being different exception objects, but one possible way of tackling
that would be to inject a dummy ssl module into sys.modules before the
regular one had a chance to be imported.

Cheers,
Nick.

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


More information about the Security-SIG mailing list