On 2017-01-26 15:23, Nick Coghlan wrote: > On 26 January 2017 at 10:50, Cory Benfield <c...@lukasa.co.uk> wrote: >> >>> On 26 Jan 2017, at 07:49, Nick Coghlan <ncogh...@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.
For technical reasons it is beneficial to define SSL exception in C code. I don't want to force people to load _ssl to avoid the overhead of OpenSSL loading and initialization. After some brain storming with Nick I came up with the idea to define the exceptions in _socket. The _ssl module imports a PyCapsule from _socket any way. I can just piggyback on the PyCapsule. For maximum compatibility with Python 2, the tls module should subclass from socket.error anyway, too. Python 2: >>> import ssl >>> ssl.SSLError.__mro__ (<class 'ssl.SSLError'>, <class 'socket.error'>, <type 'exceptions.IOError'>, <type 'exceptions.EnvironmentError'>, <type 'exceptions.StandardError'>, <type 'exceptions.Exception'>, <type 'exceptions.BaseException'>, <type 'object'>) Python 3: >>> import ssl, socket >>> ssl.SSLError.__mro__ (<class 'ssl.SSLError'>, <class 'OSError'>, <class 'Exception'>, <class 'BaseException'>, <class 'object'>) >>> socket.error <class 'OSError'> This import block should (hopefully) cover all bases: try: # CPython 3.7+ from _socket import SSLError as TLSError from _socket import SSLWantWriteError as WantWriteError from _socket import SSLWantReadError as WantReadError except ImportError: # CPython < 3.7 and other implementations try: from ssl import SSLError as TLSError from ssl import SSLWantWriteError as WantWriteError from ssl import SSLWantReadError as WantReadError except ImportError: # ssl module is not available # Python 2: socket.error is a subclass of IOError # Python 3: socket.error is just an alias of OSError import socket class TLSError(socket.error): pass class WantWriteError(TLSError): pass class WantReadError(TLSError): pass Christian _______________________________________________ Security-SIG mailing list Security-SIG@python.org https://mail.python.org/mailman/listinfo/security-sig