Show More
@@ -506,22 +506,38 b' class httphandler(keepalive.HTTPHandler)' | |||||
506 |
|
506 | |||
507 | def _verifycert(cert, hostname): |
|
507 | def _verifycert(cert, hostname): | |
508 | '''Verify that cert (in socket.getpeercert() format) matches hostname. |
|
508 | '''Verify that cert (in socket.getpeercert() format) matches hostname. | |
509 |
CRLs |
|
509 | CRLs is not handled. | |
510 |
|
510 | |||
511 | Returns error message if any problems are found and None on success. |
|
511 | Returns error message if any problems are found and None on success. | |
512 | ''' |
|
512 | ''' | |
513 | if not cert: |
|
513 | if not cert: | |
514 | return _('no certificate received') |
|
514 | return _('no certificate received') | |
515 | dnsname = hostname.lower() |
|
515 | dnsname = hostname.lower() | |
|
516 | def matchdnsname(certname): | |||
|
517 | return (certname == dnsname or | |||
|
518 | '.' in dnsname and certname == '*.' + dnsname.split('.', 1)[1]) | |||
|
519 | ||||
|
520 | san = cert.get('subjectAltName', []) | |||
|
521 | if san: | |||
|
522 | certnames = [value.lower() for key, value in san if key == 'DNS'] | |||
|
523 | for name in certnames: | |||
|
524 | if matchdnsname(name): | |||
|
525 | return None | |||
|
526 | return _('certificate is for %s') % ', '.join(certnames) | |||
|
527 | ||||
|
528 | # subject is only checked when subjectAltName is empty | |||
516 | for s in cert.get('subject', []): |
|
529 | for s in cert.get('subject', []): | |
517 | key, value = s[0] |
|
530 | key, value = s[0] | |
518 | if key == 'commonName': |
|
531 | if key == 'commonName': | |
519 | certname = value.lower() |
|
532 | try: | |
520 | if (certname == dnsname or |
|
533 | # 'subject' entries are unicode | |
521 | '.' in dnsname and certname == '*.' + dnsname.split('.', 1)[1]): |
|
534 | certname = value.lower().encode('ascii') | |
|
535 | except UnicodeEncodeError: | |||
|
536 | return _('IDN in certificate not supported') | |||
|
537 | if matchdnsname(certname): | |||
522 | return None |
|
538 | return None | |
523 | return _('certificate is for %s') % certname |
|
539 | return _('certificate is for %s') % certname | |
524 | return _('no commonName found in certificate') |
|
540 | return _('no commonName or subjectAltName found in certificate') | |
525 |
|
541 | |||
526 | if has_https: |
|
542 | if has_https: | |
527 | class BetterHTTPS(httplib.HTTPSConnection): |
|
543 | class BetterHTTPS(httplib.HTTPSConnection): |
@@ -25,6 +25,18 b" check(_verifycert(cert('*.example.com')," | |||||
25 | check(_verifycert(cert('*.example.com'), 'w.w.example.com'), |
|
25 | check(_verifycert(cert('*.example.com'), 'w.w.example.com'), | |
26 | 'certificate is for *.example.com') |
|
26 | 'certificate is for *.example.com') | |
27 |
|
27 | |||
|
28 | # Test subjectAltName | |||
|
29 | san_cert = {'subject': ((('commonName', 'example.com'),),), | |||
|
30 | 'subjectAltName': (('DNS', '*.example.net'), | |||
|
31 | ('DNS', 'example.net'))} | |||
|
32 | check(_verifycert(san_cert, 'example.net'), | |||
|
33 | None) | |||
|
34 | check(_verifycert(san_cert, 'foo.example.net'), | |||
|
35 | None) | |||
|
36 | # subject is only checked when subjectAltName is empty | |||
|
37 | check(_verifycert(san_cert, 'example.com'), | |||
|
38 | 'certificate is for *.example.net, example.net') | |||
|
39 | ||||
28 | # Avoid some pitfalls |
|
40 | # Avoid some pitfalls | |
29 | check(_verifycert(cert('*.foo'), 'foo'), |
|
41 | check(_verifycert(cert('*.foo'), 'foo'), | |
30 | 'certificate is for *.foo') |
|
42 | 'certificate is for *.foo') | |
@@ -33,6 +45,10 b" check(_verifycert(cert('*o'), 'foo')," | |||||
33 |
|
45 | |||
34 | check(_verifycert({'subject': ()}, |
|
46 | check(_verifycert({'subject': ()}, | |
35 | 'example.com'), |
|
47 | 'example.com'), | |
36 | 'no commonName found in certificate') |
|
48 | 'no commonName or subjectAltName found in certificate') | |
37 | check(_verifycert(None, 'example.com'), |
|
49 | check(_verifycert(None, 'example.com'), | |
38 | 'no certificate received') |
|
50 | 'no certificate received') | |
|
51 | ||||
|
52 | # Unicode (IDN) certname isn't supported | |||
|
53 | check(_verifycert(cert(u'\u4f8b.jp'), 'example.jp'), | |||
|
54 | 'IDN in certificate not supported') |
General Comments 0
You need to be logged in to leave comments.
Login now