mercurial/sslutil.py
changeset 25430 19fa0cb71cd3
parent 25429 9d1c61715939
child 25431 96159068c506
equal deleted inserted replaced
25429:9d1c61715939 25430:19fa0cb71cd3
     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, sys
     9 import os, sys, ssl
    10 
    10 
    11 from mercurial import util
    11 from mercurial import util
    12 from mercurial.i18n import _
    12 from mercurial.i18n import _
    13 
    13 
    14 _canloaddefaultcerts = False
    14 _canloaddefaultcerts = False
    15 try:
    15 try:
    16     # avoid using deprecated/broken FakeSocket in python 2.6
       
    17     import ssl
       
    18     CERT_REQUIRED = ssl.CERT_REQUIRED
    16     CERT_REQUIRED = ssl.CERT_REQUIRED
    19     try:
    17     try:
    20         ssl_context = ssl.SSLContext
    18         ssl_context = ssl.SSLContext
    21         _canloaddefaultcerts = util.safehasattr(ssl_context,
    19         _canloaddefaultcerts = util.safehasattr(ssl_context,
    22                                                 'load_default_certs')
    20                                                 'load_default_certs')
    66             # - see http://bugs.python.org/issue13721
    64             # - see http://bugs.python.org/issue13721
    67             if not sslsocket.cipher():
    65             if not sslsocket.cipher():
    68                 raise util.Abort(_('ssl connection failed'))
    66                 raise util.Abort(_('ssl connection failed'))
    69             return sslsocket
    67             return sslsocket
    70 except ImportError:
    68 except ImportError:
    71     CERT_REQUIRED = 2
    69     raise
    72 
       
    73     import socket, httplib
       
    74 
       
    75     def wrapsocket(sock, keyfile, certfile, ui,
       
    76                    cert_reqs=CERT_REQUIRED,
       
    77                    ca_certs=None, serverhostname=None):
       
    78         if not util.safehasattr(socket, 'ssl'):
       
    79             raise util.Abort(_('Python SSL support not found'))
       
    80         if ca_certs:
       
    81             raise util.Abort(_(
       
    82                 'certificate checking requires Python 2.6'))
       
    83 
       
    84         ssl = socket.ssl(sock, keyfile, certfile)
       
    85         return httplib.FakeSocket(sock, ssl)
       
    86 
    70 
    87 def _verifycert(cert, hostname):
    71 def _verifycert(cert, hostname):
    88     '''Verify that cert (in socket.getpeercert() format) matches hostname.
    72     '''Verify that cert (in socket.getpeercert() format) matches hostname.
    89     CRLs is not handled.
    73     CRLs is not handled.
    90 
    74 
   121     return _('no commonName or subjectAltName found in certificate')
   105     return _('no commonName or subjectAltName found in certificate')
   122 
   106 
   123 
   107 
   124 # CERT_REQUIRED means fetch the cert from the server all the time AND
   108 # CERT_REQUIRED means fetch the cert from the server all the time AND
   125 # validate it against the CA store provided in web.cacerts.
   109 # validate it against the CA store provided in web.cacerts.
   126 #
       
   127 # We COMPLETELY ignore CERT_REQUIRED on Python <= 2.5, as it's totally
       
   128 # busted on those versions.
       
   129 
   110 
   130 def _plainapplepython():
   111 def _plainapplepython():
   131     """return true if this seems to be a pure Apple Python that
   112     """return true if this seems to be a pure Apple Python that
   132     * is unfrozen and presumably has the whole mercurial module in the file
   113     * is unfrozen and presumably has the whole mercurial module in the file
   133       system
   114       system
   181 
   162 
   182     def __call__(self, sock, strict=False):
   163     def __call__(self, sock, strict=False):
   183         host = self.host
   164         host = self.host
   184         cacerts = self.ui.config('web', 'cacerts')
   165         cacerts = self.ui.config('web', 'cacerts')
   185         hostfingerprint = self.ui.config('hostfingerprints', host)
   166         hostfingerprint = self.ui.config('hostfingerprints', host)
   186         if not getattr(sock, 'getpeercert', False): # python 2.5 ?
       
   187             if hostfingerprint:
       
   188                 raise util.Abort(_("host fingerprint for %s can't be "
       
   189                                    "verified (Python too old)") % host)
       
   190             if strict:
       
   191                 raise util.Abort(_("certificate for %s can't be verified "
       
   192                                    "(Python too old)") % host)
       
   193             if self.ui.configbool('ui', 'reportoldssl', True):
       
   194                 self.ui.warn(_("warning: certificate for %s can't be verified "
       
   195                                "(Python too old)\n") % host)
       
   196             return
       
   197 
   167 
   198         if not sock.cipher(): # work around http://bugs.python.org/issue13721
   168         if not sock.cipher(): # work around http://bugs.python.org/issue13721
   199             raise util.Abort(_('%s ssl connection error') % host)
   169             raise util.Abort(_('%s ssl connection error') % host)
   200         try:
   170         try:
   201             peercert = sock.getpeercert(True)
   171             peercert = sock.getpeercert(True)