ó
[³XMc           @   s1  d  Z  d d l m Z m Z m Z d d l m Z m Z m Z y e e e ƒ e ƒ Wn7 e	 k
 rŽ Z
 e e
 ƒ d k r ‚  n  e d ƒ ‚ n Xd d l m Z d d l m Z d d l m Z m Z d d	 l m Z m Z d d
 l m Z d d l m Z m Z d e f d „  ƒ  YZ d e f d „  ƒ  YZ d S(   sö  
Implementation of a TLS transport (L{ISSLTransport}) as an L{IProtocol}
layered on top of any L{ITransport} implementation, based on OpenSSL's
memory BIO features.

L{TLSMemoryBIOFactory} is a L{WrappingFactory} which wraps protocols created by
the factory it wraps with L{TLSMemoryBIOProtocol}.  L{TLSMemoryBIOProtocol}
intercedes between the underlying transport and the wrapped protocol to
implement SSL and TLS.  Typical usage of this module looks like this::

    from twisted.protocols.tls import TLSMemoryBIOFactory
    from twisted.internet.protocol import ServerFactory
    from twisted.internet.ssl import PrivateCertificate
    from twisted.internet import reactor

    from someapplication import ApplicationProtocol

    serverFactory = ServerFactory()
    serverFactory.protocol = ApplicationProtocol
    certificate = PrivateCertificate.loadPEM(certPEMData)
    contextFactory = certificate.options()
    tlsFactory = TLSMemoryBIOFactory(contextFactory, False, serverFactory)
    reactor.listenTCP(12345, tlsFactory)
    reactor.run()

Because the reactor's SSL and TLS APIs are likely implemented in a more
efficient way, it is more common to use them (see L{IReactorSSL} and
L{ITLSTransport}).  However, this API offers somewhat more flexibility; for
example, a L{TLSMemoryBIOProtocol} instance can use another instance of
L{TLSMemoryBIOProtocol} as its transport, yielding TLS over TLS - useful to
implement onion routing.  Or it can be used to run TLS over a UNIX socket,
or over stdio to a child process.
iÿÿÿÿ(   t   Errort   ZeroReturnErrort   WantReadError(   t   TLSv1_METHODt   Contextt
   Connections3   argument must be an int, or have a fileno() method.s7   twisted.protocols.tls requires pyOpenSSL 0.10 or newer.(   t
   implements(   t   Failure(   t   ISystemHandlet   ISSLTransport(   t   CONNECTION_DONEt   CONNECTION_LOST(   t   Protocol(   t   ProtocolWrappert   WrappingFactoryt   TLSMemoryBIOProtocolc           B   s™   e  Z d  Z e e e ƒ d Z e Z	 e Z
 e Z e d „ Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d	 „  Z d
 „  Z d „  Z RS(   s}  
    L{TLSMemoryBIOProtocol} is a protocol wrapper which uses OpenSSL via a
    memory BIO to encrypt bytes written to it before sending them on to the
    underlying transport and decrypts bytes received from the underlying
    transport before delivering them to the wrapped protocol.

    @ivar _tlsConnection: The L{OpenSSL.SSL.Connection} instance which is
        encrypted and decrypting this connection.

    @ivar _lostConnection: A flag indicating whether connection loss has
        already been dealt with (C{True}) or not (C{False}).

    @ivar _writeBlockedOnRead: A flag indicating whether further writing must
        wait for data to be received (C{True}) or not (C{False}).

    @ivar _appSendBuffer: A C{list} of C{str} of application-level (cleartext)
        data which is waiting for C{_writeBlockedOnRead} to be reset to
        C{False} so it can be passed to and perhaps accepted by
        C{_tlsConnection.send}.

    @ivar _connectWrapped: A flag indicating whether or not to call
        C{makeConnection} on the wrapped protocol.  This is for the reactor's
        L{ITLSTransport.startTLS} implementation, since it has a protocol which
        it has already called C{makeConnection} on, and which has no interest
        in a new transport.  See #3821.

    @ivar _handshakeDone: A flag indicating whether or not the handshake is
        known to have completed successfully (C{True}) or not (C{False}).  This
        is used to control error reporting behavior.  If the handshake has not
        completed, the underlying L{OpenSSL.SSL.Error} will be passed to the
        application's C{connectionLost} method.  If it has completed, any
        unexpected L{OpenSSL.SSL.Error} will be turned into a
        L{ConnectionLost}.  This is weird; however, it is simply an attempt at
        a faithful re-implementation of the behavior provided by
        L{twisted.internet.ssl}.

    @ivar _reason: If an unexpected L{OpenSSL.SSL.Error} occurs which causes
        the connection to be lost, it is saved here.  If appropriate, this may
        be used as the reason passed to the application protocol's
        C{connectionLost} method.
    c         C   s    t  j |  | | ƒ | |  _ d  S(   N(   R   t   __init__t   _connectWrapped(   t   selft   factoryt   wrappedProtocolR   (    (    s9   /usr/lib/python2.7/dist-packages/twisted/protocols/tls.pyR   l   s    c         C   s   |  j  S(   si  
        Return the L{OpenSSL.SSL.Connection} object being used to encrypt and
        decrypt this connection.

        This is done for the benefit of L{twisted.internet.ssl.Certificate}'s
        C{peerFromTransport} and C{hostFromTransport} methods only.  A
        different system handle may be returned by future versions of this
        method.
        (   t   _tlsConnection(   R   (    (    s9   /usr/lib/python2.7/dist-packages/twisted/protocols/tls.pyt	   getHandleq   s    
c         C   sÅ   |  j  j j ƒ  } t | d ƒ |  _ |  j  j r@ |  j j ƒ  n |  j j ƒ  g  |  _	 t
 j |  | ƒ |  j  j |  ƒ |  j r’ t j |  | ƒ n  y |  j j ƒ  Wn t k
 rÀ |  j ƒ  n Xd S(   s   
        Connect this wrapper to the given transport and initialize the
        necessary L{OpenSSL.SSL.Connection} with a memory BIO.
        N(   R   t   _contextFactoryt
   getContextR   t   NoneR   t	   _isClientt   set_connect_statet   set_accept_statet   _appSendBufferR   t   makeConnectiont   registerProtocolR   R   t   do_handshakeR   t   _flushSendBIO(   R   t	   transportt
   tlsContext(    (    s9   /usr/lib/python2.7/dist-packages/twisted/protocols/tls.pyR   ~   s    		c         C   s>   y |  j  j d ƒ } Wn t k
 r) n X|  j j | ƒ d S(   sh   
        Read any bytes out of the send BIO and write them to the underlying
        transport.
        i   i   Ni €  (   R   t   bio_readR   R"   t   write(   R   t   bytes(    (    s9   /usr/lib/python2.7/dist-packages/twisted/protocols/tls.pyR!   ¢   s
    c         C   sR  xA|  j  sCy |  j j d ƒ } Wnt k
 r6 Pq t k
 r¦ t |  _  |  j j ƒ  |  j r~ |  j	 d k	 r~ |  j	 } n t t ƒ } d |  _	 t j |  | ƒ q t k
 r&} |  j ƒ  t |  _  | j d d k rý | j d d k rý t t ƒ } n	 t ƒ  } t j |  | ƒ |  j j ƒ  q Xt |  _ t j |  | ƒ q W|  j ƒ  d S(	   se  
        Try to receive any application-level bytes which are now available
        because of a previous write into the receive BIO.  This will take
        care of delivering any application-level bytes which are received to
        the protocol, as well as handling of the various exceptions which
        can come from trying to get such bytes.
        i   i   i    iÿÿÿÿi   s   Unexpected EOFNi €  (   t   _lostConnectionR   t   recvR   R   t   TrueR"   t   loseConnectiont   _handshakeDonet   _reasonR   R   R
   R   t   connectionLostR    R!   t   argsR   t   dataReceived(   R   R&   t   failuret   e(    (    s9   /usr/lib/python2.7/dist-packages/twisted/protocols/tls.pyt   _flushReceiveBIO°   s0    		
	&		c         C   sƒ   |  j  j | ƒ |  j ru t |  _ |  j } g  |  _ x | D] } |  j | ƒ q; W|  j ru |  j ru |  j ƒ  qu n  |  j ƒ  d S(   sÄ   
        Deliver any received bytes to the receive BIO and then read and deliver
        to the application any application-level data which becomes available
        as a result of this.
        N(	   R   t	   bio_writet   _writeBlockedOnReadt   FalseR   R%   t   disconnectingR*   R2   (   R   R&   t   appSendBuffer(    (    s9   /usr/lib/python2.7/dist-packages/twisted/protocols/tls.pyR/   ì   s    				c         C   s'   |  j  s# |  j j ƒ  |  j ƒ  n  d S(   sî   
        Handle the possible repetition of calls to this method (due to either
        the underlying transport going away or due to an error at the TLS
        layer) and make sure the base implementation only gets invoked once.
        N(   R'   R   t   bio_shutdownR2   (   R   t   reason(    (    s9   /usr/lib/python2.7/dist-packages/twisted/protocols/tls.pyR-     s    	c         C   s=   t  |  _ |  j s9 |  j j ƒ  |  j ƒ  |  j j ƒ  n  d S(   sM   
        Send a TLS close alert and close the underlying connection.
        N(   R)   R6   R4   R   t   shutdownR!   R"   R*   (   R   (    (    s9   /usr/lib/python2.7/dist-packages/twisted/protocols/tls.pyR*     s
    		
c         C   s±   |  j  r d S| } x— | r¬ y |  j j | ƒ } WnW t k
 r_ t |  _ |  j j | ƒ Pq t k
 r‹ } t	 ƒ  |  _
 |  j j ƒ  Pq Xt |  _ |  j ƒ  | | } q Wd S(   s   
        Process the given application bytes and send any resulting TLS traffic
        which arrives in the send BIO.
        N(   R'   R   t   sendR   R)   R4   R   t   appendR    R   R,   R"   R*   R+   R!   (   R   R&   t
   leftToSendt   sentR1   (    (    s9   /usr/lib/python2.7/dist-packages/twisted/protocols/tls.pyR%     s"    				
c         C   s   |  j  d j | ƒ ƒ d S(   s}   
        Write a sequence of application bytes by joining them into one string
        and passing them to L{write}.
        t    N(   R%   t   join(   R   t   iovec(    (    s9   /usr/lib/python2.7/dist-packages/twisted/protocols/tls.pyt   writeSequence=  s    c         C   s   |  j  j ƒ  S(   N(   R   t   get_peer_certificate(   R   (    (    s9   /usr/lib/python2.7/dist-packages/twisted/protocols/tls.pyt   getPeerCertificateE  s    N(   t   __name__t
   __module__t   __doc__R   R   R	   R   R,   R5   R+   R'   R4   R)   R   R   R   R!   R2   R/   R-   R*   R%   RB   RD   (    (    (    s9   /usr/lib/python2.7/dist-packages/twisted/protocols/tls.pyR   ;   s"   )		$		<				#	t   TLSMemoryBIOFactoryc           B   s   e  Z d  Z e Z d „  Z RS(   s:  
    L{TLSMemoryBIOFactory} adds TLS to connections.

    @ivar _contextFactory: The TLS context factory which will be used to define
        certain TLS connection parameters.

    @ivar _isClient: A flag which is C{True} if this is a client TLS
        connection, C{False} if it is a server TLS connection.
    c         C   s&   t  j |  | ƒ | |  _ | |  _ d  S(   N(   R   R   R   R   (   R   t   contextFactoryt   isClientt   wrappedFactory(    (    s9   /usr/lib/python2.7/dist-packages/twisted/protocols/tls.pyR   V  s    	(   RE   RF   RG   R   t   protocolR   (    (    (    s9   /usr/lib/python2.7/dist-packages/twisted/protocols/tls.pyRH   J  s   	N(   RG   t   OpenSSL.SSLR    R   R   R   R   R   R   t	   TypeErrorR1   t   strt   ImportErrort   zope.interfaceR   t   twisted.python.failureR   t   twisted.internet.interfacesR   R	   t   twisted.internet.mainR
   R   t   twisted.internet.protocolR   t   twisted.protocols.policiesR   R   R   RH   (    (    (    s9   /usr/lib/python2.7/dist-packages/twisted/protocols/tls.pyt   <module>%   s"   ÿ 