Patchwork https: support tls sni (server name indication) for https urls (issue3090)

login
register
mail settings
Submitter Alex Orange
Date Jan. 13, 2015, 1:11 a.m.
Message ID <b683de04cfd910f8f9c1.1421111465@localhost>
Download mbox | patch
Permalink /patch/7446/
State Superseded
Commit 40d582ff434f3fdca4f78655503bb177388dda66
Headers show

Comments

Alex Orange - Jan. 13, 2015, 1:11 a.m.
# HG changeset patch
# User Alex Orange <crazycasta@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)

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.
Antoine Pitrou - Jan. 13, 2015, 8:53 a.m.
On Mon, 12 Jan 2015 18:11:05 -0700
Alex Orange <crazycasta@gmail.com> wrote:
> +
> +        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)

I would recommend using create_default_context() if possible:
https://docs.python.org/2.7/library/ssl.html#ssl.create_default_context

Regards

Antoine.
Augie Fackler - Jan. 13, 2015, 7:05 p.m.
On Mon, Jan 12, 2015 at 06:11:05PM -0700, Alex Orange wrote:
> # HG changeset patch
> # User Alex Orange <crazycasta@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.

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@selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel
Augie Fackler - Jan. 14, 2015, 1:57 a.m.
On Jan 13, 2015, at 2:05 PM, Augie Fackler <raf@durin42.com> wrote:

> On Mon, Jan 12, 2015 at 06:11:05PM -0700, Alex Orange wrote:
>> # HG changeset patch
>> # User Alex Orange <crazycasta@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@selenic.com
>> http://selenic.com/mailman/listinfo/mercurial-devel
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel
Alex Orange - Jan. 14, 2015, 2:41 a.m.
Ok, I've found the problem, wasn't checking ca_certs for noneness. I wasn't
aware that there was a path that it could be None and so wasn't checking
for it. I've checked everything else and everything either can't be None
(sock, ssl_version, cert_reqs), is checked (certfile and ca_certs), or is
ok to be None. keyfile is okay to be None because this indicates that the
private key is in the cert file (I don't believe we actually use this, but
as far as I can tell it's the best consistency with the underlying
behavior). server_hostname can also be None, which I presume means that SNI
is not invoked (I've tested that it doesn't throw anything, but I'm not
sure what effect it has). test-https.t works and I'm running the rest of
the tests, assuming they all pass I'll send a new patch.

On Tue, Jan 13, 2015 at 6:57 PM, Augie Fackler <raf@durin42.com> wrote:

>
> On Jan 13, 2015, at 2:05 PM, Augie Fackler <raf@durin42.com> wrote:
>
> > On Mon, Jan 12, 2015 at 06:11:05PM -0700, Alex Orange wrote:
> >> # HG changeset patch
> >> # User Alex Orange <crazycasta@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@selenic.com
> >> http://selenic.com/mailman/listinfo/mercurial-devel
> > _______________________________________________
> > Mercurial-devel mailing list
> > Mercurial-devel@selenic.com
> > http://selenic.com/mailman/listinfo/mercurial-devel
>
>

Patch

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)