Support for DANE/TLSA with ssl.SSLContext

Hi everyone, I was recently messing around with secure connection establishment and tried to implement optimistic DANE/TLSA verification to avoid having to go through my browser-provided list of several hundred Certificate Authorities, which I assume will get quite a bit longer in the near future due to regulation in the European Union (Context).

Armed with a satisfying solution for DNSSEC (another topic…) and seeing support for DANE has already made its way into OpenSSL (e.g. have a look at SSL_CTX_dane_enable(3ssl)), I was looking to use this functionality in cpython.

This is where I hit a roadblock:

The OpenSSL functionality mentioned above is currently not exposed in the _ssl module, which (as far as I can tell) rules out usage of this functionality during the handshake validation routine. At the same time, there does not seem to exist a functionality to acquire the peer’s certificate chain in order to manually verify the peer after the handshake. (Note that SSLObject.getpeercert is insufficient for this, since TLSA records can reference CAs.)

Hence some proposals of mine, for which I am seeking feedback in the form of additions, opinions, alternatives/workarounds and all kinds of helpful comments :slight_smile:

I tried ordering them from least to most invasive to the documented stdlib:

Proposal 1

Declare functions in the _ssl module corresponding to the following OpenSSL functions:

  • SSL_CTX_dane_enable
  • SSL_dane_enable
  • SSL_dane_tlsa_add

By corresponding I do not mean that there should be one function in python for every function in C, rather the functionality of enabling DANE verification and adding acceptable records should be exposed.

This would allow external python modules to wrap an SSLContext and add TLSA verification.
Since the documented stdlib is not touched, the impact on users should be minimal.

Proposal 2

Add the functionality directly to the ssl module, ideally exposed on the SSLContext passed to the various stdlib functions establishing secure TLS connections.

This is a bit more invasive, and likely requires the new functionality to be properly documented (which it probably should be anyway), but does not break backwards compatibility with existing python scripts, since functionality is only added, not removed.

That said, modules (and code in general) relying on this addition without a fallback will be backwards-incompatible with current versions of cpython, but this seems unavoidable.

Looking forward to any comments :slight_smile: . Thanks for reading!

I used pyOpenSSL · PyPI to go beyond what the python ssl module supports. Can you use pyOpenSSL for DANE?

Hi, thanks for your quick response :slightly_smiling_face:
I have had a brief look through their documentation and did not find a mention of DANE. Looking further into it, there is this issue, which was closed because

this project is basically in maintenance mode at this time, and adding new features is unlikely.

The maintainer recommends opening an issue at the cryptography library, but this seems like quite far off, since apart from dealing with hashes and some X.509 certificates in the algorithms, there is no overlap with either the Recipes nor the Hazmat layer in this library.

Of course, this does not rule out verification after the handshake, and indeed the module exposes a function called get_peer_cert_chain to retrieve the entire certificate chain presented by the peer. It should probably be possible to use this to do manual DANE verification and then wrap this in an SSLContext-like object. Probably not bulletproof, since e.g. I would have liked to make use of some of the more advanced TLS-considerations, like the ability to verify the server’s certificate before sending one’s own to preserve some level of client anonymity. This one specifically could probably be addressed by having the server support post-handshake client authentication, but this is not always a given when interacting with arbitrary servers.