[PATCH 06 of 11 V4] hgweb: use sslutil.wrapserversocket()

Gregory Szorc gregory.szorc at gmail.com
Fri Jul 15 00:09:07 EDT 2016


# HG changeset patch
# User Gregory Szorc <gregory.szorc at gmail.com>
# Date 1468390323 25200
#      Tue Jul 12 23:12:03 2016 -0700
# Node ID 539058a0cb93216877c6116b3071cc12cab9e679
# Parent  e0c8977678cca5a1ceb8174ecd347810482f6656
hgweb: use sslutil.wrapserversocket()

This patch transitions the built-in HTTPS server to use sslutil for
creating the server socket.

As part of this transition, we implement developer-only config options
to control CA loading and whether to require client certificates. This
eliminates the need for the custom extension in test-https.t to define
these.

There is a slight change in behavior with regards to protocol
selection. Before, we would always use the TLS 1.0 constant to define
the protocol version. This would *only* use TLS 1.0. sslutil defaults
to TLS 1.0+. So this patch improves the security of `hg serve` out of
the box by allowing it to use TLS 1.1 and 1.2 (if available).

diff --git a/mercurial/hgweb/server.py b/mercurial/hgweb/server.py
--- a/mercurial/hgweb/server.py
+++ b/mercurial/hgweb/server.py
@@ -219,25 +219,33 @@ class _httprequesthandler(BaseHTTPServer
 class _httprequesthandlerssl(_httprequesthandler):
     """HTTPS handler based on Python's ssl module"""
 
     url_scheme = 'https'
 
     @staticmethod
     def preparehttpserver(httpserver, ui):
         try:
-            import ssl
-            ssl.wrap_socket
+            from .. import sslutil
+            sslutil.modernssl
         except ImportError:
             raise error.Abort(_("SSL support is unavailable"))
 
         certfile = ui.config('web', 'certificate')
-        httpserver.socket = ssl.wrap_socket(
-            httpserver.socket, server_side=True,
-            certfile=certfile, ssl_version=ssl.PROTOCOL_TLSv1)
+
+        # These config options are currently only meant for testing. Use
+        # at your own risk.
+        cafile = ui.config('devel', 'servercafile')
+        reqcert = ui.configbool('devel', 'serverrequirecert')
+
+        httpserver.socket = sslutil.wrapserversocket(httpserver.socket,
+                                                     ui,
+                                                     certfile=certfile,
+                                                     cafile=cafile,
+                                                     requireclientcert=reqcert)
 
     def setup(self):
         self.connection = self.request
         self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
         self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
 
 try:
     import threading
diff --git a/tests/test-https.t b/tests/test-https.t
--- a/tests/test-https.t
+++ b/tests/test-https.t
@@ -392,37 +392,21 @@ Test https with cert problems through pr
   abort: error: *certificate verify failed* (glob)
   [255]
 
 
   $ killdaemons.py hg0.pid
 
 #if sslcontext
 
-Start patched hgweb that requires client certificates:
+Start hgweb that requires client certificates:
 
-  $ cat << EOT > reqclientcert.py
-  > import ssl
-  > from mercurial.hgweb import server
-  > class _httprequesthandlersslclientcert(server._httprequesthandlerssl):
-  >     @staticmethod
-  >     def preparehttpserver(httpserver, ui):
-  >         certfile = ui.config('web', 'certificate')
-  >         sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
-  >         sslcontext.verify_mode = ssl.CERT_REQUIRED
-  >         sslcontext.load_cert_chain(certfile)
-  >         # verify clients by server certificate
-  >         sslcontext.load_verify_locations(certfile)
-  >         httpserver.socket = sslcontext.wrap_socket(httpserver.socket,
-  >                                                    server_side=True)
-  > server._httprequesthandlerssl = _httprequesthandlersslclientcert
-  > EOT
   $ cd test
   $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV \
-  > --config extensions.reqclientcert=../reqclientcert.py
+  > --config devel.servercafile=$PRIV --config devel.serverrequirecert=true
   $ cat ../hg0.pid >> $DAEMON_PIDS
   $ cd ..
 
 without client certificate:
 
   $ P="$CERTSDIR" hg id https://localhost:$HGPORT/
   abort: error: *handshake failure* (glob)
   [255]


More information about the Mercurial-devel mailing list