[PATCH 3 of 6 V2] sslutil: implement wrapserversocket()

Gregory Szorc gregory.szorc at gmail.com
Wed Jul 13 03:18:09 EDT 2016


# HG changeset patch
# User Gregory Szorc <gregory.szorc at gmail.com>
# Date 1468390002 25200
#      Tue Jul 12 23:06:42 2016 -0700
# Node ID 005dfad47596743676ac4146e2b9fc6cdafa407b
# Parent  8fc44e26c415d33b15ed9ba9dd1e29522eafb251
sslutil: implement wrapserversocket()

wrapsocket() is heavily tailored towards client use. In preparation
for converting the built-in server to use sslutil (as opposed to
the ssl module directly), we add wrapserversocket() for wrapping
a socket to be used on servers.

diff --git a/mercurial/sslutil.py b/mercurial/sslutil.py
--- a/mercurial/sslutil.py
+++ b/mercurial/sslutil.py
@@ -326,16 +326,53 @@ def wrapsocket(sock, keyfile, certfile, 
         'caloaded': caloaded,
         'hostname': serverhostname,
         'settings': settings,
         'ui': ui,
     }
 
     return sslsocket
 
+def wrapserversocket(sock, ui, certfile=None, keyfile=None, cafile=None,
+                     requireclientcert=False):
+    """Wrap a socket for use by servers.
+
+    ``certfile`` and ``keyfile`` specify the files containing the certificate's
+    public and private keys, respectively. Both keys can be defined in the same
+    file via ``certfile`` (the private key must come first in the file).
+
+    ``cafile`` defines the path to certificate authorities.
+
+    ``requireclientcert`` specifies whether to require client certificates.
+
+    Typically ``cafile`` is only defined if ``requireclientcert`` is true.
+    """
+    if modernssl:
+        sslcontext = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH)
+    else:
+        sslcontext = SSLContext(ssl.PROTOCOL_TLSv1)
+
+    # We don't need to apply options to the context here because either
+    # a) create_default_context() has appropriate defaults and we don't have
+    # any custom settings to apply b) legacy ssl module is already using the
+    # appropriate protocol.
+
+    if requireclientcert:
+        sslcontext.verify_mode = ssl.CERT_REQUIRED
+    else:
+        sslcontext.verify_mode = ssl.CERT_NONE
+
+    if certfile or keyfile:
+        sslcontext.load_cert_chain(certfile=certfile, keyfile=keyfile)
+
+    if cafile:
+        sslcontext.load_verify_locations(cafile=cafile)
+
+    return sslcontext.wrap_socket(sock, server_side=True)
+
 class wildcarderror(Exception):
     """Represents an error parsing wildcards in DNS name."""
 
 def _dnsnamematch(dn, hostname, maxwildcards=1):
     """Match DNS names according RFC 6125 section 6.4.3.
 
     This code is effectively copied from CPython's ssl._dnsname_match.
 


More information about the Mercurial-devel mailing list