2015-07-10 48 views
0

我最近開始使用Bitbucket和mercurial。我可以用Git倉庫工作得很好,但是當我嘗試克隆一個善變的一個,它在/Users/foobar/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/mercurial-3.4.2-py2.7-macosx-10.6-x86_64.egg/mercurial/sslutil.py崩潰上線36,與錯誤:使用Mercurial進行克隆時,SSL封裝中的錯誤

ValueError: can't clear options before OpenSSL 0.9.8m

我運行的OpenSSL 1.0.2c。

如從文件路徑明顯,我通過Enthought雨棚下載蟒蛇(和水銀)

我搜索周圍,我發現有人有類似的問題:https://bitbucket.org/durin42/hgsubversion/issues/439/unknown-exception-in-dispatchpy-value。他的部分解決方案(評論出問題的線)足以讓我的下載工作,但我承認,我已經深深地試圖確定這是否會對我使用Mercurial造成任何安全問題。這有沒有任何潛在的安全問題?是否有任何其他信息需要開始回答?

我編輯的文件如下(搜索「==========」找到我刪除的行)。

# sslutil.py - SSL handling for mercurial 
# 
# Copyright 2005, 2006, 2007, 2008 Matt Mackall <[email protected]> 
# Copyright 2006, 2007 Alexis S. L. Carvalho <[email protected]> 
# Copyright 2006 Vadim Gelfer <[email protected]> 
# 
# This software may be used and distributed according to the terms of the 
# GNU General Public License version 2 or any later version. 
import os, sys 

from mercurial import util 
from mercurial.i18n import _ 

_canloaddefaultcerts = False 
try: 
    # avoid using deprecated/broken FakeSocket in python 2.6 
    import ssl 
    CERT_REQUIRED = ssl.CERT_REQUIRED 
    try: 
     ssl_context = ssl.SSLContext 
     _canloaddefaultcerts = util.safehasattr(ssl_context, 
               'load_default_certs') 

     def ssl_wrap_socket(sock, keyfile, certfile, cert_reqs=ssl.CERT_NONE, 
          ca_certs=None, serverhostname=None): 
      # Allow any version of SSL starting with TLSv1 and 
      # up. Note that specifying TLSv1 here prohibits use of 
      # newer standards (like TLSv1_2), so this is the right way 
      # to do this. Note that in the future it'd be better to 
      # support using ssl.create_default_context(), which sets 
      # up a bunch of things in smart ways (strong ciphers, 
      # protocol versions, etc) and is upgraded by Python 
      # maintainers for us, but that breaks too many things to 
      # do it in a hurry. 
      sslcontext = ssl.SSLContext(ssl.PROTOCOL_SSLv23) 

      # ================================================ 
      # LINE I REMOVED 
      sslcontext.options &= ssl.OP_NO_SSLv2 & ssl.OP_NO_SSLv3 
      # ================================================ 

      if certfile is not None: 
       sslcontext.load_cert_chain(certfile, keyfile) 
      sslcontext.verify_mode = cert_reqs 
      if ca_certs is not None: 
       sslcontext.load_verify_locations(cafile=ca_certs) 
      elif _canloaddefaultcerts: 
       sslcontext.load_default_certs() 

      sslsocket = sslcontext.wrap_socket(sock, 
               server_hostname=serverhostname) 
      # check if wrap_socket failed silently because socket had been 
      # closed 
      # - see http://bugs.python.org/issue13721 
      if not sslsocket.cipher(): 
       raise util.Abort(_('ssl connection failed')) 
      return sslsocket 
    except AttributeError: 
     def ssl_wrap_socket(sock, keyfile, certfile, cert_reqs=ssl.CERT_NONE, 
          ca_certs=None, serverhostname=None): 
      sslsocket = ssl.wrap_socket(sock, keyfile, certfile, 
             cert_reqs=cert_reqs, ca_certs=ca_certs, 
             ssl_version=ssl.PROTOCOL_TLSv1) 
      # check if wrap_socket failed silently because socket had been 
      # closed 
      # - see http://bugs.python.org/issue13721 
      if not sslsocket.cipher(): 
       raise util.Abort(_('ssl connection failed')) 
      return sslsocket 
except ImportError: 
    CERT_REQUIRED = 2 

    import socket, httplib 

    def ssl_wrap_socket(sock, keyfile, certfile, cert_reqs=CERT_REQUIRED, 
         ca_certs=None, serverhostname=None): 
     if not util.safehasattr(socket, 'ssl'): 
      raise util.Abort(_('Python SSL support not found')) 
     if ca_certs: 
      raise util.Abort(_(
       'certificate checking requires Python 2.6')) 

     ssl = socket.ssl(sock, keyfile, certfile) 
     return httplib.FakeSocket(sock, ssl) 

def _verifycert(cert, hostname): 
    '''Verify that cert (in socket.getpeercert() format) matches hostname. 
    CRLs is not handled. 

    Returns error message if any problems are found and None on success. 
    ''' 
    if not cert: 
     return _('no certificate received') 
    dnsname = hostname.lower() 
    def matchdnsname(certname): 
     return (certname == dnsname or 
       '.' in dnsname and certname == '*.' + dnsname.split('.', 1)[1]) 

    san = cert.get('subjectAltName', []) 
    if san: 
     certnames = [value.lower() for key, value in san if key == 'DNS'] 
     for name in certnames: 
      if matchdnsname(name): 
       return None 
     if certnames: 
      return _('certificate is for %s') % ', '.join(certnames) 

    # subject is only checked when subjectAltName is empty 
    for s in cert.get('subject', []): 
     key, value = s[0] 
     if key == 'commonName': 
      try: 
       # 'subject' entries are unicode 
       certname = value.lower().encode('ascii') 
      except UnicodeEncodeError: 
       return _('IDN in certificate not supported') 
      if matchdnsname(certname): 
       return None 
      return _('certificate is for %s') % certname 
    return _('no commonName or subjectAltName found in certificate') 


# CERT_REQUIRED means fetch the cert from the server all the time AND 
# validate it against the CA store provided in web.cacerts. 
# 
# We COMPLETELY ignore CERT_REQUIRED on Python <= 2.5, as it's totally 
# busted on those versions. 

def _plainapplepython(): 
    """return true if this seems to be a pure Apple Python that 
    * is unfrozen and presumably has the whole mercurial module in the file 
     system 
    * presumably is an Apple Python that uses Apple OpenSSL which has patches 
     for using system certificate store CAs in addition to the provided 
     cacerts file 
    """ 
    if sys.platform != 'darwin' or util.mainfrozen() or not sys.executable: 
     return False 
    exe = os.path.realpath(sys.executable).lower() 
    return (exe.startswith('/usr/bin/python') or 
      exe.startswith('/system/library/frameworks/python.framework/')) 

def _defaultcacerts(): 
    """return path to CA certificates; None for system's store; ! to disable""" 
    if _plainapplepython(): 
     dummycert = os.path.join(os.path.dirname(__file__), 'dummycert.pem') 
     if os.path.exists(dummycert): 
      return dummycert 
    if _canloaddefaultcerts: 
     return None 
    return '!' 

def sslkwargs(ui, host): 
    kws = {} 
    hostfingerprint = ui.config('hostfingerprints', host) 
    if hostfingerprint: 
     return kws 
    cacerts = ui.config('web', 'cacerts') 
    if cacerts == '!': 
     pass 
    elif cacerts: 
     cacerts = util.expandpath(cacerts) 
     if not os.path.exists(cacerts): 
      raise util.Abort(_('could not find web.cacerts: %s') % cacerts) 
    else: 
     cacerts = _defaultcacerts() 
     if cacerts and cacerts != '!': 
      ui.debug('using %s to enable OS X system CA\n' % cacerts) 
     ui.setconfig('web', 'cacerts', cacerts, 'defaultcacerts') 
    if cacerts != '!': 
     kws.update({'ca_certs': cacerts, 
        'cert_reqs': CERT_REQUIRED, 
        }) 
    return kws 

class validator(object): 
    def __init__(self, ui, host): 
     self.ui = ui 
     self.host = host 

    def __call__(self, sock, strict=False): 
     host = self.host 
     cacerts = self.ui.config('web', 'cacerts') 
     hostfingerprint = self.ui.config('hostfingerprints', host) 
     if not getattr(sock, 'getpeercert', False): # python 2.5 ? 
      if hostfingerprint: 
       raise util.Abort(_("host fingerprint for %s can't be " 
            "verified (Python too old)") % host) 
      if strict: 
       raise util.Abort(_("certificate for %s can't be verified " 
            "(Python too old)") % host) 
      if self.ui.configbool('ui', 'reportoldssl', True): 
       self.ui.warn(_("warning: certificate for %s can't be verified " 
           "(Python too old)\n") % host) 
      return 

     if not sock.cipher(): # work around http://bugs.python.org/issue13721 
      raise util.Abort(_('%s ssl connection error') % host) 
     try: 
      peercert = sock.getpeercert(True) 
      peercert2 = sock.getpeercert() 
     except AttributeError: 
      raise util.Abort(_('%s ssl connection error') % host) 

     if not peercert: 
      raise util.Abort(_('%s certificate error: ' 
           'no certificate received') % host) 
     peerfingerprint = util.sha1(peercert).hexdigest() 
     nicefingerprint = ":".join([peerfingerprint[x:x + 2] 
      for x in xrange(0, len(peerfingerprint), 2)]) 
     if hostfingerprint: 
      if peerfingerprint.lower() != \ 
        hostfingerprint.replace(':', '').lower(): 
       raise util.Abort(_('certificate for %s has unexpected ' 
            'fingerprint %s') % (host, nicefingerprint), 
           hint=_('check hostfingerprint configuration')) 
      self.ui.debug('%s certificate matched fingerprint %s\n' % 
          (host, nicefingerprint)) 
     elif cacerts != '!': 
      msg = _verifycert(peercert2, host) 
      if msg: 
       raise util.Abort(_('%s certificate error: %s') % (host, msg), 
           hint=_('configure hostfingerprint %s or use ' 
             '--insecure to connect insecurely') % 
             nicefingerprint) 
      self.ui.debug('%s certificate successfully verified\n' % host) 
     elif strict: 
      raise util.Abort(_('%s certificate with fingerprint %s not ' 
           'verified') % (host, nicefingerprint), 
          hint=_('check hostfingerprints or web.cacerts ' 
            'config setting')) 
     else: 
      self.ui.warn(_('warning: %s certificate with fingerprint %s not ' 
          'verified (check hostfingerprints or web.cacerts ' 
          'config setting)\n') % 
         (host, nicefingerprint)) 

回答

0

註釋掉的行是禁止使用一些較老和較弱加密協議的行;評論它可以讓你使用那些較舊的協議。服務器可能不支持更新的協議。除非你擔心NSA得到他們的代碼,否則這可能不是什麼大不了的事情。

1
ValueError: can't clear options before OpenSSL 0.9.8m 

I am running OpenSSL 1.0.2c.

只是一個猜測,但它聽起來像腳本使用蘋果的OpenSSL版本,這是0.9.8的(而不是OpenSSL的1.0.2,你建的東西反對)。

爲確保您使用OpenSSL 1.0.2,請使用DYLD_LIBRARY_PATH。它類似於Linux上的LD_LIBRARY_PATH

另一種選擇是從OpenSSL Configure中省略shared,以便您的裝備只能執行靜態鏈接。如果可用的話,蘋果的鏈接器總是使用*.dylib(即使在iOS中,如果不允許的話),所以你必須小心。

+0

我的問題是,雖然我已經通過自制安裝了Python和OpenSSL 1.0.2e,自制不會覆蓋默認在/ usr/local/bin目錄現有的符號鏈接,所以我實際上是使用不同的Python和OpenSSL。運行| brew重新安裝python |輸出一條消息注意到這一點,並注意如何覆蓋現有的符號鏈接。這個問題解決了。 – jwatt

1

假設OS X.

嘗試檢查蟒蛇你用什麼:

which python /usr/local/bin/python

然後看到該記錄指向

ls -al /usr/local/bin/python 

/usr/local/bin/python -> /System/Library/Frameworks/Python.framework/Versions/2.7/bin/python 

確保您使用/System/Library/Frameworks蟒蛇如果沒有,則刪除/usr/local/bin/python符號鏈接並重新創建它:

ln -s /System/Library/Frameworks/Python.framework/Versions/2.7/bin/python /usr/local/bin/python