NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

ssl_pyopenssl.py (5603B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\cherrypy\wsgiserver\ssl_pyopenssl.py
      2 import socket
      3 import threading
      4 import time
      5 from cherrypy import wsgiserver
      6 try:
      7     from OpenSSL import SSL
      8     from OpenSSL import crypto
      9 except ImportError:
     10     SSL = None
     11 
     12 class SSL_fileobject(wsgiserver.CP_fileobject):
     13     ssl_timeout = 3
     14     ssl_retry = 0.01
     15 
     16     def _safe_call(self, is_reader, call, *args, **kwargs):
     17         start = time.time()
     18         while True:
     19             try:
     20                 return call(*args, **kwargs)
     21             except SSL.WantReadError:
     22                 time.sleep(self.ssl_retry)
     23             except SSL.WantWriteError:
     24                 time.sleep(self.ssl_retry)
     25             except SSL.SysCallError as e:
     26                 if is_reader and e.args == (-1, 'Unexpected EOF'):
     27                     return ''
     28                 errnum = e.args[0]
     29                 if is_reader and errnum in wsgiserver.socket_errors_to_ignore:
     30                     return ''
     31                 raise socket.error(errnum)
     32             except SSL.Error as e:
     33                 if is_reader and e.args == (-1, 'Unexpected EOF'):
     34                     return ''
     35                 thirdarg = None
     36                 try:
     37                     thirdarg = e.args[0][0][2]
     38                 except IndexError:
     39                     pass
     40 
     41                 if thirdarg == 'http request':
     42                     raise wsgiserver.NoSSLError()
     43                 raise wsgiserver.FatalSSLAlert(*e.args)
     44             except:
     45                 raise
     46 
     47             if time.time() - start > self.ssl_timeout:
     48                 raise socket.timeout('timed out')
     49 
     50     def recv(self, *args, **kwargs):
     51         buf = []
     52         r = super(SSL_fileobject, self).recv
     53         while True:
     54             data = self._safe_call(True, r, *args, **kwargs)
     55             buf.append(data)
     56             p = self._sock.pending()
     57             if not p:
     58                 return ''.join(buf)
     59 
     60     def sendall(self, *args, **kwargs):
     61         return self._safe_call(False, super(SSL_fileobject, self).sendall, *args, **kwargs)
     62 
     63     def send(self, *args, **kwargs):
     64         return self._safe_call(False, super(SSL_fileobject, self).send, *args, **kwargs)
     65 
     66 
     67 class SSLConnection:
     68 
     69     def __init__(self, *args):
     70         self._ssl_conn = SSL.Connection(*args)
     71         self._lock = threading.RLock()
     72 
     73     for f in ('get_context', 'pending', 'send', 'write', 'recv', 'read', 'renegotiate', 'bind', 'listen', 'connect', 'accept', 'setblocking', 'fileno', 'close', 'get_cipher_list', 'getpeername', 'getsockname', 'getsockopt', 'setsockopt', 'makefile', 'get_app_data', 'set_app_data', 'state_string', 'sock_shutdown', 'get_peer_certificate', 'want_read', 'want_write', 'set_connect_state', 'set_accept_state', 'connect_ex', 'sendall', 'settimeout', 'gettimeout'):
     74         exec 'def %s(self, *args):\n        self._lock.acquire()\n        try:\n            return self._ssl_conn.%s(*args)\n        finally:\n            self._lock.release()\n' % (f, f)
     75 
     76     def shutdown(self, *args):
     77         self._lock.acquire()
     78         try:
     79             return self._ssl_conn.shutdown()
     80         finally:
     81             self._lock.release()
     82 
     83 
     84 class pyOpenSSLAdapter(wsgiserver.SSLAdapter):
     85     context = None
     86     certificate = None
     87     private_key = None
     88     certificate_chain = None
     89 
     90     def __init__(self, certificate, private_key, certificate_chain = None):
     91         if SSL is None:
     92             raise ImportError('You must install pyOpenSSL to use HTTPS.')
     93         self.context = None
     94         self.certificate = certificate
     95         self.private_key = private_key
     96         self.certificate_chain = certificate_chain
     97         self._environ = None
     98 
     99     def bind(self, sock):
    100         if self.context is None:
    101             self.context = self.get_context()
    102         conn = SSLConnection(self.context, sock)
    103         self._environ = self.get_environ()
    104         return conn
    105 
    106     def wrap(self, sock):
    107         return (sock, self._environ.copy())
    108 
    109     def get_context(self):
    110         c = SSL.Context(SSL.SSLv23_METHOD)
    111         c.use_privatekey_file(self.private_key)
    112         if self.certificate_chain:
    113             c.load_verify_locations(self.certificate_chain)
    114         c.use_certificate_file(self.certificate)
    115         return c
    116 
    117     def get_environ(self):
    118         ssl_environ = {'HTTPS': 'on'}
    119         if self.certificate:
    120             cert = open(self.certificate, 'rb').read()
    121             cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert)
    122             ssl_environ.update({'SSL_SERVER_M_VERSION': cert.get_version(),
    123              'SSL_SERVER_M_SERIAL': cert.get_serial_number()})
    124             for prefix, dn in [('I', cert.get_issuer()), ('S', cert.get_subject())]:
    125                 dnstr = str(dn)[18:-2]
    126                 wsgikey = 'SSL_SERVER_%s_DN' % prefix
    127                 ssl_environ[wsgikey] = dnstr
    128                 while dnstr:
    129                     pos = dnstr.rfind('=')
    130                     dnstr, value = dnstr[:pos], dnstr[pos + 1:]
    131                     pos = dnstr.rfind('/')
    132                     dnstr, key = dnstr[:pos], dnstr[pos + 1:]
    133                     if key and value:
    134                         wsgikey = 'SSL_SERVER_%s_DN_%s' % (prefix, key)
    135                         ssl_environ[wsgikey] = value
    136 
    137         return ssl_environ
    138 
    139     def makefile(self, sock, mode = 'r', bufsize = -1):
    140         if SSL and isinstance(sock, SSL.ConnectionType):
    141             timeout = sock.gettimeout()
    142             f = SSL_fileobject(sock, mode, bufsize)
    143             f.ssl_timeout = timeout
    144             return f
    145         else:
    146             return wsgiserver.CP_fileobject(sock, mode, bufsize)