Talk Review: A Dive into TLS

The "S" in "HTTPS" stands for secure.

This is from the series of entries covering topics of note from PyCon 2015. More articles from this series can be found here.

Credit for the talk should go to Benjamin Peterson. A video can be seen here.

Overview

This talk discussed the state of the SSL library in Python2 and Python3. Python does not actually have native SSL/TLS implementation, opting instead to make calls out to OpenSSL. It is debatable whether this is good or bad, but at minimum what can be said is that OpenSSL is battle tested and only rarely exhibits widely exploitable bugs (Heartbleed).

However, it can be said that until recently the state of SSL in Python, especially Python 2, was abysmal. The SSL library in the Python2.7 standard Lib had become aged while it's much more attractive and younger sister Python3 was updated. This was largely due to the fact that in 2010 Python 2.7 was frozen for new feature development and back ports are individually justified via the PEP process.

Over the course of the last year PEPs 466 and 476 were filed with the aim of network security enhancements for Python 2.7.x and specifically for 476 enabling certificate validation by default.

PEP 466

TLS v1.2 and modern cipher suites

I'll spare you my two light-nanosecond deep understanding of the details of the differences in TLS v1.0 and TLS v1.2. The important things to keep in mind are that TSL v1.0 was specified in 1999 while TLS v1.2 was specific in 2008 and therefore is hardened against vulnerabilities discovered in the 9 intervening years. V1.2 removes the IDEA and DES cipher suites which are known to be insecure. V1.2 adds support for TLS extensions defined in RFC 3546.

SNI support

This is technically a TLS extension. However, as it holds a special place in my heart, I'm calling it out specifically. SNI or Server Name Indication is a protocol extension for TLS wherein the client application, e.g. the browser, along with the initial request will encode the domain name it's attempting to reach. The server then in kind responds with the certificate that it has for that domain. This is worthwhile in order to host multiple website under one IP address to physical interface without the need for proxies (meaning pre-gateway network communication is unencrypted) or combined certificates wherein all possible addresses served from that IP are in the subject alternative name list of the cert (and thus increasing the blast radius if the cert compromised).

SSLContext manipulation

Now in Python 2.7 and 3, the SSL module has a concept of configuration contexts. Prior to this addition, using the SSL module required the user to create manually configure and wrap their sockets.

while True:
   newsocket, fromaddr = bindsocket.accept()
   connstream = ssl.wrap_socket(newsocket,
                                server_side=True,
                                certfile="mycertfile",
                                keyfile="mykeyfile",
                                ssl_version=ssl.PROTOCOL_TLSv1)
   deal_with_client(connstream)

Not only did this require an eye for detail and knowledge of how the SSL module works, it was prone to leaving SSL configuration lying around the code base which may or may not be updated to comply with the latest guidance.

As of this addition, the Python SSL module ships with a set of defaults and the ability to read system certificate stores (for trust configuration). The SSL Context itself furnishes a wrap_socket method into which a socket is passed.

context = ssl.create_default_context()
sock = socket.create_connection(('elif.us',443))
context.wrap_socket(sock)

PEP 476 - certificate validation by default

The fact that this was not already default somewhat saddens me.

A notable quote from the PEP:

The "S" in "HTTPS" stands for secure. When Python's users type "HTTPS" they are expecting a secure connection, and Python should adhere to a reasonable standard of care in delivering this. Currently we are failing at this, and in doing so, APIs which appear simple are misleading users.

When asked, many Python users state that they were not aware that Python failed to perform these validations, and are shocked.

Creative Commons image used for banner. Image credit: Sean MacEntee