Issue2446

classification
Title: Support SNI for SSL/TLS client sockets
Type: Severity: normal
Components: Versions: Jython 2.7
Milestone: Jython 2.7.1
process
Status: pending Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: amak, darjus, zyasoft
Priority: high Keywords:

Created on 2015-12-29.14:21:45 by zyasoft, last changed 2016-11-13.20:41:23 by zyasoft.

Messages
msg10562 (view) Author: Jim Baker (zyasoft) Date: 2015-12-29.14:21:44
SNI (server name information) is an extension to SSL/TLS that allows the client to select a hostname and the server to pick the appropriate certificate matching that hostname. Although there is internal support in Java 7, it really requires Java 8 to use the public API. Since the ssl module is written in Python, it is easy to provide this support only on Java 8 or higher, by using standard ImportError handling semantics.

Server side. Python specifies a callback on the SSL context (https://docs.python.org/2.7/library/ssl.html#ssl.SSLContext.set_servername_callback), which corresponds roughly to the SniHandler class provided by Netty 4 (http://netty.io/4.0/api/io/netty/handler/ssl/SniHandler.html). By default, SniHandler will automatically switch the SSL context, but a subclass of SniHandler can override SniHandler.sslContext, which can in turn interrogate SniHandler.hostname() to provide set_servername_callback.

Client side. In wrapping a socket, client code can specify the desired server hostname. This hostname in turn can be set in the ssl module's SSLContext._createSSLEngine, which currenty sets some of the SSL parameters, via javax.net.ssl.SSLParameters.setServerNames(javax.net.ssl.SNIHostName(server_name)).

There is some additional certificate functionality that is already implemented for SNI in Jython's ssl, namely match_hostname. But it looks like we need to complete SSLContext.check_hostname support.
msg10953 (view) Author: Darjus Loktevic (darjus) Date: 2016-09-19.13:11:37
Client-side SNI support should now be implemented in: https://hg.python.org/jython/rev/a07c595b410f
msg10963 (view) Author: Jim Baker (zyasoft) Date: 2016-10-05.16:43:50
So this still fails:

from __future__ import print_function
import socket
import ssl

context = ssl.create_default_context()
my_socket = context.wrap_socket(socket.socket(socket.AF_INET), server_hostname="www.mnot.net")
my_socket.connect(("www.mnot.net", 443))
my_socket.send(b"GET /blog/2014/05/09/if_you_can_read_this_youre_sniing HTTP/1.1\r\n")
my_socket.send(b"Host: www.mnot.net\r\n\r\n")
data = my_socket.recv(1000000)
print(data)

fails on Jython trunk with

_socket.SSLError: [Errno 1] certificate verify failed (javax.net.ssl.SSLHandshakeException: General SSLEngine problem)

but works on CPython 2.7.10 (and 3.5), getting the Connection: Upgrade response
msg10983 (view) Author: Jim Baker (zyasoft) Date: 2016-11-13.20:41:22
The real underlying problem for the SNI probe page we were trying (www.mnot.net) is that it uses Let's Encrypt, which did not have any CA support prior to Java 8u111. Just tested with an updated JDK and everything looks good. So some unfortunate delays here, but that's being busy.

I changed the title to reflect we still have SNI server support to add. Probably easy, but not something we should delay further for.

As usual, the best way to understand this problem was to compare to an alternative just using Java classes (with minimal Jython wrapping), vs the much more complex entity seen when using our socket/ssl/select alternative:

from __future__ import print_function

from java.io import BufferedInputStream
from java.net import URL
import jarray

url = URL("https://www.mnot.net/blog/2014/05/09/if_you_can_read_this_youre_sniing")
stream = BufferedInputStream(url.openStream())

data = []
while True:
    data.append(jarray.zeros(1024, "b"))
    amount_read = stream.read(data[-1], 0, 1024)
    if amount_read == -1:
        break

print("".join((buff.tostring() for buff in data)))
History
Date User Action Args
2016-11-13 20:41:23zyasoftsetstatus: open -> pending
resolution: fixed
messages: + msg10983
title: Support SNI for SSL/TLS -> Support SNI for SSL/TLS client sockets
2016-10-24 09:58:49zyasoftsetmilestone: Jython 2.7.2 -> Jython 2.7.1
2016-10-05 16:43:50zyasoftsetmessages: + msg10963
2016-09-19 13:11:38darjussetmessages: + msg10953
2016-02-08 15:51:39zyasoftsetpriority: high
2016-02-05 17:45:05amaksetnosy: + amak
2015-12-29 14:31:27zyasoftsetnosy: + darjus
2015-12-29 14:21:45zyasoftcreate