Original patch developed by grooverdan Reference: http://bugs.python.org/issue5639 Patch adapted to Python 3.1.3-r1 by david@blue-labs.org diff -ruN Python-3.1.3/Doc/library/ssl.rst Python-3.1.3.patched//Doc/library/ssl.rst --- Python-3.1.3/Doc/library/ssl.rst 2010-10-06 03:55:35.000000000 -0400 +++ Python-3.1.3.patched//Doc/library/ssl.rst 2011-06-10 16:04:15.241911484 -0400 @@ -47,7 +47,7 @@ is a subtype of :exc:`socket.error`, which in turn is a subtype of :exc:`IOError`. -.. function:: wrap_socket(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version={see docs}, ca_certs=None, do_handshake_on_connect=True, suppress_ragged_eofs=True) +.. function:: wrap_socket (sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version={see docs}, ca_certs=None, server_hostname=None, do_handshake_on_connect=True, suppress_ragged_eofs=True) Takes an instance ``sock`` of :class:`socket.socket`, and returns an instance of :class:`ssl.SSLSocket`, a subtype of :class:`socket.socket`, which wraps @@ -119,6 +119,10 @@ In some older versions of OpenSSL (for instance, 0.9.7l on OS X 10.4), an SSLv2 client could not connect to an SSLv23 server. + The parameter ``server_hostname`` specifies the hostname in the SSL client connection + (SSLv3 or TLSv1) allowing the server to run multiple certificates on a single host + (Server Name Indication extension defined in RFC 4366). + The parameter ``do_handshake_on_connect`` specifies whether to do the SSL handshake automatically after doing a :meth:`socket.connect`, or whether the application program will call it explicitly, by invoking the @@ -580,3 +584,6 @@ `RFC 3280: Internet X.509 Public Key Infrastructure Certificate and CRL Profile `_ Housley et. al. + + `RFC 4366: Transport Layer Security (TLS) Extensions `_ + Blake-Wilson et. al. diff -ruN Python-3.1.3/Lib/ssl.py Python-3.1.3.patched//Lib/ssl.py --- Python-3.1.3/Lib/ssl.py 2010-09-14 10:47:08.000000000 -0400 +++ Python-3.1.3.patched//Lib/ssl.py 2011-06-10 16:04:15.241911484 -0400 @@ -92,6 +92,7 @@ def __init__(self, sock=None, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version=PROTOCOL_SSLv23, ca_certs=None, + server_hostname=None, do_handshake_on_connect=True, family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None, suppress_ragged_eofs=True): @@ -128,7 +129,8 @@ try: self._sslobj = _ssl.sslwrap(self, server_side, keyfile, certfile, - cert_reqs, ssl_version, ca_certs) + cert_reqs, ssl_version, + ca_certs, server_hostname) if do_handshake_on_connect: timeout = self.gettimeout() if timeout == 0.0: @@ -145,6 +147,7 @@ self.cert_reqs = cert_reqs self.ssl_version = ssl_version self.ca_certs = ca_certs + self.server_hostname = server_hostname self.do_handshake_on_connect = do_handshake_on_connect self.suppress_ragged_eofs = suppress_ragged_eofs @@ -332,7 +335,7 @@ socket.connect(self, addr) self._sslobj = _ssl.sslwrap(self, False, self.keyfile, self.certfile, self.cert_reqs, self.ssl_version, - self.ca_certs) + self.ca_certs, self.server_hostname) try: if self.do_handshake_on_connect: self.do_handshake() @@ -364,12 +367,14 @@ def wrap_socket(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version=PROTOCOL_SSLv23, ca_certs=None, + server_hostname=None, do_handshake_on_connect=True, suppress_ragged_eofs=True): return SSLSocket(sock=sock, keyfile=keyfile, certfile=certfile, server_side=server_side, cert_reqs=cert_reqs, ssl_version=ssl_version, ca_certs=ca_certs, + server_hostname=server_hostname, do_handshake_on_connect=do_handshake_on_connect, suppress_ragged_eofs=suppress_ragged_eofs) diff -ruN Python-3.1.3/Lib/test/test_ssl.py Python-3.1.3.patched//Lib/test/test_ssl.py --- Python-3.1.3/Lib/test/test_ssl.py 2010-11-26 03:59:40.000000000 -0500 +++ Python-3.1.3.patched//Lib/test/test_ssl.py 2011-06-10 16:04:15.241911484 -0400 @@ -644,7 +644,8 @@ def server_params_test(certfile, protocol, certreqs, cacertsfile, client_certfile, client_protocol=None, indata=b"FOO\n", - chatty=True, connectionchatty=False): + chatty=True, connectionchatty=False, + server_hostname=None): """ Launch a server, connect a client to it and try various reads and writes. @@ -667,7 +668,8 @@ certfile=client_certfile, ca_certs=cacertsfile, cert_reqs=certreqs, - ssl_version=client_protocol) + ssl_version=client_protocol, + server_hostname=server_hostname) s.connect((HOST, server.port)) arg = indata if connectionchatty: @@ -741,6 +743,24 @@ CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1, chatty=True, connectionchatty=True) + def testSNI_TLS (self): + + if support.verbose: + sys.stdout.write("\n") + serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE, + CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1, + chatty=True,connectionchatty=True, + server_hostname='arbitary.host.name') + + def testSNI_SSL2 (self): + + if support.verbose: + sys.stdout.write("\n") + serverParamsTest(CERTFILE, ssl.PROTOCOL_SSLv2, ssl.CERT_NONE, + CERTFILE, CERTFILE, ssl.PROTOCOL_SSLv2, + chatty=True,connectionchatty=True, + server_hostname='arbitary.host.name') + def test_getpeercert(self): if support.verbose: sys.stdout.write("\n") diff -ruN Python-3.1.3/Modules/_ssl.c Python-3.1.3.patched//Modules/_ssl.c --- Python-3.1.3/Modules/_ssl.c 2010-10-13 18:20:48.000000000 -0400 +++ Python-3.1.3.patched//Modules/_ssl.c 2011-06-10 16:04:15.241911484 -0400 @@ -269,7 +269,7 @@ enum py_ssl_server_or_client socket_type, enum py_ssl_cert_requirements certreq, enum py_ssl_version proto_version, - char *cacerts_file) + char *cacerts_file, char *server_hostname) { PySSLObject *self; char *errstr = NULL; @@ -374,6 +374,14 @@ PySSL_BEGIN_ALLOW_THREADS self->ssl = SSL_new(self->ctx); /* New ssl struct */ +#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT) + /* If SNI isn't supported, we just don't call it and fail silently, + * as there's not much else we can do. + */ + if ((socket_type == PY_SSL_CLIENT) && + (proto_version != PY_SSL_VERSION_SSL2) && server_hostname) + SSL_set_tlsext_host_name(self->ssl, server_hostname); +#endif PySSL_END_ALLOW_THREADS SSL_set_fd(self->ssl, Sock->sock_fd); /* Set the socket for SSL */ #ifdef SSL_MODE_AUTO_RETRY @@ -415,32 +423,34 @@ char *key_file = NULL; char *cert_file = NULL; char *cacerts_file = NULL; + char *server_hostname = NULL; - if (!PyArg_ParseTuple(args, "O!i|zziiz:sslwrap", + if (!PyArg_ParseTuple(args, "O!i|zziizz:sslwrap", PySocketModule.Sock_Type, &Sock, &server_side, &key_file, &cert_file, &verification_mode, &protocol, - &cacerts_file)) + &cacerts_file, &server_hostname)) return NULL; /* fprintf(stderr, "server_side is %d, keyfile %p, certfile %p, verify_mode %d, " - "protocol %d, certs %p\n", + "protocol %d, certs %p, server_hostname %p\n", server_side, key_file, cert_file, verification_mode, - protocol, cacerts_file); + protocol, cacerts_file, server_hostname); */ return (PyObject *) newPySSLObject(Sock, key_file, cert_file, server_side, verification_mode, - protocol, cacerts_file); + protocol, cacerts_file, + server_hostname); } PyDoc_STRVAR(ssl_doc, "sslwrap(socket, server_side, [keyfile, certfile, certs_mode, protocol,\n" -" cacertsfile]) -> sslobject"); +" cacertsfile, server_hostname]) -> sslobject"); /* SSL object methods */