comparison mercurial/sslutil.py @ 28850:3819c349b194

sslutil: document and slightly refactor validation logic This main purpose of this patch is to make it clearer that fingerprint pinning takes precedence over CA verification. This will make subsequent refactoring to the validation code easier to read.
author Gregory Szorc <gregory.szorc@gmail.com>
date Sun, 10 Apr 2016 11:02:58 -0700
parents 1fde84d42f9c
children 693b856a4d45
comparison
equal deleted inserted replaced
28849:1fde84d42f9c 28850:3819c349b194
262 self.ui = ui 262 self.ui = ui
263 self.host = host 263 self.host = host
264 264
265 def __call__(self, sock, strict=False): 265 def __call__(self, sock, strict=False):
266 host = self.host 266 host = self.host
267 cacerts = self.ui.config('web', 'cacerts')
268 hostfingerprints = self.ui.configlist('hostfingerprints', host)
269 267
270 if not sock.cipher(): # work around http://bugs.python.org/issue13721 268 if not sock.cipher(): # work around http://bugs.python.org/issue13721
271 raise error.Abort(_('%s ssl connection error') % host) 269 raise error.Abort(_('%s ssl connection error') % host)
272 try: 270 try:
273 peercert = sock.getpeercert(True) 271 peercert = sock.getpeercert(True)
276 raise error.Abort(_('%s ssl connection error') % host) 274 raise error.Abort(_('%s ssl connection error') % host)
277 275
278 if not peercert: 276 if not peercert:
279 raise error.Abort(_('%s certificate error: ' 277 raise error.Abort(_('%s certificate error: '
280 'no certificate received') % host) 278 'no certificate received') % host)
279
280 # If a certificate fingerprint is pinned, use it and only it to
281 # validate the remote cert.
282 hostfingerprints = self.ui.configlist('hostfingerprints', host)
281 peerfingerprint = util.sha1(peercert).hexdigest() 283 peerfingerprint = util.sha1(peercert).hexdigest()
282 nicefingerprint = ":".join([peerfingerprint[x:x + 2] 284 nicefingerprint = ":".join([peerfingerprint[x:x + 2]
283 for x in xrange(0, len(peerfingerprint), 2)]) 285 for x in xrange(0, len(peerfingerprint), 2)])
284 if hostfingerprints: 286 if hostfingerprints:
285 fingerprintmatch = False 287 fingerprintmatch = False
292 raise error.Abort(_('certificate for %s has unexpected ' 294 raise error.Abort(_('certificate for %s has unexpected '
293 'fingerprint %s') % (host, nicefingerprint), 295 'fingerprint %s') % (host, nicefingerprint),
294 hint=_('check hostfingerprint configuration')) 296 hint=_('check hostfingerprint configuration'))
295 self.ui.debug('%s certificate matched fingerprint %s\n' % 297 self.ui.debug('%s certificate matched fingerprint %s\n' %
296 (host, nicefingerprint)) 298 (host, nicefingerprint))
297 elif cacerts != '!': 299 return
300
301 # No pinned fingerprint. Establish trust by looking at the CAs.
302 cacerts = self.ui.config('web', 'cacerts')
303 if cacerts != '!':
298 msg = _verifycert(peercert2, host) 304 msg = _verifycert(peercert2, host)
299 if msg: 305 if msg:
300 raise error.Abort(_('%s certificate error: %s') % (host, msg), 306 raise error.Abort(_('%s certificate error: %s') % (host, msg),
301 hint=_('configure hostfingerprint %s or use ' 307 hint=_('configure hostfingerprint %s or use '
302 '--insecure to connect insecurely') % 308 '--insecure to connect insecurely') %