##// END OF EJS Templates
sslutil: show fingerprint when cacerts validation fails
Mads Kiilerich -
r15814:c3e958b5 default
parent child Browse files
Show More
@@ -1,138 +1,139
1 # sslutil.py - SSL handling for mercurial
1 # sslutil.py - SSL handling for mercurial
2 #
2 #
3 # Copyright 2005, 2006, 2007, 2008 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006, 2007, 2008 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006, 2007 Alexis S. L. Carvalho <alexis@cecm.usp.br>
4 # Copyright 2006, 2007 Alexis S. L. Carvalho <alexis@cecm.usp.br>
5 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
6 #
6 #
7 # This software may be used and distributed according to the terms of the
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
8 # GNU General Public License version 2 or any later version.
9 import os
9 import os
10
10
11 from mercurial import util
11 from mercurial import util
12 from mercurial.i18n import _
12 from mercurial.i18n import _
13 try:
13 try:
14 # avoid using deprecated/broken FakeSocket in python 2.6
14 # avoid using deprecated/broken FakeSocket in python 2.6
15 import ssl
15 import ssl
16 CERT_REQUIRED = ssl.CERT_REQUIRED
16 CERT_REQUIRED = ssl.CERT_REQUIRED
17 def ssl_wrap_socket(sock, keyfile, certfile,
17 def ssl_wrap_socket(sock, keyfile, certfile,
18 cert_reqs=ssl.CERT_NONE, ca_certs=None):
18 cert_reqs=ssl.CERT_NONE, ca_certs=None):
19 sslsocket = ssl.wrap_socket(sock, keyfile, certfile,
19 sslsocket = ssl.wrap_socket(sock, keyfile, certfile,
20 cert_reqs=cert_reqs, ca_certs=ca_certs)
20 cert_reqs=cert_reqs, ca_certs=ca_certs)
21 # check if wrap_socket failed silently because socket had been closed
21 # check if wrap_socket failed silently because socket had been closed
22 # - see http://bugs.python.org/issue13721
22 # - see http://bugs.python.org/issue13721
23 if not sslsocket.cipher():
23 if not sslsocket.cipher():
24 raise util.Abort(_('ssl connection failed'))
24 raise util.Abort(_('ssl connection failed'))
25 return sslsocket
25 return sslsocket
26 except ImportError:
26 except ImportError:
27 CERT_REQUIRED = 2
27 CERT_REQUIRED = 2
28
28
29 import socket, httplib
29 import socket, httplib
30
30
31 def ssl_wrap_socket(sock, key_file, cert_file,
31 def ssl_wrap_socket(sock, key_file, cert_file,
32 cert_reqs=CERT_REQUIRED, ca_certs=None):
32 cert_reqs=CERT_REQUIRED, ca_certs=None):
33 if not util.safehasattr(socket, 'ssl'):
33 if not util.safehasattr(socket, 'ssl'):
34 raise util.Abort(_('Python SSL support not found'))
34 raise util.Abort(_('Python SSL support not found'))
35 if ca_certs:
35 if ca_certs:
36 raise util.Abort(_(
36 raise util.Abort(_(
37 'certificate checking requires Python 2.6'))
37 'certificate checking requires Python 2.6'))
38
38
39 ssl = socket.ssl(sock, key_file, cert_file)
39 ssl = socket.ssl(sock, key_file, cert_file)
40 return httplib.FakeSocket(sock, ssl)
40 return httplib.FakeSocket(sock, ssl)
41
41
42 def _verifycert(cert, hostname):
42 def _verifycert(cert, hostname):
43 '''Verify that cert (in socket.getpeercert() format) matches hostname.
43 '''Verify that cert (in socket.getpeercert() format) matches hostname.
44 CRLs is not handled.
44 CRLs is not handled.
45
45
46 Returns error message if any problems are found and None on success.
46 Returns error message if any problems are found and None on success.
47 '''
47 '''
48 if not cert:
48 if not cert:
49 return _('no certificate received')
49 return _('no certificate received')
50 dnsname = hostname.lower()
50 dnsname = hostname.lower()
51 def matchdnsname(certname):
51 def matchdnsname(certname):
52 return (certname == dnsname or
52 return (certname == dnsname or
53 '.' in dnsname and certname == '*.' + dnsname.split('.', 1)[1])
53 '.' in dnsname and certname == '*.' + dnsname.split('.', 1)[1])
54
54
55 san = cert.get('subjectAltName', [])
55 san = cert.get('subjectAltName', [])
56 if san:
56 if san:
57 certnames = [value.lower() for key, value in san if key == 'DNS']
57 certnames = [value.lower() for key, value in san if key == 'DNS']
58 for name in certnames:
58 for name in certnames:
59 if matchdnsname(name):
59 if matchdnsname(name):
60 return None
60 return None
61 if certnames:
61 if certnames:
62 return _('certificate is for %s') % ', '.join(certnames)
62 return _('certificate is for %s') % ', '.join(certnames)
63
63
64 # subject is only checked when subjectAltName is empty
64 # subject is only checked when subjectAltName is empty
65 for s in cert.get('subject', []):
65 for s in cert.get('subject', []):
66 key, value = s[0]
66 key, value = s[0]
67 if key == 'commonName':
67 if key == 'commonName':
68 try:
68 try:
69 # 'subject' entries are unicode
69 # 'subject' entries are unicode
70 certname = value.lower().encode('ascii')
70 certname = value.lower().encode('ascii')
71 except UnicodeEncodeError:
71 except UnicodeEncodeError:
72 return _('IDN in certificate not supported')
72 return _('IDN in certificate not supported')
73 if matchdnsname(certname):
73 if matchdnsname(certname):
74 return None
74 return None
75 return _('certificate is for %s') % certname
75 return _('certificate is for %s') % certname
76 return _('no commonName or subjectAltName found in certificate')
76 return _('no commonName or subjectAltName found in certificate')
77
77
78
78
79 # CERT_REQUIRED means fetch the cert from the server all the time AND
79 # CERT_REQUIRED means fetch the cert from the server all the time AND
80 # validate it against the CA store provided in web.cacerts.
80 # validate it against the CA store provided in web.cacerts.
81 #
81 #
82 # We COMPLETELY ignore CERT_REQUIRED on Python <= 2.5, as it's totally
82 # We COMPLETELY ignore CERT_REQUIRED on Python <= 2.5, as it's totally
83 # busted on those versions.
83 # busted on those versions.
84
84
85 def sslkwargs(ui, host):
85 def sslkwargs(ui, host):
86 cacerts = ui.config('web', 'cacerts')
86 cacerts = ui.config('web', 'cacerts')
87 hostfingerprint = ui.config('hostfingerprints', host)
87 hostfingerprint = ui.config('hostfingerprints', host)
88 if cacerts and not hostfingerprint:
88 if cacerts and not hostfingerprint:
89 cacerts = util.expandpath(cacerts)
89 cacerts = util.expandpath(cacerts)
90 if not os.path.exists(cacerts):
90 if not os.path.exists(cacerts):
91 raise util.Abort(_('could not find web.cacerts: %s') % cacerts)
91 raise util.Abort(_('could not find web.cacerts: %s') % cacerts)
92 return {'ca_certs': cacerts,
92 return {'ca_certs': cacerts,
93 'cert_reqs': CERT_REQUIRED,
93 'cert_reqs': CERT_REQUIRED,
94 }
94 }
95 return {}
95 return {}
96
96
97 class validator(object):
97 class validator(object):
98 def __init__(self, ui, host):
98 def __init__(self, ui, host):
99 self.ui = ui
99 self.ui = ui
100 self.host = host
100 self.host = host
101
101
102 def __call__(self, sock):
102 def __call__(self, sock):
103 host = self.host
103 host = self.host
104 cacerts = self.ui.config('web', 'cacerts')
104 cacerts = self.ui.config('web', 'cacerts')
105 hostfingerprint = self.ui.config('hostfingerprints', host)
105 hostfingerprint = self.ui.config('hostfingerprints', host)
106 if not getattr(sock, 'getpeercert', False): # python 2.5 ?
106 if not getattr(sock, 'getpeercert', False): # python 2.5 ?
107 if hostfingerprint:
107 if hostfingerprint:
108 raise util.Abort(_("host fingerprint for %s can't be "
108 raise util.Abort(_("host fingerprint for %s can't be "
109 "verified (Python too old)") % host)
109 "verified (Python too old)") % host)
110 self.ui.warn(_("warning: certificate for %s can't be verified "
110 self.ui.warn(_("warning: certificate for %s can't be verified "
111 "(Python too old)\n") % host)
111 "(Python too old)\n") % host)
112 return
112 return
113 if cacerts and not hostfingerprint:
114 msg = _verifycert(sock.getpeercert(), host)
115 if msg:
116 raise util.Abort(_('%s certificate error: %s '
117 '(use --insecure to connect '
118 'insecurely)') % (host, msg))
119 self.ui.debug('%s certificate successfully verified\n' % host)
120 else:
121 peercert = sock.getpeercert(True)
113 peercert = sock.getpeercert(True)
122 peerfingerprint = util.sha1(peercert).hexdigest()
114 peerfingerprint = util.sha1(peercert).hexdigest()
123 nicefingerprint = ":".join([peerfingerprint[x:x + 2]
115 nicefingerprint = ":".join([peerfingerprint[x:x + 2]
124 for x in xrange(0, len(peerfingerprint), 2)])
116 for x in xrange(0, len(peerfingerprint), 2)])
117 if cacerts and not hostfingerprint:
118 msg = _verifycert(sock.getpeercert(), host)
119 if msg:
120 raise util.Abort(_('%s certificate error: %s') % (host, msg),
121 hint=_('configure hostfingerprint %s or use '
122 '--insecure to connect insecurely') %
123 nicefingerprint)
124 self.ui.debug('%s certificate successfully verified\n' % host)
125 else:
125 if hostfingerprint:
126 if hostfingerprint:
126 if peerfingerprint.lower() != \
127 if peerfingerprint.lower() != \
127 hostfingerprint.replace(':', '').lower():
128 hostfingerprint.replace(':', '').lower():
128 raise util.Abort(_('invalid certificate for %s '
129 raise util.Abort(_('invalid certificate for %s '
129 'with fingerprint %s') %
130 'with fingerprint %s') %
130 (host, nicefingerprint))
131 (host, nicefingerprint))
131 self.ui.debug('%s certificate matched fingerprint %s\n' %
132 self.ui.debug('%s certificate matched fingerprint %s\n' %
132 (host, nicefingerprint))
133 (host, nicefingerprint))
133 else:
134 else:
134 self.ui.warn(_('warning: %s certificate '
135 self.ui.warn(_('warning: %s certificate '
135 'with fingerprint %s not verified '
136 'with fingerprint %s not verified '
136 '(check hostfingerprints or web.cacerts '
137 '(check hostfingerprints or web.cacerts '
137 'config setting)\n') %
138 'config setting)\n') %
138 (host, nicefingerprint))
139 (host, nicefingerprint))
@@ -1,275 +1,276
1 Proper https client requires the built-in ssl from Python 2.6.
1 Proper https client requires the built-in ssl from Python 2.6.
2
2
3 $ "$TESTDIR/hghave" serve ssl || exit 80
3 $ "$TESTDIR/hghave" serve ssl || exit 80
4
4
5 Certificates created with:
5 Certificates created with:
6 printf '.\n.\n.\n.\n.\nlocalhost\nhg@localhost\n' | \
6 printf '.\n.\n.\n.\n.\nlocalhost\nhg@localhost\n' | \
7 openssl req -newkey rsa:512 -keyout priv.pem -nodes -x509 -days 9000 -out pub.pem
7 openssl req -newkey rsa:512 -keyout priv.pem -nodes -x509 -days 9000 -out pub.pem
8 Can be dumped with:
8 Can be dumped with:
9 openssl x509 -in pub.pem -text
9 openssl x509 -in pub.pem -text
10
10
11 $ cat << EOT > priv.pem
11 $ cat << EOT > priv.pem
12 > -----BEGIN PRIVATE KEY-----
12 > -----BEGIN PRIVATE KEY-----
13 > MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEApjCWeYGrIa/Vo7LH
13 > MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEApjCWeYGrIa/Vo7LH
14 > aRF8ou0tbgHKE33Use/whCnKEUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8
14 > aRF8ou0tbgHKE33Use/whCnKEUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8
15 > j/xgSwIDAQABAkBxHC6+Qlf0VJXGlb6NL16yEVVTQxqDS6hA9zqu6TZjrr0YMfzc
15 > j/xgSwIDAQABAkBxHC6+Qlf0VJXGlb6NL16yEVVTQxqDS6hA9zqu6TZjrr0YMfzc
16 > EGNIiZGt7HCBL0zO+cPDg/LeCZc6HQhf0KrhAiEAzlJq4hWWzvguWFIJWSoBeBUG
16 > EGNIiZGt7HCBL0zO+cPDg/LeCZc6HQhf0KrhAiEAzlJq4hWWzvguWFIJWSoBeBUG
17 > MF1ACazQO7PYE8M0qfECIQDONHHP0SKZzz/ZwBZcAveC5K61f/v9hONFwbeYulzR
17 > MF1ACazQO7PYE8M0qfECIQDONHHP0SKZzz/ZwBZcAveC5K61f/v9hONFwbeYulzR
18 > +wIgc9SvbtgB/5Yzpp//4ZAEnR7oh5SClCvyB+KSx52K3nECICbhQphhoXmI10wy
18 > +wIgc9SvbtgB/5Yzpp//4ZAEnR7oh5SClCvyB+KSx52K3nECICbhQphhoXmI10wy
19 > aMTellaq0bpNMHFDziqH9RsqAHhjAiEAgYGxfzkftt5IUUn/iFK89aaIpyrpuaAh
19 > aMTellaq0bpNMHFDziqH9RsqAHhjAiEAgYGxfzkftt5IUUn/iFK89aaIpyrpuaAh
20 > HY8gUVkVRVs=
20 > HY8gUVkVRVs=
21 > -----END PRIVATE KEY-----
21 > -----END PRIVATE KEY-----
22 > EOT
22 > EOT
23
23
24 $ cat << EOT > pub.pem
24 $ cat << EOT > pub.pem
25 > -----BEGIN CERTIFICATE-----
25 > -----BEGIN CERTIFICATE-----
26 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNV
26 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNV
27 > BAMMCWxvY2FsaG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEw
27 > BAMMCWxvY2FsaG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEw
28 > MTAxNDIwMzAxNFoXDTM1MDYwNTIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0
28 > MTAxNDIwMzAxNFoXDTM1MDYwNTIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0
29 > MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhvc3QwXDANBgkqhkiG9w0BAQEFAANL
29 > MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhvc3QwXDANBgkqhkiG9w0BAQEFAANL
30 > ADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnKEUm34rDaXQd4lxxX
30 > ADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnKEUm34rDaXQd4lxxX
31 > 6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA+amm
31 > 6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA+amm
32 > r24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQw
32 > r24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQw
33 > DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAFArvQFiAZJgQczRsbYlG1xl
33 > DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAFArvQFiAZJgQczRsbYlG1xl
34 > t+truk37w5B3m3Ick1ntRcQrqs+hf0CO1q6Squ144geYaQ8CDirSR92fICELI1c=
34 > t+truk37w5B3m3Ick1ntRcQrqs+hf0CO1q6Squ144geYaQ8CDirSR92fICELI1c=
35 > -----END CERTIFICATE-----
35 > -----END CERTIFICATE-----
36 > EOT
36 > EOT
37 $ cat priv.pem pub.pem >> server.pem
37 $ cat priv.pem pub.pem >> server.pem
38 $ PRIV=`pwd`/server.pem
38 $ PRIV=`pwd`/server.pem
39
39
40 $ cat << EOT > pub-other.pem
40 $ cat << EOT > pub-other.pem
41 > -----BEGIN CERTIFICATE-----
41 > -----BEGIN CERTIFICATE-----
42 > MIIBqzCCAVWgAwIBAgIJALwZS731c/ORMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNV
42 > MIIBqzCCAVWgAwIBAgIJALwZS731c/ORMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNV
43 > BAMMCWxvY2FsaG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEw
43 > BAMMCWxvY2FsaG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEw
44 > MTAxNDIwNDUxNloXDTM1MDYwNTIwNDUxNlowMTESMBAGA1UEAwwJbG9jYWxob3N0
44 > MTAxNDIwNDUxNloXDTM1MDYwNTIwNDUxNlowMTESMBAGA1UEAwwJbG9jYWxob3N0
45 > MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhvc3QwXDANBgkqhkiG9w0BAQEFAANL
45 > MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhvc3QwXDANBgkqhkiG9w0BAQEFAANL
46 > ADBIAkEAsxsapLbHrqqUKuQBxdpK4G3m2LjtyrTSdpzzzFlecxd5yhNP6AyWrufo
46 > ADBIAkEAsxsapLbHrqqUKuQBxdpK4G3m2LjtyrTSdpzzzFlecxd5yhNP6AyWrufo
47 > K4VMGo2xlu9xOo88nDSUNSKPuD09MwIDAQABo1AwTjAdBgNVHQ4EFgQUoIB1iMhN
47 > K4VMGo2xlu9xOo88nDSUNSKPuD09MwIDAQABo1AwTjAdBgNVHQ4EFgQUoIB1iMhN
48 > y868rpQ2qk9dHnU6ebswHwYDVR0jBBgwFoAUoIB1iMhNy868rpQ2qk9dHnU6ebsw
48 > y868rpQ2qk9dHnU6ebswHwYDVR0jBBgwFoAUoIB1iMhNy868rpQ2qk9dHnU6ebsw
49 > DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJ544f125CsE7J2t55PdFaF6
49 > DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJ544f125CsE7J2t55PdFaF6
50 > bBlNBb91FCywBgSjhBjf+GG3TNPwrPdc3yqeq+hzJiuInqbOBv9abmMyq8Wsoig=
50 > bBlNBb91FCywBgSjhBjf+GG3TNPwrPdc3yqeq+hzJiuInqbOBv9abmMyq8Wsoig=
51 > -----END CERTIFICATE-----
51 > -----END CERTIFICATE-----
52 > EOT
52 > EOT
53
53
54 pub.pem patched with other notBefore / notAfter:
54 pub.pem patched with other notBefore / notAfter:
55
55
56 $ cat << EOT > pub-not-yet.pem
56 $ cat << EOT > pub-not-yet.pem
57 > -----BEGIN CERTIFICATE-----
57 > -----BEGIN CERTIFICATE-----
58 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNVBAMMCWxvY2Fs
58 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNVBAMMCWxvY2Fs
59 > aG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTM1MDYwNTIwMzAxNFoXDTM1MDYw
59 > aG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTM1MDYwNTIwMzAxNFoXDTM1MDYw
60 > NTIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhv
60 > NTIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhv
61 > c3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnK
61 > c3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnK
62 > EUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA
62 > EUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA
63 > +ammr24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQwDAYDVR0T
63 > +ammr24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQwDAYDVR0T
64 > BAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJXV41gWnkgC7jcpPpFRSUSZaxyzrXmD1CIqQf0WgVDb
64 > BAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJXV41gWnkgC7jcpPpFRSUSZaxyzrXmD1CIqQf0WgVDb
65 > /12E0vR2DuZitgzUYtBaofM81aTtc0a2/YsrmqePGm0=
65 > /12E0vR2DuZitgzUYtBaofM81aTtc0a2/YsrmqePGm0=
66 > -----END CERTIFICATE-----
66 > -----END CERTIFICATE-----
67 > EOT
67 > EOT
68 $ cat priv.pem pub-not-yet.pem > server-not-yet.pem
68 $ cat priv.pem pub-not-yet.pem > server-not-yet.pem
69
69
70 $ cat << EOT > pub-expired.pem
70 $ cat << EOT > pub-expired.pem
71 > -----BEGIN CERTIFICATE-----
71 > -----BEGIN CERTIFICATE-----
72 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNVBAMMCWxvY2Fs
72 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNVBAMMCWxvY2Fs
73 > aG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEwMTAxNDIwMzAxNFoXDTEwMTAx
73 > aG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEwMTAxNDIwMzAxNFoXDTEwMTAx
74 > NDIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhv
74 > NDIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhv
75 > c3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnK
75 > c3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnK
76 > EUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA
76 > EUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA
77 > +ammr24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQwDAYDVR0T
77 > +ammr24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQwDAYDVR0T
78 > BAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJfk57DTRf2nUbYaMSlVAARxMNbFGOjQhAUtY400GhKt
78 > BAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJfk57DTRf2nUbYaMSlVAARxMNbFGOjQhAUtY400GhKt
79 > 2uiKCNGKXVXD3AHWe13yHc5KttzbHQStE5Nm/DlWBWQ=
79 > 2uiKCNGKXVXD3AHWe13yHc5KttzbHQStE5Nm/DlWBWQ=
80 > -----END CERTIFICATE-----
80 > -----END CERTIFICATE-----
81 > EOT
81 > EOT
82 $ cat priv.pem pub-expired.pem > server-expired.pem
82 $ cat priv.pem pub-expired.pem > server-expired.pem
83
83
84 $ hg init test
84 $ hg init test
85 $ cd test
85 $ cd test
86 $ echo foo>foo
86 $ echo foo>foo
87 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
87 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
88 $ echo foo>foo.d/foo
88 $ echo foo>foo.d/foo
89 $ echo bar>foo.d/bAr.hg.d/BaR
89 $ echo bar>foo.d/bAr.hg.d/BaR
90 $ echo bar>foo.d/baR.d.hg/bAR
90 $ echo bar>foo.d/baR.d.hg/bAR
91 $ hg commit -A -m 1
91 $ hg commit -A -m 1
92 adding foo
92 adding foo
93 adding foo.d/bAr.hg.d/BaR
93 adding foo.d/bAr.hg.d/BaR
94 adding foo.d/baR.d.hg/bAR
94 adding foo.d/baR.d.hg/bAR
95 adding foo.d/foo
95 adding foo.d/foo
96 $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV
96 $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV
97 $ cat ../hg0.pid >> $DAEMON_PIDS
97 $ cat ../hg0.pid >> $DAEMON_PIDS
98
98
99 cacert not found
99 cacert not found
100
100
101 $ hg in --config web.cacerts=no-such.pem https://localhost:$HGPORT/
101 $ hg in --config web.cacerts=no-such.pem https://localhost:$HGPORT/
102 abort: could not find web.cacerts: no-such.pem
102 abort: could not find web.cacerts: no-such.pem
103 [255]
103 [255]
104
104
105 Test server address cannot be reused
105 Test server address cannot be reused
106
106
107 $ hg serve -p $HGPORT --certificate=$PRIV 2>&1
107 $ hg serve -p $HGPORT --certificate=$PRIV 2>&1
108 abort: cannot start server at ':$HGPORT': Address already in use
108 abort: cannot start server at ':$HGPORT': Address already in use
109 [255]
109 [255]
110 $ cd ..
110 $ cd ..
111
111
112 clone via pull
112 clone via pull
113
113
114 $ hg clone https://localhost:$HGPORT/ copy-pull
114 $ hg clone https://localhost:$HGPORT/ copy-pull
115 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
115 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
116 requesting all changes
116 requesting all changes
117 adding changesets
117 adding changesets
118 adding manifests
118 adding manifests
119 adding file changes
119 adding file changes
120 added 1 changesets with 4 changes to 4 files
120 added 1 changesets with 4 changes to 4 files
121 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
121 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
122 updating to branch default
122 updating to branch default
123 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
123 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
124 $ hg verify -R copy-pull
124 $ hg verify -R copy-pull
125 checking changesets
125 checking changesets
126 checking manifests
126 checking manifests
127 crosschecking files in changesets and manifests
127 crosschecking files in changesets and manifests
128 checking files
128 checking files
129 4 files, 1 changesets, 4 total revisions
129 4 files, 1 changesets, 4 total revisions
130 $ cd test
130 $ cd test
131 $ echo bar > bar
131 $ echo bar > bar
132 $ hg commit -A -d '1 0' -m 2
132 $ hg commit -A -d '1 0' -m 2
133 adding bar
133 adding bar
134 $ cd ..
134 $ cd ..
135
135
136 pull without cacert
136 pull without cacert
137
137
138 $ cd copy-pull
138 $ cd copy-pull
139 $ echo '[hooks]' >> .hg/hgrc
139 $ echo '[hooks]' >> .hg/hgrc
140 $ echo "changegroup = python '$TESTDIR'/printenv.py changegroup" >> .hg/hgrc
140 $ echo "changegroup = python '$TESTDIR'/printenv.py changegroup" >> .hg/hgrc
141 $ hg pull
141 $ hg pull
142 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
142 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
143 pulling from https://localhost:$HGPORT/
143 pulling from https://localhost:$HGPORT/
144 searching for changes
144 searching for changes
145 adding changesets
145 adding changesets
146 adding manifests
146 adding manifests
147 adding file changes
147 adding file changes
148 added 1 changesets with 1 changes to 1 files
148 added 1 changesets with 1 changes to 1 files
149 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
149 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
150 changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_URL=https://localhost:$HGPORT/
150 changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_URL=https://localhost:$HGPORT/
151 (run 'hg update' to get a working copy)
151 (run 'hg update' to get a working copy)
152 $ cd ..
152 $ cd ..
153
153
154 cacert configured in local repo
154 cacert configured in local repo
155
155
156 $ cp copy-pull/.hg/hgrc copy-pull/.hg/hgrc.bu
156 $ cp copy-pull/.hg/hgrc copy-pull/.hg/hgrc.bu
157 $ echo "[web]" >> copy-pull/.hg/hgrc
157 $ echo "[web]" >> copy-pull/.hg/hgrc
158 $ echo "cacerts=`pwd`/pub.pem" >> copy-pull/.hg/hgrc
158 $ echo "cacerts=`pwd`/pub.pem" >> copy-pull/.hg/hgrc
159 $ hg -R copy-pull pull --traceback
159 $ hg -R copy-pull pull --traceback
160 pulling from https://localhost:$HGPORT/
160 pulling from https://localhost:$HGPORT/
161 searching for changes
161 searching for changes
162 no changes found
162 no changes found
163 $ mv copy-pull/.hg/hgrc.bu copy-pull/.hg/hgrc
163 $ mv copy-pull/.hg/hgrc.bu copy-pull/.hg/hgrc
164
164
165 cacert configured globally, also testing expansion of environment
165 cacert configured globally, also testing expansion of environment
166 variables in the filename
166 variables in the filename
167
167
168 $ echo "[web]" >> $HGRCPATH
168 $ echo "[web]" >> $HGRCPATH
169 $ echo 'cacerts=$P/pub.pem' >> $HGRCPATH
169 $ echo 'cacerts=$P/pub.pem' >> $HGRCPATH
170 $ P=`pwd` hg -R copy-pull pull
170 $ P=`pwd` hg -R copy-pull pull
171 pulling from https://localhost:$HGPORT/
171 pulling from https://localhost:$HGPORT/
172 searching for changes
172 searching for changes
173 no changes found
173 no changes found
174 $ P=`pwd` hg -R copy-pull pull --insecure
174 $ P=`pwd` hg -R copy-pull pull --insecure
175 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
175 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
176 pulling from https://localhost:$HGPORT/
176 pulling from https://localhost:$HGPORT/
177 searching for changes
177 searching for changes
178 no changes found
178 no changes found
179
179
180 cacert mismatch
180 cacert mismatch
181
181
182 $ hg -R copy-pull pull --config web.cacerts=pub.pem https://127.0.0.1:$HGPORT/
182 $ hg -R copy-pull pull --config web.cacerts=pub.pem https://127.0.0.1:$HGPORT/
183 abort: 127.0.0.1 certificate error: certificate is for localhost (use --insecure to connect insecurely)
183 abort: 127.0.0.1 certificate error: certificate is for localhost
184 (configure hostfingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca or use --insecure to connect insecurely)
184 [255]
185 [255]
185 $ hg -R copy-pull pull --config web.cacerts=pub.pem https://127.0.0.1:$HGPORT/ --insecure
186 $ hg -R copy-pull pull --config web.cacerts=pub.pem https://127.0.0.1:$HGPORT/ --insecure
186 warning: 127.0.0.1 certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
187 warning: 127.0.0.1 certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
187 pulling from https://127.0.0.1:$HGPORT/
188 pulling from https://127.0.0.1:$HGPORT/
188 searching for changes
189 searching for changes
189 no changes found
190 no changes found
190 $ hg -R copy-pull pull --config web.cacerts=pub-other.pem
191 $ hg -R copy-pull pull --config web.cacerts=pub-other.pem
191 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
192 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
192 [255]
193 [255]
193 $ hg -R copy-pull pull --config web.cacerts=pub-other.pem --insecure
194 $ hg -R copy-pull pull --config web.cacerts=pub-other.pem --insecure
194 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
195 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
195 pulling from https://localhost:$HGPORT/
196 pulling from https://localhost:$HGPORT/
196 searching for changes
197 searching for changes
197 no changes found
198 no changes found
198
199
199 Test server cert which isn't valid yet
200 Test server cert which isn't valid yet
200
201
201 $ hg -R test serve -p $HGPORT1 -d --pid-file=hg1.pid --certificate=server-not-yet.pem
202 $ hg -R test serve -p $HGPORT1 -d --pid-file=hg1.pid --certificate=server-not-yet.pem
202 $ cat hg1.pid >> $DAEMON_PIDS
203 $ cat hg1.pid >> $DAEMON_PIDS
203 $ hg -R copy-pull pull --config web.cacerts=pub-not-yet.pem https://localhost:$HGPORT1/
204 $ hg -R copy-pull pull --config web.cacerts=pub-not-yet.pem https://localhost:$HGPORT1/
204 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
205 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
205 [255]
206 [255]
206
207
207 Test server cert which no longer is valid
208 Test server cert which no longer is valid
208
209
209 $ hg -R test serve -p $HGPORT2 -d --pid-file=hg2.pid --certificate=server-expired.pem
210 $ hg -R test serve -p $HGPORT2 -d --pid-file=hg2.pid --certificate=server-expired.pem
210 $ cat hg2.pid >> $DAEMON_PIDS
211 $ cat hg2.pid >> $DAEMON_PIDS
211 $ hg -R copy-pull pull --config web.cacerts=pub-expired.pem https://localhost:$HGPORT2/
212 $ hg -R copy-pull pull --config web.cacerts=pub-expired.pem https://localhost:$HGPORT2/
212 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
213 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
213 [255]
214 [255]
214
215
215 Fingerprints
216 Fingerprints
216
217
217 $ echo "[hostfingerprints]" >> copy-pull/.hg/hgrc
218 $ echo "[hostfingerprints]" >> copy-pull/.hg/hgrc
218 $ echo "localhost = 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca" >> copy-pull/.hg/hgrc
219 $ echo "localhost = 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca" >> copy-pull/.hg/hgrc
219 $ echo "127.0.0.1 = 914f1aff87249c09b6859b88b1906d30756491ca" >> copy-pull/.hg/hgrc
220 $ echo "127.0.0.1 = 914f1aff87249c09b6859b88b1906d30756491ca" >> copy-pull/.hg/hgrc
220
221
221 - works without cacerts
222 - works without cacerts
222 $ hg -R copy-pull id https://localhost:$HGPORT/ --config web.cacerts=
223 $ hg -R copy-pull id https://localhost:$HGPORT/ --config web.cacerts=
223 5fed3813f7f5
224 5fed3813f7f5
224
225
225 - fails when cert doesn't match hostname (port is ignored)
226 - fails when cert doesn't match hostname (port is ignored)
226 $ hg -R copy-pull id https://localhost:$HGPORT1/
227 $ hg -R copy-pull id https://localhost:$HGPORT1/
227 abort: invalid certificate for localhost with fingerprint 28:ff:71:bf:65:31:14:23:ad:62:92:b4:0e:31:99:18:fc:83:e3:9b
228 abort: invalid certificate for localhost with fingerprint 28:ff:71:bf:65:31:14:23:ad:62:92:b4:0e:31:99:18:fc:83:e3:9b
228 [255]
229 [255]
229
230
230 - ignores that certificate doesn't match hostname
231 - ignores that certificate doesn't match hostname
231 $ hg -R copy-pull id https://127.0.0.1:$HGPORT/
232 $ hg -R copy-pull id https://127.0.0.1:$HGPORT/
232 5fed3813f7f5
233 5fed3813f7f5
233
234
234 Prepare for connecting through proxy
235 Prepare for connecting through proxy
235
236
236 $ kill `cat hg1.pid`
237 $ kill `cat hg1.pid`
237 $ sleep 1
238 $ sleep 1
238
239
239 $ ("$TESTDIR/tinyproxy.py" $HGPORT1 localhost >proxy.log 2>&1 </dev/null &
240 $ ("$TESTDIR/tinyproxy.py" $HGPORT1 localhost >proxy.log 2>&1 </dev/null &
240 $ echo $! > proxy.pid)
241 $ echo $! > proxy.pid)
241 $ cat proxy.pid >> $DAEMON_PIDS
242 $ cat proxy.pid >> $DAEMON_PIDS
242 $ sleep 2
243 $ sleep 2
243
244
244 $ echo "[http_proxy]" >> copy-pull/.hg/hgrc
245 $ echo "[http_proxy]" >> copy-pull/.hg/hgrc
245 $ echo "always=True" >> copy-pull/.hg/hgrc
246 $ echo "always=True" >> copy-pull/.hg/hgrc
246 $ echo "[hostfingerprints]" >> copy-pull/.hg/hgrc
247 $ echo "[hostfingerprints]" >> copy-pull/.hg/hgrc
247 $ echo "localhost =" >> copy-pull/.hg/hgrc
248 $ echo "localhost =" >> copy-pull/.hg/hgrc
248
249
249 Test unvalidated https through proxy
250 Test unvalidated https through proxy
250
251
251 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --insecure --traceback
252 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --insecure --traceback
252 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
253 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
253 pulling from https://localhost:$HGPORT/
254 pulling from https://localhost:$HGPORT/
254 searching for changes
255 searching for changes
255 no changes found
256 no changes found
256
257
257 Test https with cacert and fingerprint through proxy
258 Test https with cacert and fingerprint through proxy
258
259
259 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub.pem
260 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub.pem
260 pulling from https://localhost:$HGPORT/
261 pulling from https://localhost:$HGPORT/
261 searching for changes
262 searching for changes
262 no changes found
263 no changes found
263 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull https://127.0.0.1:$HGPORT/
264 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull https://127.0.0.1:$HGPORT/
264 pulling from https://127.0.0.1:$HGPORT/
265 pulling from https://127.0.0.1:$HGPORT/
265 searching for changes
266 searching for changes
266 no changes found
267 no changes found
267
268
268 Test https with cert problems through proxy
269 Test https with cert problems through proxy
269
270
270 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub-other.pem
271 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub-other.pem
271 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
272 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
272 [255]
273 [255]
273 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub-expired.pem https://localhost:$HGPORT2/
274 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub-expired.pem https://localhost:$HGPORT2/
274 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
275 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
275 [255]
276 [255]
General Comments 0
You need to be logged in to leave comments. Login now