diff -r 14af04391fb9 -r 9a9f95214f46 mercurial/debugcommands.py --- a/mercurial/debugcommands.py Wed Mar 29 23:45:23 2017 -0400 +++ b/mercurial/debugcommands.py Thu Mar 30 00:27:46 2017 -0400 @@ -13,6 +13,7 @@ import os import random import socket +import ssl import string import sys import tempfile @@ -2057,6 +2058,66 @@ with repo.wlock(): repo.setparents(r1, r2) +@command('debugssl', [], '[SOURCE]', optionalrepo=True) +def debugssl(ui, repo, source=None, **opts): + '''test a secure connection to a server + + This builds the certificate chain for the server on Windows, installing the + missing intermediates and trusted root via Windows Update if necessary. It + does nothing on other platforms. + + If SOURCE is omitted, the 'default' path will be used. If a URL is given, + that server is used. See :hg:`help urls` for more information. + + If the update succeeds, retry the original operation. Otherwise, the cause + of the SSL error is likely another issue. + ''' + if pycompat.osname != 'nt': + raise error.Abort(_('Certificate chain building is only possible on ' + 'Windows')) + + if not source: + source = "default" + elif not repo: + raise error.Abort(_("there is no Mercurial repository here, and no " + "server specified")) + + source, branches = hg.parseurl(ui.expandpath(source)) + url = util.url(source) + addr = None + + if url.scheme == 'https': + addr = (url.host, url.port or 443) + elif url.scheme == 'ssh': + addr = (url.host, url.port or 22) + else: + raise error.Abort(_("Only https and ssh connections are supported")) + + from . import win32 + + s = ssl.wrap_socket(socket.socket(), ssl_version=ssl.PROTOCOL_TLS, + cert_reqs=ssl.CERT_NONE, ca_certs=None) + + try: + s.connect(addr) + cert = s.getpeercert(True) + + ui.status(_('Checking the certificate chain for %s.\n') % url.host) + + complete = win32.checkcertificatechain(cert, build=False) + + if not complete: + ui.status(_('The certificate chain is incomplete. Updating... ')) + + if not win32.checkcertificatechain(cert): + ui.status(_('Failed.\n')) + else: + ui.status(_('Done.\n')) + else: + ui.status(_('The full certificate chain is available.\n')) + finally: + s.close() + @command('debugsub', [('r', 'rev', '', _('revision to check'), _('REV'))],