[PATCH 2 of 2] url: debug print ssl certificate if connection failed
Yuya Nishihara
yuya at tcha.org
Sat Jan 8 07:08:26 CST 2011
# HG changeset patch
# User Yuya Nishihara <yuya at tcha.org>
# Date 1294491295 -32400
# Branch stable
# Node ID e541b8d268395ece35aff45f8116c6041d22d91f
# Parent 160f24a7970a402d0f7df1912b92419d7acbd8f3
url: debug print ssl certificate if connection failed
If a server provides self-signed certificate, ssl.wrap_socket raises exception
like "routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed".
As of Python 2.6 or 2.7, it doesn't provide a legitimate way to decode
certificate to human-readable text without established ssl socket.
So _printservercert() tries to use _ssl._test_decode_cert(), which is available
at least on Python 2.6.6 or 2.7.1.
diff --git a/mercurial/url.py b/mercurial/url.py
--- a/mercurial/url.py
+++ b/mercurial/url.py
@@ -290,8 +290,11 @@ if has_https:
import ssl
_ssl_wrap_socket = ssl.wrap_socket
CERT_REQUIRED = ssl.CERT_REQUIRED
+ SSLError = ssl.SSLError
except ImportError:
CERT_REQUIRED = 2
+ class SSLError(Exception):
+ pass
def _ssl_wrap_socket(sock, key_file, cert_file,
cert_reqs=CERT_REQUIRED, ca_certs=None):
@@ -521,6 +524,27 @@ def _printcert(cert, write):
for key, value in cert.get('subjectAltName', []):
write(' subjectAltName.%s: %s\n' % (key, value))
+def _printservercert(addr, write):
+ """Fetch server certificate and print human-readable details"""
+ import tempfile
+ try: # needs Python 2.6
+ import ssl, _ssl
+ decode_certfile = _ssl._test_decode_cert
+ except (ImportError, AttributeError):
+ return
+ der = ssl.get_server_certificate(addr)
+ if not der:
+ return
+ fh, fn = tempfile.mkstemp(prefix='hg-servercert-')
+ try:
+ f = os.fdopen(fh, 'w')
+ f.write(der)
+ f.close()
+ cert = decode_certfile(fn)
+ finally:
+ os.unlink(fn)
+ _printcert(cert, write)
+
if has_https:
class BetterHTTPS(httplib.HTTPSConnection):
send = keepalive.safesend
@@ -535,9 +559,15 @@ if has_https:
if cacerts:
sock = _create_connection((self.host, self.port))
- self.sock = _ssl_wrap_socket(sock, self.key_file,
- self.cert_file, cert_reqs=CERT_REQUIRED,
- ca_certs=cacerts)
+ try:
+ self.sock = _ssl_wrap_socket(sock, self.key_file,
+ self.cert_file, cert_reqs=CERT_REQUIRED,
+ ca_certs=cacerts)
+ except SSLError:
+ if self.ui.debugflag:
+ _printservercert((self.host, self.port),
+ self.ui.debug)
+ raise
msg = _verifycert(self.sock.getpeercert(), self.host)
if msg:
if self.ui.debugflag:
More information about the Mercurial-devel
mailing list