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') |
@@ -7,7 +7,7 b'' | |||
|
7 | 7 | # This software may be used and distributed according to the terms of the |
|
8 | 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 | 11 | from i18n import _ |
|
12 | 12 | import keepalive, util |
|
13 | 13 | |
@@ -469,6 +469,31 b' class httphandler(keepalive.HTTPHandler)' | |||
|
469 | 469 | _generic_start_transaction(self, h, req) |
|
470 | 470 | return keepalive.HTTPHandler._start_transaction(self, h, req) |
|
471 | 471 | |
|
472 | def _verifycert(cert, hostname): | |
|
473 | '''Verify that cert (in socket.getpeercert() format) matches hostname and is | |
|
474 | valid at this time. CRLs and subjectAltName are not handled. | |
|
475 | ||
|
476 | Returns error message if any problems are found and None on success. | |
|
477 | ''' | |
|
478 | if not cert: | |
|
479 | return _('no certificate received') | |
|
480 | notafter = cert.get('notAfter') | |
|
481 | if notafter and time.time() > ssl.cert_time_to_seconds(notafter): | |
|
482 | return _('certificate expired %s') % notafter | |
|
483 | notbefore = cert.get('notBefore') | |
|
484 | if notbefore and time.time() < ssl.cert_time_to_seconds(notbefore): | |
|
485 | return _('certificate not valid before %s') % notbefore | |
|
486 | dnsname = hostname.lower() | |
|
487 | for s in cert.get('subject', []): | |
|
488 | key, value = s[0] | |
|
489 | if key == 'commonName': | |
|
490 | certname = value.lower() | |
|
491 | if (certname == dnsname or | |
|
492 | '.' in dnsname and certname == '*.' + dnsname.split('.', 1)[1]): | |
|
493 | return None | |
|
494 | return _('certificate is for %s') % certname | |
|
495 | return _('no commonName found in certificate') | |
|
496 | ||
|
472 | 497 | if has_https: |
|
473 | 498 | class BetterHTTPS(httplib.HTTPSConnection): |
|
474 | 499 | send = keepalive.safesend |
@@ -484,7 +509,11 b' if has_https:' | |||
|
484 | 509 | self.sock = _ssl_wrap_socket(sock, self.key_file, |
|
485 | 510 | self.cert_file, cert_reqs=CERT_REQUIRED, |
|
486 | 511 | ca_certs=cacerts) |
|
487 | self.ui.debug(_('server identity verification succeeded\n')) | |
|
512 | msg = _verifycert(self.sock.getpeercert(), self.host) | |
|
513 | if msg: | |
|
514 | raise util.Abort('%s certificate error: %s' % (self.host, msg)) | |
|
515 | self.ui.debug(_('%s certificate successfully verified\n') % | |
|
516 | self.host) | |
|
488 | 517 | else: |
|
489 | 518 | httplib.HTTPSConnection.connect(self) |
|
490 | 519 |
General Comments 0
You need to be logged in to leave comments.
Login now