comparison mercurial/sslutil.py @ 19806:47ff9d1abfa9

sslutil: add a config knob to support TLS (default) or SSLv23 (bc) (issue4038) Prior to this change, we default to SSLv23, which is insecure because it allows use of SSLv2. Unfortunately, there's no constant for OpenSSL to let us use SSLv3 or TLS - we have to pick one or the other. We expose a knob to revert to pre-TLS SSL for the user that has an ancient server that lacks proper TLS support.
author Augie Fackler <raf@durin42.com>
date Thu, 19 Sep 2013 16:29:00 -0400
parents f2871c30e6a7
children 3b82d412e9e8
comparison
equal deleted inserted replaced
19805:9b088e9c2690 19806:47ff9d1abfa9
12 from mercurial.i18n import _ 12 from mercurial.i18n import _
13 try: 13 try:
14 # avoid using deprecated/broken FakeSocket in python 2.6 14 # avoid using deprecated/broken FakeSocket in python 2.6
15 import ssl 15 import ssl
16 CERT_REQUIRED = ssl.CERT_REQUIRED 16 CERT_REQUIRED = ssl.CERT_REQUIRED
17 def ssl_wrap_socket(sock, keyfile, certfile, 17 PROTOCOL_SSLv23 = ssl.PROTOCOL_SSLv23
18 PROTOCOL_TLSv1 = ssl.PROTOCOL_TLSv1
19 def ssl_wrap_socket(sock, keyfile, certfile, ssl_version=PROTOCOL_TLSv1,
18 cert_reqs=ssl.CERT_NONE, ca_certs=None): 20 cert_reqs=ssl.CERT_NONE, ca_certs=None):
19 sslsocket = ssl.wrap_socket(sock, keyfile, certfile, 21 sslsocket = ssl.wrap_socket(sock, keyfile, certfile,
20 cert_reqs=cert_reqs, ca_certs=ca_certs) 22 cert_reqs=cert_reqs, ca_certs=ca_certs,
23 ssl_version=ssl_version)
21 # check if wrap_socket failed silently because socket had been closed 24 # check if wrap_socket failed silently because socket had been closed
22 # - see http://bugs.python.org/issue13721 25 # - see http://bugs.python.org/issue13721
23 if not sslsocket.cipher(): 26 if not sslsocket.cipher():
24 raise util.Abort(_('ssl connection failed')) 27 raise util.Abort(_('ssl connection failed'))
25 return sslsocket 28 return sslsocket
26 except ImportError: 29 except ImportError:
27 CERT_REQUIRED = 2 30 CERT_REQUIRED = 2
28 31
32 PROTOCOL_SSLv23 = 2
33 PROTOCOL_TLSv1 = 3
34
29 import socket, httplib 35 import socket, httplib
30 36
31 def ssl_wrap_socket(sock, key_file, cert_file, 37 def ssl_wrap_socket(sock, key_file, cert_file, ssl_version=PROTOCOL_TLSv1,
32 cert_reqs=CERT_REQUIRED, ca_certs=None): 38 cert_reqs=CERT_REQUIRED, ca_certs=None):
33 if not util.safehasattr(socket, 'ssl'): 39 if not util.safehasattr(socket, 'ssl'):
34 raise util.Abort(_('Python SSL support not found')) 40 raise util.Abort(_('Python SSL support not found'))
35 if ca_certs: 41 if ca_certs:
36 raise util.Abort(_( 42 raise util.Abort(_(
82 # We COMPLETELY ignore CERT_REQUIRED on Python <= 2.5, as it's totally 88 # We COMPLETELY ignore CERT_REQUIRED on Python <= 2.5, as it's totally
83 # busted on those versions. 89 # busted on those versions.
84 90
85 def sslkwargs(ui, host): 91 def sslkwargs(ui, host):
86 cacerts = ui.config('web', 'cacerts') 92 cacerts = ui.config('web', 'cacerts')
93 forcetls = ui.configbool('ui', 'tls', default=True)
94 if forcetls:
95 ssl_version = PROTOCOL_TLSv1
96 else:
97 ssl_version = PROTOCOL_SSLv23
87 hostfingerprint = ui.config('hostfingerprints', host) 98 hostfingerprint = ui.config('hostfingerprints', host)
99 kws = {'ssl_version': ssl_version,
100 }
88 if cacerts and not hostfingerprint: 101 if cacerts and not hostfingerprint:
89 cacerts = util.expandpath(cacerts) 102 cacerts = util.expandpath(cacerts)
90 if not os.path.exists(cacerts): 103 if not os.path.exists(cacerts):
91 raise util.Abort(_('could not find web.cacerts: %s') % cacerts) 104 raise util.Abort(_('could not find web.cacerts: %s') % cacerts)
92 return {'ca_certs': cacerts, 105 kws.update({'ca_certs': cacerts,
93 'cert_reqs': CERT_REQUIRED, 106 'cert_reqs': CERT_REQUIRED,
94 } 107 })
95 return {} 108 return kws
96 109
97 class validator(object): 110 class validator(object):
98 def __init__(self, ui, host): 111 def __init__(self, ui, host):
99 self.ui = ui 112 self.ui = ui
100 self.host = host 113 self.host = host