Mercurial > hg
comparison mercurial/sslutil.py @ 29227:dffe78d80a6c
sslutil: convert socket validation from a class to a function (API)
Now that the socket validator doesn't have any instance state,
we can make it a generic function.
The "validator" class has been converted into the "validatesocket"
function and all consumers have been updated.
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Sun, 15 May 2016 11:38:38 -0700 |
parents | 33006bd6a1d7 |
children | 9b07017ba528 |
comparison
equal
deleted
inserted
replaced
29226:33006bd6a1d7 | 29227:dffe78d80a6c |
---|---|
289 kws['cert_reqs'] = ssl.CERT_REQUIRED | 289 kws['cert_reqs'] = ssl.CERT_REQUIRED |
290 return kws | 290 return kws |
291 | 291 |
292 return kws | 292 return kws |
293 | 293 |
294 class validator(object): | 294 def validatesocket(sock, strict=False): |
295 def __init__(self, ui=None, host=None): | 295 """Validate a socket meets security requiremnets. |
296 pass | 296 |
297 | 297 The passed socket must have been created with ``wrapsocket()``. |
298 def __call__(self, sock, strict=False): | 298 """ |
299 host = sock._hgstate['hostname'] | 299 host = sock._hgstate['hostname'] |
300 ui = sock._hgstate['ui'] | 300 ui = sock._hgstate['ui'] |
301 | 301 |
302 if not sock.cipher(): # work around http://bugs.python.org/issue13721 | 302 if not sock.cipher(): # work around http://bugs.python.org/issue13721 |
303 raise error.Abort(_('%s ssl connection error') % host) | 303 raise error.Abort(_('%s ssl connection error') % host) |
304 try: | 304 try: |
305 peercert = sock.getpeercert(True) | 305 peercert = sock.getpeercert(True) |
306 peercert2 = sock.getpeercert() | 306 peercert2 = sock.getpeercert() |
307 except AttributeError: | 307 except AttributeError: |
308 raise error.Abort(_('%s ssl connection error') % host) | 308 raise error.Abort(_('%s ssl connection error') % host) |
309 | 309 |
310 if not peercert: | 310 if not peercert: |
311 raise error.Abort(_('%s certificate error: ' | 311 raise error.Abort(_('%s certificate error: ' |
312 'no certificate received') % host) | 312 'no certificate received') % host) |
313 | 313 |
314 # If a certificate fingerprint is pinned, use it and only it to | 314 # If a certificate fingerprint is pinned, use it and only it to |
315 # validate the remote cert. | 315 # validate the remote cert. |
316 hostfingerprints = ui.configlist('hostfingerprints', host) | 316 hostfingerprints = ui.configlist('hostfingerprints', host) |
317 peerfingerprint = util.sha1(peercert).hexdigest() | 317 peerfingerprint = util.sha1(peercert).hexdigest() |
318 nicefingerprint = ":".join([peerfingerprint[x:x + 2] | 318 nicefingerprint = ":".join([peerfingerprint[x:x + 2] |
319 for x in xrange(0, len(peerfingerprint), 2)]) | 319 for x in xrange(0, len(peerfingerprint), 2)]) |
320 if hostfingerprints: | 320 if hostfingerprints: |
321 fingerprintmatch = False | 321 fingerprintmatch = False |
322 for hostfingerprint in hostfingerprints: | 322 for hostfingerprint in hostfingerprints: |
323 if peerfingerprint.lower() == \ | 323 if peerfingerprint.lower() == \ |
324 hostfingerprint.replace(':', '').lower(): | 324 hostfingerprint.replace(':', '').lower(): |
325 fingerprintmatch = True | 325 fingerprintmatch = True |
326 break | 326 break |
327 if not fingerprintmatch: | 327 if not fingerprintmatch: |
328 raise error.Abort(_('certificate for %s has unexpected ' | 328 raise error.Abort(_('certificate for %s has unexpected ' |
329 'fingerprint %s') % (host, nicefingerprint), | 329 'fingerprint %s') % (host, nicefingerprint), |
330 hint=_('check hostfingerprint configuration')) | 330 hint=_('check hostfingerprint configuration')) |
331 ui.debug('%s certificate matched fingerprint %s\n' % | 331 ui.debug('%s certificate matched fingerprint %s\n' % |
332 (host, nicefingerprint)) | 332 (host, nicefingerprint)) |
333 return | 333 return |
334 | 334 |
335 # If insecure connections were explicitly requested via --insecure, | 335 # If insecure connections were explicitly requested via --insecure, |
336 # print a warning and do no verification. | 336 # print a warning and do no verification. |
337 # | 337 # |
338 # It may seem odd that this is checked *after* host fingerprint pinning. | 338 # It may seem odd that this is checked *after* host fingerprint pinning. |
339 # This is for backwards compatibility (for now). The message is also | 339 # This is for backwards compatibility (for now). The message is also |
340 # the same as below for BC. | 340 # the same as below for BC. |
341 if ui.insecureconnections: | 341 if ui.insecureconnections: |
342 ui.warn(_('warning: %s certificate with fingerprint %s not ' | 342 ui.warn(_('warning: %s certificate with fingerprint %s not ' |
343 'verified (check hostfingerprints or web.cacerts ' | 343 'verified (check hostfingerprints or web.cacerts ' |
344 'config setting)\n') % | 344 'config setting)\n') % |
345 (host, nicefingerprint)) | |
346 return | |
347 | |
348 if not sock._hgstate['caloaded']: | |
349 if strict: | |
350 raise error.Abort(_('%s certificate with fingerprint %s not ' | |
351 'verified') % (host, nicefingerprint), | |
352 hint=_('check hostfingerprints or ' | |
353 'web.cacerts config setting')) | |
354 else: | |
355 ui.warn(_('warning: %s certificate with fingerprint %s ' | |
356 'not verified (check hostfingerprints or ' | |
357 'web.cacerts config setting)\n') % | |
345 (host, nicefingerprint)) | 358 (host, nicefingerprint)) |
346 return | 359 |
347 | 360 return |
348 if not sock._hgstate['caloaded']: | 361 |
349 if strict: | 362 msg = _verifycert(peercert2, host) |
350 raise error.Abort(_('%s certificate with fingerprint %s not ' | 363 if msg: |
351 'verified') % (host, nicefingerprint), | 364 raise error.Abort(_('%s certificate error: %s') % (host, msg), |
352 hint=_('check hostfingerprints or ' | 365 hint=_('configure hostfingerprint %s or use ' |
353 'web.cacerts config setting')) | 366 '--insecure to connect insecurely') % |
354 else: | 367 nicefingerprint) |
355 ui.warn(_('warning: %s certificate with fingerprint %s ' | |
356 'not verified (check hostfingerprints or ' | |
357 'web.cacerts config setting)\n') % | |
358 (host, nicefingerprint)) | |
359 | |
360 return | |
361 | |
362 msg = _verifycert(peercert2, host) | |
363 if msg: | |
364 raise error.Abort(_('%s certificate error: %s') % (host, msg), | |
365 hint=_('configure hostfingerprint %s or use ' | |
366 '--insecure to connect insecurely') % | |
367 nicefingerprint) |