Mercurial > hg
changeset 29554:4a7b0c696fbc
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.
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Thu, 14 Jul 2016 20:14:19 -0700 |
parents | cd3e58862cab |
children | 121d11814c62 |
files | mercurial/sslutil.py |
diffstat | 1 files changed, 46 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/sslutil.py Wed Jul 13 00:14:50 2016 -0700 +++ b/mercurial/sslutil.py Thu Jul 14 20:14:19 2016 -0700 @@ -325,6 +325,52 @@ 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: + # We /could/ use create_default_context() here since it doesn't load + # CAs when configured for client auth. + sslcontext = SSLContext(ssl.PROTOCOL_SSLv23) + # SSLv2 and SSLv3 are broken. Ban them outright. + sslcontext.options |= OP_NO_SSLv2 | OP_NO_SSLv3 + # Prevent CRIME + sslcontext.options |= getattr(ssl, 'OP_NO_COMPRESSION', 0) + # Improve forward secrecy. + sslcontext.options |= getattr(ssl, 'OP_SINGLE_DH_USE', 0) + sslcontext.options |= getattr(ssl, 'OP_SINGLE_ECDH_USE', 0) + + # Use the list of more secure ciphers if found in the ssl module. + if util.safehasattr(ssl, '_RESTRICTED_SERVER_CIPHERS'): + sslcontext.options |= getattr(ssl, 'OP_CIPHER_SERVER_PREFERENCE', 0) + sslcontext.set_ciphers(ssl._RESTRICTED_SERVER_CIPHERS) + else: + sslcontext = SSLContext(ssl.PROTOCOL_TLSv1) + + 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."""