153 return ui.getpass(_('passphrase for %s: ') % f, '') |
153 return ui.getpass(_('passphrase for %s: ') % f, '') |
154 sslcontext.load_cert_chain(certfile, keyfile, password) |
154 sslcontext.load_cert_chain(certfile, keyfile, password) |
155 |
155 |
156 if ca_certs is not None: |
156 if ca_certs is not None: |
157 sslcontext.load_verify_locations(cafile=ca_certs) |
157 sslcontext.load_verify_locations(cafile=ca_certs) |
|
158 caloaded = True |
158 else: |
159 else: |
159 # This is a no-op on old Python. |
160 # This is a no-op on old Python. |
160 sslcontext.load_default_certs() |
161 sslcontext.load_default_certs() |
|
162 caloaded = _canloaddefaultcerts |
161 |
163 |
162 sslsocket = sslcontext.wrap_socket(sock, server_hostname=serverhostname) |
164 sslsocket = sslcontext.wrap_socket(sock, server_hostname=serverhostname) |
163 # check if wrap_socket failed silently because socket had been |
165 # check if wrap_socket failed silently because socket had been |
164 # closed |
166 # closed |
165 # - see http://bugs.python.org/issue13721 |
167 # - see http://bugs.python.org/issue13721 |
166 if not sslsocket.cipher(): |
168 if not sslsocket.cipher(): |
167 raise error.Abort(_('ssl connection failed')) |
169 raise error.Abort(_('ssl connection failed')) |
|
170 |
|
171 sslsocket._hgcaloaded = caloaded |
|
172 |
168 return sslsocket |
173 return sslsocket |
169 |
174 |
170 def _verifycert(cert, hostname): |
175 def _verifycert(cert, hostname): |
171 '''Verify that cert (in socket.getpeercert() format) matches hostname. |
176 '''Verify that cert (in socket.getpeercert() format) matches hostname. |
172 CRLs is not handled. |
177 CRLs is not handled. |
278 # FUTURE this can disappear once wrapsocket() is secure by default. |
283 # FUTURE this can disappear once wrapsocket() is secure by default. |
279 if _canloaddefaultcerts: |
284 if _canloaddefaultcerts: |
280 kws['cert_reqs'] = ssl.CERT_REQUIRED |
285 kws['cert_reqs'] = ssl.CERT_REQUIRED |
281 return kws |
286 return kws |
282 |
287 |
283 # This is effectively indicating that no CAs can be loaded because |
|
284 # we can't get here if web.cacerts is set or if we can find |
|
285 # CA certs elsewhere. Using a config option (which is later |
|
286 # consulted by validator.__call__ is not very obvious). |
|
287 # FUTURE fix this |
|
288 ui.setconfig('web', 'cacerts', '!', 'defaultcacerts') |
|
289 return kws |
288 return kws |
290 |
289 |
291 class validator(object): |
290 class validator(object): |
292 def __init__(self, ui, host): |
291 def __init__(self, ui, host): |
293 self.ui = ui |
292 self.ui = ui |
340 'verified (check hostfingerprints or web.cacerts ' |
339 'verified (check hostfingerprints or web.cacerts ' |
341 'config setting)\n') % |
340 'config setting)\n') % |
342 (host, nicefingerprint)) |
341 (host, nicefingerprint)) |
343 return |
342 return |
344 |
343 |
345 # No pinned fingerprint. Establish trust by looking at the CAs. |
344 if not sock._hgcaloaded: |
346 cacerts = self.ui.config('web', 'cacerts') |
345 if strict: |
347 if cacerts != '!': |
346 raise error.Abort(_('%s certificate with fingerprint %s not ' |
348 msg = _verifycert(peercert2, host) |
347 'verified') % (host, nicefingerprint), |
349 if msg: |
348 hint=_('check hostfingerprints or ' |
350 raise error.Abort(_('%s certificate error: %s') % (host, msg), |
349 'web.cacerts config setting')) |
351 hint=_('configure hostfingerprint %s or use ' |
350 else: |
352 '--insecure to connect insecurely') % |
351 self.ui.warn(_('warning: %s certificate with fingerprint %s ' |
353 nicefingerprint) |
352 'not verified (check hostfingerprints or ' |
354 self.ui.debug('%s certificate successfully verified\n' % host) |
353 'web.cacerts config setting)\n') % |
355 elif strict: |
354 (host, nicefingerprint)) |
356 raise error.Abort(_('%s certificate with fingerprint %s not ' |
355 |
357 'verified') % (host, nicefingerprint), |
356 return |
358 hint=_('check hostfingerprints or web.cacerts ' |
357 |
359 'config setting')) |
358 msg = _verifycert(peercert2, host) |
360 else: |
359 if msg: |
361 self.ui.warn(_('warning: %s certificate with fingerprint %s not ' |
360 raise error.Abort(_('%s certificate error: %s') % (host, msg), |
362 'verified (check hostfingerprints or web.cacerts ' |
361 hint=_('configure hostfingerprint %s or use ' |
363 'config setting)\n') % |
362 '--insecure to connect insecurely') % |
364 (host, nicefingerprint)) |
363 nicefingerprint) |