288 return kws |
290 return kws |
289 |
291 |
290 return kws |
292 return kws |
291 |
293 |
292 class validator(object): |
294 class validator(object): |
293 def __init__(self, ui, host): |
295 def __init__(self, ui=None, host=None): |
294 self.ui = ui |
296 pass |
295 self.host = host |
|
296 |
297 |
297 def __call__(self, sock, strict=False): |
298 def __call__(self, sock, strict=False): |
298 host = self.host |
299 host = sock._hgstate['hostname'] |
|
300 ui = sock._hgstate['ui'] |
299 |
301 |
300 if not sock.cipher(): # work around http://bugs.python.org/issue13721 |
302 if not sock.cipher(): # work around http://bugs.python.org/issue13721 |
301 raise error.Abort(_('%s ssl connection error') % host) |
303 raise error.Abort(_('%s ssl connection error') % host) |
302 try: |
304 try: |
303 peercert = sock.getpeercert(True) |
305 peercert = sock.getpeercert(True) |
309 raise error.Abort(_('%s certificate error: ' |
311 raise error.Abort(_('%s certificate error: ' |
310 'no certificate received') % host) |
312 'no certificate received') % host) |
311 |
313 |
312 # 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 |
313 # validate the remote cert. |
315 # validate the remote cert. |
314 hostfingerprints = self.ui.configlist('hostfingerprints', host) |
316 hostfingerprints = ui.configlist('hostfingerprints', host) |
315 peerfingerprint = util.sha1(peercert).hexdigest() |
317 peerfingerprint = util.sha1(peercert).hexdigest() |
316 nicefingerprint = ":".join([peerfingerprint[x:x + 2] |
318 nicefingerprint = ":".join([peerfingerprint[x:x + 2] |
317 for x in xrange(0, len(peerfingerprint), 2)]) |
319 for x in xrange(0, len(peerfingerprint), 2)]) |
318 if hostfingerprints: |
320 if hostfingerprints: |
319 fingerprintmatch = False |
321 fingerprintmatch = False |
324 break |
326 break |
325 if not fingerprintmatch: |
327 if not fingerprintmatch: |
326 raise error.Abort(_('certificate for %s has unexpected ' |
328 raise error.Abort(_('certificate for %s has unexpected ' |
327 'fingerprint %s') % (host, nicefingerprint), |
329 'fingerprint %s') % (host, nicefingerprint), |
328 hint=_('check hostfingerprint configuration')) |
330 hint=_('check hostfingerprint configuration')) |
329 self.ui.debug('%s certificate matched fingerprint %s\n' % |
331 ui.debug('%s certificate matched fingerprint %s\n' % |
330 (host, nicefingerprint)) |
332 (host, nicefingerprint)) |
331 return |
333 return |
332 |
334 |
333 # If insecure connections were explicitly requested via --insecure, |
335 # If insecure connections were explicitly requested via --insecure, |
334 # print a warning and do no verification. |
336 # print a warning and do no verification. |
335 # |
337 # |
336 # 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. |
337 # This is for backwards compatibility (for now). The message is also |
339 # This is for backwards compatibility (for now). The message is also |
338 # the same as below for BC. |
340 # the same as below for BC. |
339 if self.ui.insecureconnections: |
341 if ui.insecureconnections: |
340 self.ui.warn(_('warning: %s certificate with fingerprint %s not ' |
342 ui.warn(_('warning: %s certificate with fingerprint %s not ' |
341 'verified (check hostfingerprints or web.cacerts ' |
343 'verified (check hostfingerprints or web.cacerts ' |
342 'config setting)\n') % |
344 'config setting)\n') % |
343 (host, nicefingerprint)) |
345 (host, nicefingerprint)) |
344 return |
346 return |
345 |
347 |
346 if not sock._hgstate['caloaded']: |
348 if not sock._hgstate['caloaded']: |
347 if strict: |
349 if strict: |
348 raise error.Abort(_('%s certificate with fingerprint %s not ' |
350 raise error.Abort(_('%s certificate with fingerprint %s not ' |
349 'verified') % (host, nicefingerprint), |
351 'verified') % (host, nicefingerprint), |
350 hint=_('check hostfingerprints or ' |
352 hint=_('check hostfingerprints or ' |
351 'web.cacerts config setting')) |
353 'web.cacerts config setting')) |
352 else: |
354 else: |
353 self.ui.warn(_('warning: %s certificate with fingerprint %s ' |
355 ui.warn(_('warning: %s certificate with fingerprint %s ' |
354 'not verified (check hostfingerprints or ' |
356 'not verified (check hostfingerprints or ' |
355 'web.cacerts config setting)\n') % |
357 'web.cacerts config setting)\n') % |
356 (host, nicefingerprint)) |
358 (host, nicefingerprint)) |
357 |
359 |
358 return |
360 return |
359 |
361 |
360 msg = _verifycert(peercert2, host) |
362 msg = _verifycert(peercert2, host) |
361 if msg: |
363 if msg: |