a
    mzf=@                     @   s  d Z ddlZddlZddlZddlmZ zddlZW n eyJ   dZY n0 zddlm	Z	 W n: ey   zddl
m	Z	 W n ey   dZ	Y n0 Y n0 ddlmZ dd	lmZ dd
lmZmZ ddlmZ dd Zdd Zdd Zdd Zdd ZG dd deZdS )z
A library for integrating Python's builtin :py:mod:`ssl` library with Cheroot.

The :py:mod:`ssl` module must be importable for SSL functionality.

To use this module, set ``HTTPServer.ssl_adapter`` to an instance of
``BuiltinSSLAdapter``.
    N)suppress)DEFAULT_BUFFER_SIZE   )Adapter   )errorsStreamReaderStreamWriter)
HTTPServerc                    s6   t |dk rtdt|   t fdd|D S )zACheck whether SSL exception contains either of messages provided.r   zF_assert_ssl_exc_contains() requires at least one message to be passed.c                 3   s   | ]}|   v V  qd S )N)lower).0mZerr_msg_lower A/var/www/media/lib/python3.9/site-packages/cheroot/ssl/builtin.py	<genexpr>*       z+_assert_ssl_exc_contains.<locals>.<genexpr>)len	TypeErrorstrr   any)excZmsgsr   r   r   _assert_ssl_exc_contains"   s    r   c              	   C   sj   t tjtJ | j|ddd}|d W d   n1 s>0    Y  W d   n1 s\0    Y  dS )z;Wrap a socket in ssl and perform the server-side handshake.Tdo_handshake_on_connectserver_sides   0000N)r   sslSSLErrorOSErrorwrap_socketsend)contextserverssl_sockr   r   r   _loopback_for_cert_thread-   s    r&   c                 C   s   t j|d}|| | d|_t j|_t \}}ztj	t
||fd}zr|  |j|ddd>}|d | W  d   W |  W |  |  S 1 s0    Y  W |  n
|  0 W |  |  n|  |  0 dS )z@Create a loopback connection to parse a cert with a private key.)cafileF)targetargsTr      N)r   create_default_contextload_cert_chaincheck_hostname	CERT_NONEverify_modesocket
socketpair	threadingThreadr&   startr!   recvgetpeercertjoinclose)certificateprivate_keycertificate_chainr#   clientr$   threadr%   r   r   r   _loopback_for_certL   s8    

r>   c                 C   sr   t ttjt t| ||W  d   S 1 s00    Y  t t tj| W  d   S 1 sd0    Y  i S )zParse a certificate.N)	r   AttributeErrorr   r   r    r>   	Exception_ssl_test_decode_cert)r9   r:   r;   r   r   r   _parse_certn   s
    *
*rC   c                 C   s
   || _ dS )z7Handle the SNI callback to tag the socket with the SNI.N)sni)sockrD   r#   r   r   r   _sni_callback   s    rF   c                       s   e Zd ZdZdZdZdZdZddddddd	d
ZddddddddddddddZ	d- fdd	Z
edd Zejdd Z fddZd d! Zd"d# Zd$d% Zd&d' Zd(d) Zd*efd+d,Z  ZS ).BuiltinSSLAdapterzDWrapper for integrating Python's builtin :py:mod:`ssl` with Cheroot.NZ	M_VERSIONZM_SERIALZV_STARTZV_ENDZS_DNZI_DNSAN)versionZserialNumber	notBeforenotAftersubjectZissuersubjectAltNameCZSTLOZOUZCNTIGSDUIDEmail)ZcountryNameZstateOrProvinceNameZlocalityNameZorganizationNameZorganizationalUnitName
commonNametitleZinitialsZ	givenNameZsurnamedescriptionZuseridZemailAddressc           	         s  t du rtdtt| |||| t jt jj|d| _| j	|| | j
dur^| j| | dt||| j| _| jsdS d}t|dd}| }W d   n1 s0    Y  |t j}|dkrdS |t j|}|dkrdS |tt j7 }||| | jd< dS )	zASet up context in addition to base class properties if available.Nz-You must install the ssl module to use HTTPS.)purposer'   Z
SSL_SERVERrt)moder   ZSSL_SERVER_CERT)r   ImportErrorsuperrG   __init__r+   PurposeCLIENT_AUTHr#   r,   ciphersset_ciphers_make_env_cert_dictrC   r;   _server_envopenreadfind
PEM_HEADER
PEM_FOOTERr   )	selfr9   r:   r;   rc   certfZ
cert_startZcert_end	__class__r   r   r`      s:    

&zBuiltinSSLAdapter.__init__c                 C   s   | j S )z>:py:class:`~ssl.SSLContext` that will be used to wrap sockets.)_context)rl   r   r   r   r#      s    zBuiltinSSLAdapter.contextc                 C   sH   || _ tt& tjr&|jdu r&t|_W d   n1 s:0    Y  dS )zSet the ssl ``context`` to use.N)rq   r   r?   r   HAS_SNIsni_callbackrF   )rl   r#   r   r   r   r#      s    
c                    s   t t| |S )z!Wrap and return the given socket.)r_   rG   bind)rl   rE   ro   r   r   rt     s    zBuiltinSSLAdapter.bindc              
   C   s   z| j j|ddd}W n tjtjfyP } ztj|j |W Y d}~nd}~0  tjy } z@|j	tj
kott|d}|rtj}ntj}||j |W Y d}~n:d}~0  ty } ztj|j |W Y d}~n
d}~0 0 || |fS )z<Wrap and return the given socket, plus WSGI environ entries.Tr   Nzhttp request)r#   r!   r   SSLEOFErrorSSLZeroReturnErrorr   ZFatalSSLAlertr)   r   errnoSSL_ERROR_SSLr   Z
NoSSLErrorr    get_environ)rl   rE   sZtls_connection_drop_errorZgeneric_tls_errorZ!peer_speaks_plain_http_over_httpsZ reraised_connection_drop_exc_clsZtcp_connection_drop_errorr   r   r   wrap  s@    
zBuiltinSSLAdapter.wrapc              
   C   s  |  }dd|d |d d|d dtjtjf tjdd		}tt( | }|d
ur\||d< W d
   n1 sp0    Y  tt  |j	j
 |d< W d
   n1 s0    Y  ttP |d
d }|j D ](}||d |d fkr|d |d<  qqW d
   n1 s0    Y  tt |j|d< W d
   n1 sF0    Y  | jr| jjtjkr| }|rd|d< || d| t|jdd |d< || j |S )z;Create WSGI environ entries to be merged into each request.httpsonr   r    r   z%s Python/%sNONE)	zwsgi.url_schemeHTTPSZSSL_PROTOCOLZ
SSL_CIPHERZSSL_CIPHER_EXPORTZSSL_CIPHER_USEKEYSIZEZSSL_VERSION_INTERFACEZSSL_VERSION_LIBRARYSSL_CLIENT_VERIFYNZSSL_COMPRESS_METHODZSSL_SESSION_IDnameprotocolZalg_bitsZSSL_CIPHER_ALGKEYSIZEZSSL_TLS_SNISUCCESSr   Z
SSL_CLIENTT)binary_formZSSL_CLIENT_CERT)cipherr   rI   sysr   OPENSSL_VERSIONr   r?   compressionsessionidhexr#   get_ciphersrD   r/   r.   r6   updatere   DER_cert_to_PEM_certstriprf   )rl   rE   r   Zssl_environr   Ztarget_cipherZcipclient_certr   r   r   ry   (  sN    
&
.
&
*

	zBuiltinSSLAdapter.get_environc           	      C   s   |si S i }| j  D ]d\}}d||f }||}|dkrP|| || q|drn|| || qt|||< qd|v rt	|d }|t	|d 8 }|d }tt
||d|f < |S )zReturn a dict of WSGI environment variables for a certificate.

        E.g. SSL_CLIENT_M_VERSION, SSL_CLIENT_M_SERIAL, etc.
        See https://httpd.apache.org/docs/2.4/mod/mod_ssl.html#envvars.
        %s_%srH   Z_DNrJ   rK   iQ z%s_V_REMAIN)CERT_KEY_TO_ENVitemsgetr   _make_env_san_dictendswith_make_env_dn_dictr   r   cert_time_to_secondsint)	rl   
env_prefixZparsed_certenvZcert_keyenv_varkeyvalueZremainr   r   r   re   f  s"    

z%BuiltinSSLAdapter._make_env_cert_dictc                 C   sh   |si S i }d}d}|D ]J\}}|dkrB||d||f < |d7 }q|dkr||d||f < |d7 }q|S )zReturn a dict of WSGI environment variables for a certificate DN.

        E.g. SSL_CLIENT_SAN_Email_0, SSL_CLIENT_SAN_DNS_0, etc.
        See SSL_CLIENT_SAN_* at
        https://httpd.apache.org/docs/2.4/mod/mod_ssl.html#envvars.
        r   DNSz	%s_DNS_%ir   rW   z%s_Email_%ir   )rl   r   
cert_valuer   Z	dns_countZemail_count	attr_namevalr   r   r   r     s    

z$BuiltinSSLAdapter._make_env_san_dictc                 C   s   |si S g }i }|D ]T}|D ]J\}}| j |}|d|p<||f  |sLq||g  || | qq|d|i}	| D ]P\}}
d|
|	d||f < t|
dkrqt|
D ]\}}||	d|||f < qq|	S )zReturn a dict of WSGI environment variables for a certificate DN.

        E.g. SSL_CLIENT_S_DN_CN, SSL_CLIENT_S_DN_C, etc.
        See SSL_CLIENT_S_DN_x509 at
        https://httpd.apache.org/docs/2.4/mod/mod_ssl.html#envvars.
        z%s=%s,r   r   z%s_%s_%i)CERT_KEY_TO_LDAP_CODEr   append
setdefaultr7   r   r   	enumerate)rl   r   r   dnZdn_attrsZrdnr   r   Z	attr_coder   valuesir   r   r   r     s*    
z#BuiltinSSLAdapter._make_env_dn_dictrc                 C   s   d|v rt nt}||||S )zReturn socket file object.r   r	   )rl   rE   r]   bufsizeclsr   r   r   makefile  s    zBuiltinSSLAdapter.makefile)NN)__name__
__module____qualname____doc__r9   r:   r;   rc   r   r   r`   propertyr#   setterrt   r{   ry   re   r   r   r   r   __classcell__r   r   ro   r   rG      sR     (

!> rG   )r   r0   r   r2   
contextlibr   r   r^   Z_pyior   ior~   r   r   r   r
   r   r$   r   r   r&   r>   rC   rF   rG   r   r   r   r   <module>   s2   	
"