##// END OF EJS Templates
merge with stable
Mads Kiilerich -
r12595:0f83a402 merge default
parent child Browse files
Show More
@@ -0,0 +1,41 b''
1 #!/usr/bin/env python
2
3 def check(a, b):
4 if a != b:
5 print (a, b)
6
7 from mercurial.url import _verifycert
8
9 # Test non-wildcard certificates
10 check(_verifycert({'subject': ((('commonName', 'example.com'),),)}, 'example.com'),
11 None)
12 check(_verifycert({'subject': ((('commonName', 'example.com'),),)}, 'www.example.com'),
13 'certificate is for example.com')
14 check(_verifycert({'subject': ((('commonName', 'www.example.com'),),)}, 'example.com'),
15 'certificate is for www.example.com')
16
17 # Test wildcard certificates
18 check(_verifycert({'subject': ((('commonName', '*.example.com'),),)}, 'www.example.com'),
19 None)
20 check(_verifycert({'subject': ((('commonName', '*.example.com'),),)}, 'example.com'),
21 'certificate is for *.example.com')
22 check(_verifycert({'subject': ((('commonName', '*.example.com'),),)}, 'w.w.example.com'),
23 'certificate is for *.example.com')
24
25 # Avoid some pitfalls
26 check(_verifycert({'subject': ((('commonName', '*.foo'),),)}, 'foo'),
27 'certificate is for *.foo')
28 check(_verifycert({'subject': ((('commonName', '*o'),),)}, 'foo'),
29 'certificate is for *o')
30
31 import time
32 lastyear = time.gmtime().tm_year - 1
33 nextyear = time.gmtime().tm_year + 1
34 check(_verifycert({'notAfter': 'May 9 00:00:00 %s GMT' % lastyear}, 'example.com'),
35 'certificate expired May 9 00:00:00 %s GMT' % lastyear)
36 check(_verifycert({'notBefore': 'May 9 00:00:00 %s GMT' % nextyear}, 'example.com'),
37 'certificate not valid before May 9 00:00:00 %s GMT' % nextyear)
38 check(_verifycert({'notAfter': 'Sep 29 15:29:48 %s GMT' % nextyear, 'subject': ()}, 'example.com'),
39 'no commonName found in certificate')
40 check(_verifycert(None, 'example.com'),
41 'no certificate received')
@@ -951,8 +951,9 b' Web interface configuration.'
951 third-party tools like email notification hooks can construct
951 third-party tools like email notification hooks can construct
952 URLs. Example: ``http://hgserver/repos/``.
952 URLs. Example: ``http://hgserver/repos/``.
953 ``cacerts``
953 ``cacerts``
954 Path to file containing a list of PEM encoded certificate authorities
954 Path to file containing a list of PEM encoded certificate authority
955 that may be used to verify an SSL server's identity. The form must be
955 certificates. If specified on the client, then it will verify the identity
956 of remote HTTPS servers with these certificates. The form must be
956 as follows::
957 as follows::
957
958
958 -----BEGIN CERTIFICATE-----
959 -----BEGIN CERTIFICATE-----
@@ -962,8 +963,8 b' Web interface configuration.'
962 ... (certificate in base64 PEM encoding) ...
963 ... (certificate in base64 PEM encoding) ...
963 -----END CERTIFICATE-----
964 -----END CERTIFICATE-----
964
965
965 This feature is only supported when using Python 2.6. If you wish to
966 This feature is only supported when using Python 2.6 or later. If you wish
966 use it with earlier versions of Python, install the backported
967 to use it with earlier versions of Python, install the backported
967 version of the ssl library that is available from
968 version of the ssl library that is available from
968 ``http://pypi.python.org``.
969 ``http://pypi.python.org``.
969
970
@@ -18,6 +18,9 b' Some features, such as pushing to http:/'
18 possible if the feature is explicitly enabled on the remote Mercurial
18 possible if the feature is explicitly enabled on the remote Mercurial
19 server.
19 server.
20
20
21 Note that the security of HTTPS URLs depends on proper configuration of
22 web.cacerts.
23
21 Some notes about using SSH with Mercurial:
24 Some notes about using SSH with Mercurial:
22
25
23 - SSH requires an accessible shell account on the destination machine
26 - SSH requires an accessible shell account on the destination machine
@@ -7,7 +7,7 b''
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
9
10 import urllib, urllib2, urlparse, httplib, os, re, socket, cStringIO
10 import urllib, urllib2, urlparse, httplib, os, re, socket, cStringIO, time
11 import __builtin__
11 import __builtin__
12 from i18n import _
12 from i18n import _
13 import keepalive, util
13 import keepalive, util
@@ -486,6 +486,31 b' class httphandler(keepalive.HTTPHandler)'
486 _generic_start_transaction(self, h, req)
486 _generic_start_transaction(self, h, req)
487 return keepalive.HTTPHandler._start_transaction(self, h, req)
487 return keepalive.HTTPHandler._start_transaction(self, h, req)
488
488
489 def _verifycert(cert, hostname):
490 '''Verify that cert (in socket.getpeercert() format) matches hostname and is
491 valid at this time. CRLs and subjectAltName are not handled.
492
493 Returns error message if any problems are found and None on success.
494 '''
495 if not cert:
496 return _('no certificate received')
497 notafter = cert.get('notAfter')
498 if notafter and time.time() > ssl.cert_time_to_seconds(notafter):
499 return _('certificate expired %s') % notafter
500 notbefore = cert.get('notBefore')
501 if notbefore and time.time() < ssl.cert_time_to_seconds(notbefore):
502 return _('certificate not valid before %s') % notbefore
503 dnsname = hostname.lower()
504 for s in cert.get('subject', []):
505 key, value = s[0]
506 if key == 'commonName':
507 certname = value.lower()
508 if (certname == dnsname or
509 '.' in dnsname and certname == '*.' + dnsname.split('.', 1)[1]):
510 return None
511 return _('certificate is for %s') % certname
512 return _('no commonName found in certificate')
513
489 if has_https:
514 if has_https:
490 class BetterHTTPS(httplib.HTTPSConnection):
515 class BetterHTTPS(httplib.HTTPSConnection):
491 send = keepalive.safesend
516 send = keepalive.safesend
@@ -501,7 +526,11 b' if has_https:'
501 self.sock = _ssl_wrap_socket(sock, self.key_file,
526 self.sock = _ssl_wrap_socket(sock, self.key_file,
502 self.cert_file, cert_reqs=CERT_REQUIRED,
527 self.cert_file, cert_reqs=CERT_REQUIRED,
503 ca_certs=cacerts)
528 ca_certs=cacerts)
504 self.ui.debug(_('server identity verification succeeded\n'))
529 msg = _verifycert(self.sock.getpeercert(), self.host)
530 if msg:
531 raise util.Abort('%s certificate error: %s' % (self.host, msg))
532 self.ui.debug(_('%s certificate successfully verified\n') %
533 self.host)
505 else:
534 else:
506 httplib.HTTPSConnection.connect(self)
535 httplib.HTTPSConnection.connect(self)
507
536
@@ -5,21 +5,16 b" if 'TERM' in os.environ:"
5 import doctest
5 import doctest
6
6
7 import mercurial.changelog
7 import mercurial.changelog
8 # test doctest from changelog
9
10 doctest.testmod(mercurial.changelog)
8 doctest.testmod(mercurial.changelog)
11
9
12 import mercurial.httprepo
10 import mercurial.dagparser
13 doctest.testmod(mercurial.httprepo)
11 doctest.testmod(mercurial.dagparser, optionflags=doctest.NORMALIZE_WHITESPACE)
14
15 import mercurial.util
16 doctest.testmod(mercurial.util)
17
12
18 import mercurial.match
13 import mercurial.match
19 doctest.testmod(mercurial.match)
14 doctest.testmod(mercurial.match)
20
15
21 import mercurial.dagparser
16 import mercurial.url
22 doctest.testmod(mercurial.dagparser, optionflags=doctest.NORMALIZE_WHITESPACE)
17 doctest.testmod(mercurial.url)
23
18
24 import hgext.convert.cvsps
19 import hgext.convert.cvsps
25 doctest.testmod(hgext.convert.cvsps)
20 doctest.testmod(hgext.convert.cvsps)
General Comments 0
You need to be logged in to leave comments. Login now