comparison mercurial/sslutil.py @ 29249:cca59ef27e60

sslutil: move sslkwargs logic into internal function (API) As the previous commit documented, sslkwargs() doesn't add any value since its return is treated as a black box and proxied to wrapsocket(). We formalize its uselessness by moving its logic into a new, internal function and make sslkwargs() return an empty dict. The certificate arguments that sslkwargs specified have been removed from wrapsocket() because they should no longer be set.
author Gregory Szorc <gregory.szorc@gmail.com>
date Wed, 25 May 2016 19:52:02 -0700
parents e6de6ef3e426
children 9da137faaa9c
comparison
equal deleted inserted replaced
29248:e6de6ef3e426 29249:cca59ef27e60
104 if self._supportsciphers: 104 if self._supportsciphers:
105 args['ciphers'] = self._ciphers 105 args['ciphers'] = self._ciphers
106 106
107 return ssl.wrap_socket(socket, **args) 107 return ssl.wrap_socket(socket, **args)
108 108
109 def wrapsocket(sock, keyfile, certfile, ui, cert_reqs=ssl.CERT_NONE, 109 def _determinecertoptions(ui, host):
110 ca_certs=None, serverhostname=None): 110 """Determine certificate options for a connections.
111
112 Returns a tuple of (cert_reqs, ca_certs).
113 """
114 # If a host key fingerprint is on file, it is the only thing that matters
115 # and CA certs don't come into play.
116 hostfingerprint = ui.config('hostfingerprints', host)
117 if hostfingerprint:
118 return ssl.CERT_NONE, None
119
120 # The code below sets up CA verification arguments. If --insecure is
121 # used, we don't take CAs into consideration, so return early.
122 if ui.insecureconnections:
123 return ssl.CERT_NONE, None
124
125 cacerts = ui.config('web', 'cacerts')
126
127 # If a value is set in the config, validate against a path and load
128 # and require those certs.
129 if cacerts:
130 cacerts = util.expandpath(cacerts)
131 if not os.path.exists(cacerts):
132 raise error.Abort(_('could not find web.cacerts: %s') % cacerts)
133
134 return ssl.CERT_REQUIRED, cacerts
135
136 # No CAs in config. See if we can load defaults.
137 cacerts = _defaultcacerts()
138
139 # We found an alternate CA bundle to use. Load it.
140 if cacerts:
141 ui.debug('using %s to enable OS X system CA\n' % cacerts)
142 ui.setconfig('web', 'cacerts', cacerts, 'defaultcacerts')
143 return ssl.CERT_REQUIRED, cacerts
144
145 # FUTURE this can disappear once wrapsocket() is secure by default.
146 if _canloaddefaultcerts:
147 return ssl.CERT_REQUIRED, None
148
149 return ssl.CERT_NONE, None
150
151 def wrapsocket(sock, keyfile, certfile, ui, serverhostname=None):
111 """Add SSL/TLS to a socket. 152 """Add SSL/TLS to a socket.
112 153
113 This is a glorified wrapper for ``ssl.wrap_socket()``. It makes sane 154 This is a glorified wrapper for ``ssl.wrap_socket()``. It makes sane
114 choices based on what security options are available. 155 choices based on what security options are available.
115 156
120 server (and client) support SNI, this tells the server which certificate 161 server (and client) support SNI, this tells the server which certificate
121 to use. 162 to use.
122 """ 163 """
123 if not serverhostname: 164 if not serverhostname:
124 raise error.Abort('serverhostname argument is required') 165 raise error.Abort('serverhostname argument is required')
166
167 cert_reqs, ca_certs = _determinecertoptions(ui, serverhostname)
125 168
126 # Despite its name, PROTOCOL_SSLv23 selects the highest protocol 169 # Despite its name, PROTOCOL_SSLv23 selects the highest protocol
127 # that both ends support, including TLS protocols. On legacy stacks, 170 # that both ends support, including TLS protocols. On legacy stacks,
128 # the highest it likely goes in TLS 1.0. On modern stacks, it can 171 # the highest it likely goes in TLS 1.0. On modern stacks, it can
129 # support TLS 1.2. 172 # support TLS 1.2.
241 return dummycert 284 return dummycert
242 285
243 return None 286 return None
244 287
245 def sslkwargs(ui, host): 288 def sslkwargs(ui, host):
246 """Determine arguments to pass to wrapsocket(). 289 return {}
247
248 ``host`` is the hostname being connected to.
249 """
250 kws = {}
251
252 # If a host key fingerprint is on file, it is the only thing that matters
253 # and CA certs don't come into play.
254 hostfingerprint = ui.config('hostfingerprints', host)
255 if hostfingerprint:
256 return kws
257
258 # The code below sets up CA verification arguments. If --insecure is
259 # used, we don't take CAs into consideration, so return early.
260 if ui.insecureconnections:
261 return kws
262
263 cacerts = ui.config('web', 'cacerts')
264
265 # If a value is set in the config, validate against a path and load
266 # and require those certs.
267 if cacerts:
268 cacerts = util.expandpath(cacerts)
269 if not os.path.exists(cacerts):
270 raise error.Abort(_('could not find web.cacerts: %s') % cacerts)
271
272 kws.update({'ca_certs': cacerts,
273 'cert_reqs': ssl.CERT_REQUIRED})
274 return kws
275
276 # No CAs in config. See if we can load defaults.
277 cacerts = _defaultcacerts()
278
279 # We found an alternate CA bundle to use. Load it.
280 if cacerts:
281 ui.debug('using %s to enable OS X system CA\n' % cacerts)
282 ui.setconfig('web', 'cacerts', cacerts, 'defaultcacerts')
283 kws.update({'ca_certs': cacerts,
284 'cert_reqs': ssl.CERT_REQUIRED})
285 return kws
286
287 # FUTURE this can disappear once wrapsocket() is secure by default.
288 if _canloaddefaultcerts:
289 kws['cert_reqs'] = ssl.CERT_REQUIRED
290 return kws
291
292 return kws
293 290
294 def validatesocket(sock, strict=False): 291 def validatesocket(sock, strict=False):
295 """Validate a socket meets security requiremnets. 292 """Validate a socket meets security requiremnets.
296 293
297 The passed socket must have been created with ``wrapsocket()``. 294 The passed socket must have been created with ``wrapsocket()``.