[PATCH] https: support tls sni (server name indication) for https urls (issue3090)

Augie Fackler raf at durin42.com
Tue Jan 13 19:57:29 CST 2015


On Jan 13, 2015, at 2:05 PM, Augie Fackler <raf at durin42.com> wrote:

> On Mon, Jan 12, 2015 at 06:11:05PM -0700, Alex Orange wrote:
>> # HG changeset patch
>> # User Alex Orange <crazycasta at gmail.com>
>> # Date 1421110880 25200
>> #      Mon Jan 12 18:01:20 2015 -0700
>> # Node ID b683de04cfd910f8f9c1c9400c748a11ef853c35
>> # Parent  678f53865c6860a950392691814766957ee89316
>> https: support tls sni (server name indication) for https urls (issue3090)
> 
> This looks like a good start. I'll do Antoine's proposal as a
> followup, as well as a couple of other tweaks I see that'll make doing
> that less of a headache.

I’ve encountered some test failures with this patch now that we actually run test-https.t on 2.7.9 - can you rebase this over mpm’s latest and see if you see them?

(I’d have posted a link, but I’m hunting an unrelated slowness problem in obsolete markers on my FreeBSD server where I push things.)

> 
> Many thanks! This has been on my todo list since the backport was announced.
> 
>> 
>> SNI is a common way of sharing servers across multiple domains using separate
>> SSL certificates. As of Python 2.7.9 SSLContext has been backported from
>> Python 3. This patch changes sslutil's ssl_wrap_socket to use SSLContext and
>> take a server hostname as and argument. It also changes the url module to make
>> use of this argument.
>> 
>> diff -r 678f53865c68 -r b683de04cfd9 mercurial/sslutil.py
>> --- a/mercurial/sslutil.py	Thu Jan 08 00:01:03 2015 +0100
>> +++ b/mercurial/sslutil.py	Mon Jan 12 18:01:20 2015 -0700
>> @@ -15,16 +15,39 @@
>>     import ssl
>>     CERT_REQUIRED = ssl.CERT_REQUIRED
>>     PROTOCOL_TLSv1 = ssl.PROTOCOL_TLSv1
>> -    def ssl_wrap_socket(sock, keyfile, certfile, ssl_version=PROTOCOL_TLSv1,
>> -                cert_reqs=ssl.CERT_NONE, ca_certs=None):
>> -        sslsocket = ssl.wrap_socket(sock, keyfile, certfile,
>> -                                    cert_reqs=cert_reqs, ca_certs=ca_certs,
>> -                                    ssl_version=ssl_version)
>> -        # check if wrap_socket failed silently because socket had been closed
>> -        # - see http://bugs.python.org/issue13721
>> -        if not sslsocket.cipher():
>> -            raise util.Abort(_('ssl connection failed'))
>> -        return sslsocket
>> +    try:
>> +        ssl_context = ssl.SSLContext
>> +
>> +        def ssl_wrap_socket(sock, keyfile, certfile, ssl_version=PROTOCOL_TLSv1,
>> +                            cert_reqs=ssl.CERT_NONE, ca_certs=None,
>> +                            server_hostname=None):
>> +            sslcontext = ssl.SSLContext(ssl_version)
>> +            if keyfile is not None:
>> +                sslcontext.load_cert_chain(certfile, keyfile)
>> +            sslcontext.verify_mode = cert_reqs
>> +            sslcontext.load_verify_locations(cafile=ca_certs)
>> +
>> +            sslsocket = sslcontext.wrap_socket(sock,
>> +                                               server_hostname=server_hostname)
>> +            # check if wrap_socket failed silently because socket had been
>> +            # closed
>> +            # - see http://bugs.python.org/issue13721
>> +            if not sslsocket.cipher():
>> +                raise util.Abort(_('ssl connection failed'))
>> +            return sslsocket
>> +    except AttributeError:
>> +        def ssl_wrap_socket(sock, keyfile, certfile, ssl_version=PROTOCOL_TLSv1,
>> +                            cert_reqs=ssl.CERT_NONE, ca_certs=None,
>> +                            server_hostname=None):
>> +            sslsocket = ssl.wrap_socket(sock, keyfile, certfile,
>> +                                        cert_reqs=cert_reqs, ca_certs=ca_certs,
>> +                                        ssl_version=ssl_version)
>> +            # check if wrap_socket failed silently because socket had been
>> +            # closed
>> +            # - see http://bugs.python.org/issue13721
>> +            if not sslsocket.cipher():
>> +                raise util.Abort(_('ssl connection failed'))
>> +            return sslsocket
>> except ImportError:
>>     CERT_REQUIRED = 2
>> 
>> @@ -33,7 +56,8 @@
>>     import socket, httplib
>> 
>>     def ssl_wrap_socket(sock, keyfile, certfile, ssl_version=PROTOCOL_TLSv1,
>> -                        cert_reqs=CERT_REQUIRED, ca_certs=None):
>> +                        cert_reqs=CERT_REQUIRED, ca_certs=None,
>> +                        server_hostname=None):
>>         if not util.safehasattr(socket, 'ssl'):
>>             raise util.Abort(_('Python SSL support not found'))
>>         if ca_certs:
>> diff -r 678f53865c68 -r b683de04cfd9 mercurial/url.py
>> --- a/mercurial/url.py	Thu Jan 08 00:01:03 2015 +0100
>> +++ b/mercurial/url.py	Mon Jan 12 18:01:20 2015 -0700
>> @@ -185,7 +185,8 @@
>>             self.sock.connect((self.host, self.port))
>>             if _generic_proxytunnel(self):
>>                 # we do not support client X.509 certificates
>> -                self.sock = sslutil.ssl_wrap_socket(self.sock, None, None)
>> +                self.sock = sslutil.ssl_wrap_socket(self.sock, None, None,
>> +                                                    server_hostname=self.host)
>>         else:
>>             keepalive.HTTPConnection.connect(self)
>> 
>> @@ -341,7 +342,7 @@
>>                 _generic_proxytunnel(self)
>>                 host = self.realhostport.rsplit(':', 1)[0]
>>             self.sock = sslutil.ssl_wrap_socket(
>> -                self.sock, self.key_file, self.cert_file,
>> +                self.sock, self.key_file, self.cert_file, server_hostname=host,
>>                 **sslutil.sslkwargs(self.ui, host))
>>             sslutil.validator(self.ui, host)(self.sock)
>> 
>> _______________________________________________
>> Mercurial-devel mailing list
>> Mercurial-devel at selenic.com
>> http://selenic.com/mailman/listinfo/mercurial-devel
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: Message signed with OpenPGP using GPGMail
URL: <http://selenic.com/pipermail/mercurial-devel/attachments/20150113/752d84a3/attachment.pgp>


More information about the Mercurial-devel mailing list