[Security-sig] Unified TLS API for Python

Wes Turner wes.turner at gmail.com
Thu Jan 12 00:36:21 EST 2017


On Wednesday, January 11, 2017, Christian Heimes <christian at cheimes.de>
wrote:

On 2017-01-11 20:01, Cory Benfield wrote:
>
> > 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.
> >
> > The ``Context`` abstract base class has the following class definition::
> >
> >     TLSBufferObject = Union[TLSWrappedSocket, TLSWrappedBuffer]
> >     ServerNameCallback = Callable[[TLSBufferObject, Optional[str],
> Context], Any]
> >
> >     class _BaseContext(metaclass=ABCMeta):
> >
> >         @property
> >         @abstractmethod
> >         def validate_certificates(self) -> bool:
> >             """
> >             Whether to validate the TLS certificates. This switch
> operates at a
> >             very broad scope: either validation is enabled, in which
> case all
> >             forms of validation are performed including hostname
> validation if
> >             possible, or validation is disabled, in which case no
> validation is
> >             performed.
> >
> >             Not all backends support having their certificate validation
> >             disabled. If a backend does not support having their
> certificate
> >             validation disabled, attempting to set this property to
> ``False``
> >             will throw a ``TLSError``.
> >             """
> >
> >         @validate_certificates.setter
> >         @abstractmethod
> >         def validate_certificates(self, val: bool) -> None:
> >           pass
>
>
> For 3.7 I'm planning to replace ssl.match_hostname() with OpenSSL
> 1.0.2's API. For now the one flag is enough. Later we can discuss
> settings for wildcard, IP address and CN matching.
>
> >
> >         @abstractmethod
> >         def register_certificates(self,
> >                                   certificates: str,
> >                                   key=None: Optional[str],
> >                                   password=None: Optional[Callable[[],
> Union[AnyStr, bytearray]]]) -> None:
> >             """
> >             Loads a certificate, a number of intermediate certificates,
> and the
> >             corresponding private key. These certificates will be
> offered to
> >             the remote peer during the handshake if required.
> >
> >             The ``certificates`` argument must be a bytestring
> containing the
> >             PEM-encoded certificates. The first PEM-encoded certificate
> must be
> >             the leaf certificate. All subsequence certificates will be
> offered
> >             as intermediate additional certificates.
> >
> >             The ``key`` argument, if present, must contain the
> PEM-encoded
> >             private key associated with the leaf certificate. If not
> present,
> >             the private key will be extracted from ``certificates``.
> >
> >             The ``password`` argument may be a function to call to get
> the
> >             password for decrypting the private key. It will only be
> called if
> >             the private key is encrypted and a password is necessary. It
> will
> >             be called with no arguments, and it should return a string,
> bytes,
> >             or bytearray. If the return value is a string it will be
> encoded as
> >             UTF-8 before using it to decrypt the key. Alternatively a
> string,
> >             bytes, or bytearray value may be supplied directly as the
> password
> >             argument. It will be ignored if the private key is not
> encrypted
> >             and no password is needed.
> >             """
>
> I don't think this function works for all libraries and use cases. For
> some implementations the order of certificates is very important. For
> NSS and PKCS#11 we rather need to specify the slot or nick name of the
> cert. For 3.7 I also like to introduce X509 objects and EVP_Key wrapper,
> so this function would need to consume a stack of certificates.
>
> Since this function is only required for TLS servers and TLS client cert
> authentication, I'd rather mark this function provisional or not define
> it in the first version.
>
>
>
This may be a bit of a different use case (and possibly worth having in the
first version of a new tls module):

"Hitless TLS Certificate Rotation in Go"
https://diogomonica.com/2017/01/11/hitless-tls-certificate-rotation-in-go/

- Can/could this be done with only set_sni_callback ?

- VerifyPeerCertificate
  https://github.com/golang/go/issues/16363
  - https://github.com/golang/go/blob/release-branch.go1.8/
src/crypto/tls/common.go#L406


>
> >         @abstractmethod
> >         def set_ciphers(self, ciphers: List[Ciphers]) -> None:
> >             """
> >             Set the available ciphers for TLS connections created with
> this
> >             context. ``ciphers`` should be a list of ciphers from the
> >             ``Cipher`` registry. If none of the ``ciphers`` provided to
> this
> >             object are supported or available, a ``TLSError`` will be
> raised.
> >             """
>
> Implementors should initial context with sensible default settings,
> preferable system-wide settings. For example Fedora is currently
> implementing https://fedoraproject.org/wiki/Changes/CryptoPolicy for
> OpenSSL, NSS and GnuTLS.
>
>
>
> >
> >         @abstractmethod
> >         def set_inner_protocols(self, protocols: List[NextProtocol]) ->
> None:
> >             """
> >             Specify which protocols the socket should advertise as
> supported
> >             during the TLS handshake. This may be advertised using
> either or
> >             both of ALPN or NPN.
> >
> >             ``protocols`` should be a list of acceptable protocols in
> the form
> >             of ``NextProtocol`` objects, such as ``[H2, HTTP1]``,
> ordered by
> >             preference. The selection of the protocol will happen during
> the
> >             handshake, and will use whatever protocol negotiation
> mechanisms
> >             are available and supported by both peers.
> >
> >             If the TLS implementation doesn't support protocol
> negotiation,
> >             this method will raise ``NotImplementedError``.
> >             """
> >
> >         @abstractmethod
> >         def set_sni_callback(self, callback:
> Optional[ServerNameCallback]) -> None:
> >             """
> >             Register a callback function that will be called after the
> TLS
> >             Client Hello handshake message has been received by the TLS
> server
> >             when the TLS client specifies a server name indication.
> >
> >             Only one callback can be set per ``Context``. If
> ``callback`` is
> >             ``None`` then the callback is disabled. Calling this
> function a
> >             subsequent time will disable the previously registered
> callback.
> >
> >             The ``callback`` function will be called with three
> arguments: the
> >             first will be the ``TLSBufferObject`` for the connection; the
> >             second will be a string that represents the server name that
> the
> >             client is intending to communicate (or ``None`` if the TLS
> Client
> >             Hello does not contain a server name); and the third
> argument will
> >             be the original ``Context``. The server name argument will
> be the
> >             IDNA *decoded* server name.
> >
> >             The ``callback`` must return ``None`` to allow negotiation to
> >             continue. Other return values signal errors. Attempting to
> control
> >             what error is signaled by the underlying TLS implementation
> is not
> >             specified in this API, but is up to the concrete
> implementation to
> >             handle.
> >             """
> >
> >         @abstractmethod
> >         def set_version_range(self, lower_bound=None:
> Optional[TLSVersion],
> >                               upper_bound=None: Optional[TLSVersion]) ->
> None:
> >             """
> >             Set the minumum and maximum versions of TLS that should be
> allowed
> >             on TLS connections made by this context.
> >
> >             If present, ``lower_bound`` will set the lowest acceptable
> TLS
> >             version. If present, ``upper_bound`` will set the highest
> >             acceptable TLS version. If either argument is ``None``, this
> will
> >             leave that bound unchanged.
> >             """
>

So, with

```
class TLSVersion(Enum):
        MINIMUM_SUPPORTED
        SSLv2
        SSLv3
        TLSv1
        TLSv1_1
        TLSv1_2
        TLSv1_3
        MAXIMUM_SUPPORTED
```

What are the (signed?) integer values?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/security-sig/attachments/20170111/57acdef4/attachment-0001.html>


More information about the Security-SIG mailing list