a
     O–c1  ã                   @   sþ   d Z ddlZddlZddlZddlZddlZddlZddlZddl	m
Z
 ddl	mZ ddlmZ ddlmZ ddlmZ ddlmZ e e¡ZejZG d	d
„ d
eƒZG dd„ deƒZddeddfdd„Zddd„Zdd„ Zdd„ Zd dd„Ze
jfdd„Z dS )!zCrypto utilities.é    N)Úcrypto)ÚSSL)Úerrors)ÚCallable)ÚTuple)ÚUnionc                   @   s   e Zd Zdd„ Zdd„ ZdS )Ú_DefaultCertSelectionc                 C   s
   || _ d S ©N)Úcerts)Úselfr
   © r   ú2/usr/lib/python3/dist-packages/acme/crypto_util.pyÚ__init__   s    z_DefaultCertSelection.__init__c                 C   s   |  ¡ }| j |d ¡S r	   )Úget_servernamer
   Úget)r   Ú
connectionZserver_namer   r   r   Ú__call__"   s    z_DefaultCertSelection.__call__N)Ú__name__Ú
__module__Ú__qualname__r   r   r   r   r   r   r      s   r   c                   @   sJ   e Zd ZdZdeddfdd„Zdd„ Zdd„ ZG d	d
„ d
eƒZ	dd„ Z
dS )Ú	SSLSocketaÝ  SSL wrapper for sockets.

    :ivar socket sock: Original wrapped socket.
    :ivar dict certs: Mapping from domain names (`bytes`) to
        `OpenSSL.crypto.X509`.
    :ivar method: See `OpenSSL.SSL.Context` for allowed values.
    :ivar alpn_selection: Hook to select negotiated ALPN protocol for
        connection.
    :ivar cert_selection: Hook to select certificate for connection. If given,
        `certs` parameter would be ignored, and therefore must be empty.

    Nc                 C   sL   || _ || _|| _|s"|s"tdƒ‚|r2|r2tdƒ‚|d u rBt|ƒ}|| _d S )Nz*Neither cert_selection or certs specified.z(Both cert_selection and certs specified.)ÚsockÚalpn_selectionÚmethodÚ
ValueErrorr   Úcert_selection)r   r   r
   r   r   r   r   r   r   r   4   s    zSSLSocket.__init__c                 C   s   t | j|ƒS r	   )Úgetattrr   ©r   Únamer   r   r   Ú__getattr__B   s    zSSLSocket.__getattr__c                 C   sŠ   |   |¡}|du r&t d| ¡ ¡ dS |\}}t | j¡}| tj¡ | tj	¡ | 
|¡ | |¡ | jdur|| | j¡ | |¡ dS )a  SNI certificate callback.

        This method will set a new OpenSSL context object for this
        connection when an incoming connection provides an SNI name
        (in order to serve the appropriate certificate, if any).

        :param connection: The TLS connection object on which the SNI
            extension was received.
        :type connection: :class:`OpenSSL.Connection`

        Nz=Certificate selection for server name %s failed, dropping SSL)r   ÚloggerÚdebugr   r   ÚContextr   Úset_optionsÚOP_NO_SSLv2ÚOP_NO_SSLv3Zuse_privatekeyZuse_certificater   Úset_alpn_select_callbackZset_context)r   r   ZpairÚkeyÚcertZnew_contextr   r   r   Ú_pick_certificate_cbE   s    
ÿ


zSSLSocket._pick_certificate_cbc                   @   s(   e Zd ZdZdd„ Zdd„ Zdd„ ZdS )	zSSLSocket.FakeConnectionzFake OpenSSL.SSL.Connection.c                 C   s
   || _ d S r	   )Ú_wrapped)r   r   r   r   r   r   e   s    z!SSLSocket.FakeConnection.__init__c                 C   s   t | j|ƒS r	   )r   r*   r   r   r   r   r   h   s    z$SSLSocket.FakeConnection.__getattr__c                 G   s
   | j  ¡ S r	   )r*   Úshutdown)r   Zunused_argsr   r   r   r+   k   s    z!SSLSocket.FakeConnection.shutdownN)r   r   r   Ú__doc__r   r   r+   r   r   r   r   ÚFakeConnection`   s   r-   c              
   C   sÀ   | j  ¡ \}}t | j¡}| tj¡ | tj¡ | | j	¡ | j
d urT| | j
¡ |  t ||¡¡}| ¡  t d|¡ z| ¡  W n0 tjy¶ } zt |¡‚W Y d }~n
d }~0 0 ||fS )NzPerforming handshake with %s)r   Úacceptr   r"   r   r#   r$   r%   Zset_tlsext_servername_callbackr)   r   r&   r-   Ú
ConnectionZset_accept_stater    r!   Údo_handshakeÚErrorÚsocketÚerror)r   r   ZaddrÚcontextZssl_sockr3   r   r   r   r.   o   s    
 zSSLSocket.accept)r   r   r   r,   Ú_DEFAULT_SSL_METHODr   r   r)   Úobjectr-   r.   r   r   r   r   r   '   s   þ
r   i»  i,  )Ú r   c                 C   sD  t  |¡}| |¡ d|i}zJt d||t|ƒrDd |d |d ¡nd¡ ||f}	tj|	fi |¤Ž}
W n0 tj	y– } zt
 |¡‚W Y d}~n
d}~0 0 t |
¡ˆ}t  ||¡}| ¡  | | ¡ |durÔ| |¡ z| ¡  | ¡  W n2 t jy } zt
 |¡‚W Y d}~n
d}~0 0 W d  ƒ n1 s20    Y  | ¡ S )a  Probe SNI server for SSL certificate.

    :param bytes name: Byte string to send as the server name in the
        client hello message.
    :param bytes host: Host to connect to.
    :param int port: Port to connect to.
    :param int timeout: Timeout in seconds.
    :param method: See `OpenSSL.SSL.Context` for allowed values.
    :param tuple source_address: Enables multi-path probing (selection
        of source interface). See `socket.creation_connection` for more
        info. Available only in Python 2.7+.
    :param alpn_protocols: Protocols to request using ALPN.
    :type alpn_protocols: `list` of `bytes`

    :raises acme.errors.Error: In case of any problems.

    :returns: SSL certificate presented by the server.
    :rtype: OpenSSL.crypto.X509

    Úsource_addressz!Attempting to connect to %s:%d%s.z from {0}:{1}r   é   r7   N)r   r"   Zset_timeoutr    r!   ÚanyÚformatr2   Zcreate_connectionr3   r   r1   Ú
contextlibÚclosingr/   Zset_connect_stateZset_tlsext_host_nameZset_alpn_protosr0   r+   Zget_peer_certificate)r   ZhostZportZtimeoutr   r8   Zalpn_protocolsr4   Zsocket_kwargsZsocket_tupler   r3   ZclientZ
client_sslr   r   r   Ú	probe_sni‡   s:    

ýþû 

@r>   Fc                 C   s   t  t j| ¡}t  ¡ }t jddd dd„ |D ƒ¡ d¡dg}|rX| t jddd	d¡ | |¡ | 	|¡ | 
d
¡ | |d¡ t  t j|¡S )a©  Generate a CSR containing a list of domains as subjectAltNames.

    :param buffer private_key_pem: Private key, in PEM PKCS#8 format.
    :param list domains: List of DNS names to include in subjectAltNames of CSR.
    :param bool must_staple: Whether to include the TLS Feature extension (aka
        OCSP Must Staple: https://tools.ietf.org/html/rfc7633).
    :returns: buffer PEM-encoded Certificate Signing Request.
    ó   subjectAltNameFú, c                 s   s   | ]}d | V  qdS )zDNS:Nr   ©Ú.0Údr   r   r   Ú	<genexpr>Î   ó    zmake_csr.<locals>.<genexpr>Úascii©ZcriticalÚvalues   1.3.6.1.5.5.7.1.24s   DER:30:03:02:01:05r   Úsha256)r   Zload_privatekeyÚFILETYPE_PEMZX509ReqÚX509ExtensionÚjoinÚencodeÚappendÚadd_extensionsÚ
set_pubkeyÚset_versionÚsignÚdump_certificate_request)Zprivate_key_pemÚdomainsZmust_stapleZprivate_keyZcsrÚ
extensionsr   r   r   Úmake_csr¾   s.    	ÿýÿý


ÿrV   c                    s6   |   ¡ j‰ t| ƒ}ˆ d u r|S ˆ g‡ fdd„|D ƒ S )Nc                    s   g | ]}|ˆ kr|‘qS r   r   rA   ©Zcommon_namer   r   Ú
<listcomp>å   rE   z4_pyopenssl_cert_or_req_all_names.<locals>.<listcomp>)Úget_subjectÚCNÚ_pyopenssl_cert_or_req_san)Zloaded_cert_or_reqZsansr   rW   r   Ú _pyopenssl_cert_or_req_all_namesß   s
    
r\   c                    sx   d‰ d}dˆ  ‰t | tjƒr$tj}ntj}|tj| ƒ d¡}t d|¡}|du rTg n| 	d¡ 
|¡}‡ ‡fdd	„|D ƒS )
a¡  Get Subject Alternative Names from certificate or CSR using pyOpenSSL.

    .. todo:: Implement directly in PyOpenSSL!

    .. note:: Although this is `acme` internal API, it is used by
        `letsencrypt`.

    :param cert_or_req: Certificate or CSR.
    :type cert_or_req: `OpenSSL.crypto.X509` or `OpenSSL.crypto.X509Req`.

    :returns: A list of Subject Alternative Names.
    :rtype: `list` of `unicode`

    ú:r@   ZDNSzutf-8z5X509v3 Subject Alternative Name:(?: critical)?\s*(.*)Nr9   c                    s$   g | ]}|  ˆ¡r| ˆ ¡d  ‘qS )r9   )Ú
startswithÚsplit)rB   Úpart©Zpart_separatorÚprefixr   r   rX     s   ÿz._pyopenssl_cert_or_req_san.<locals>.<listcomp>)Ú
isinstancer   ÚX509Údump_certificaterS   ZFILETYPE_TEXTÚdecodeÚreÚsearchÚgroupr_   )Zcert_or_reqZparts_separatorÚfuncÚtextÚmatchZ
sans_partsr   ra   r   r[   è   s    ÿr[   é€:	 Tc              	   C   sð   |sJ dƒ‚t  ¡ }| tt t d¡¡dƒ¡ | d¡ |du rFg }| 	t  
ddd¡¡ |d | ¡ _| | ¡ ¡ |s†t|ƒd	kr¬| 	t j
d
dd dd„ |D ƒ¡d¡ | |¡ | |du rÆdn|¡ | |¡ | | ¡ | | d¡ |S )a*  Generate new self-signed certificate.

    :type domains: `list` of `unicode`
    :param OpenSSL.crypto.PKey key:
    :param bool force_san:
    :param extensions: List of additional extensions to include in the cert.
    :type extensions: `list` of `OpenSSL.crypto.X509Extension`

    If more than one domain is provided, all of the domains are put into
    ``subjectAltName`` X.509 extension and first domain is set as the
    subject CN. If only one domain is provided no ``subjectAltName``
    extension is used, unless `force_san` is ``True``.

    z0Must provide one or more hostnames for the cert.é   é   Ns   basicConstraintsTs   CA:TRUE, pathlen:0r   r9   r?   Fs   , c                 s   s   | ]}d |  ¡  V  qdS )s   DNS:N)rM   rA   r   r   r   rD   8  rE   zgen_ss_cert.<locals>.<genexpr>rG   rI   )r   rd   Zset_serial_numberÚintÚbinasciiZhexlifyÚosÚurandomrQ   rN   rK   rY   rZ   Z
set_issuerÚlenrL   rO   Zgmtime_adj_notBeforeZgmtime_adj_notAfterrP   rR   )r'   rT   Z
not_beforeZvalidityZ	force_sanrU   r(   r   r   r   Úgen_ss_cert  s2    
ÿÿý


ru   c                    s$   ‡fdd„‰ d  ‡ fdd„| D ƒ¡S )zØDump certificate chain into a bundle.

    :param list chain: List of `OpenSSL.crypto.X509` (or wrapped in
        :class:`josepy.util.ComparableX509`).

    :returns: certificate chain bundle
    :rtype: bytes

    c                    s   t | tjƒr| j} t ˆ | ¡S r	   )rc   ÚjoseZComparableX509Úwrappedr   re   )r(   )Úfiletyper   r   Ú
_dump_certR  s    z(dump_pyopenssl_chain.<locals>._dump_certrE   c                 3   s   | ]}ˆ |ƒV  qd S r	   r   )rB   r(   )ry   r   r   rD   Y  rE   z'dump_pyopenssl_chain.<locals>.<genexpr>)rL   )Úchainrx   r   )ry   rx   r   Údump_pyopenssl_chainE  s    r{   )F)Nrm   TN)!r,   rq   r<   Zloggingrr   rg   r2   Zjosepyrv   ZOpenSSLr   r   Zacmer   Zacme.magic_typingr   r   r   Z	getLoggerr   r    ZSSLv23_METHODr5   r6   r   r   r>   rV   r\   r[   ru   rJ   r{   r   r   r   r   Ú<module>   s8   
		`þ
7
!	+  ÿ
2