U
    Òøïcb6  ã                   @   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Zddl	m
Z
mZmZ e dej¡Zdd„ Zdd	„ Zd
d„ Zdd„ Zdd„ Zd&dd„Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zddd d!d"d#œZd$d%„ ZdS )'a¦  
Low-level helpers for the SecureTransport bindings.

These are Python functions that are not directly related to the high-level APIs
but are necessary to get them to work. They include a whole bunch of low-level
CoreFoundation messing about and memory management. The concerns in this module
are almost entirely about trying to avoid memory leaks and providing
appropriate and useful assistance to the higher-level code.
é    Né   )ÚCFConstÚCoreFoundationÚSecuritys;   -----BEGIN CERTIFICATE-----
(.*?)
-----END CERTIFICATE-----c                 C   s   t  t j| t| ƒ¡S )zv
    Given a bytestring, create a CFData object from it. This CFData object must
    be CFReleased by the caller.
    )r   ÚCFDataCreateÚkCFAllocatorDefaultÚlen)Z
bytestring© r	   úN/tmp/pip-unpacked-wheel-sfguo0ou/urllib3/contrib/_securetransport/low_level.pyÚ_cf_data_from_bytes   s
      ÿr   c                 C   sZ   t | ƒ}dd„ | D ƒ}dd„ | D ƒ}tj| |Ž }tj| |Ž }t tj|||tjtj¡S )zK
    Given a list of Python tuples, create an associated CFDictionary.
    c                 s   s   | ]}|d  V  qdS )r   Nr	   ©Ú.0Útr	   r	   r
   Ú	<genexpr>,   s     z-_cf_dictionary_from_tuples.<locals>.<genexpr>c                 s   s   | ]}|d  V  qdS )r   Nr	   r   r	   r	   r
   r   -   s     )r   r   Ú	CFTypeRefZCFDictionaryCreater   ZkCFTypeDictionaryKeyCallBacksZkCFTypeDictionaryValueCallBacks)ZtuplesZdictionary_sizeÚkeysÚvaluesZcf_keysZ	cf_valuesr	   r	   r
   Ú_cf_dictionary_from_tuples%   s    úr   c                 C   s    t  | ¡}t tj|tj¡}|S )zi
    Given a Python binary data, create a CFString.
    The string must be CFReleased by the caller.
    )ÚctypesÚc_char_pr   ZCFStringCreateWithCStringr   r   ÚkCFStringEncodingUTF8)Zpy_bstrZc_strÚcf_strr	   r	   r
   Ú_cfstr;   s    
ýr   c              
   C   s®   d}zdt  t jdt t j¡¡}|s*tdƒ‚| D ]6}t|ƒ}|sFtdƒ‚zt  	||¡ W 5 t  |¡ X q.W n@ t
k
r¨ } z"|rˆt  |¡ t d|f ¡‚W 5 d}~X Y nX |S )zª
    Given a list of Python binary data, create an associated CFMutableArray.
    The array must be CFReleased by the caller.

    Raises an ssl.SSLError on failure.
    Nr   úUnable to allocate memory!zUnable to allocate array: %s)r   ÚCFArrayCreateMutabler   r   ÚbyrefÚkCFTypeArrayCallBacksÚMemoryErrorr   Ú	CFReleaseÚCFArrayAppendValueÚBaseExceptionÚsslÚSSLError)ÚlstZcf_arrÚitemr   Úer	   r	   r
   Ú_create_cfstring_arrayI   s*    
ý
"r&   c                 C   sn   t  | t  t j¡¡}t |tj¡}|dkrXt  d¡}t 	||dtj¡}|sRt
dƒ‚|j}|dk	rj| d¡}|S )z¨
    Creates a Unicode string from a CFString object. Used entirely for error
    reporting.

    Yes, it annoys me quite a lot that this function is this complex.
    Ni   z'Error copying C string from CFStringRefúutf-8)r   ÚcastÚPOINTERÚc_void_pr   ZCFStringGetCStringPtrr   r   Úcreate_string_bufferZCFStringGetCStringÚOSErrorÚvalueÚdecode)r-   Zvalue_as_void_pÚstringÚbufferÚresultr	   r	   r
   Ú_cf_string_to_unicodeh   s&     ÿ
   ÿ
r2   c                 C   s\   | dkrdS t  | d¡}t|ƒ}t |¡ |dks:|dkrBd|  }|dkrPtj}||ƒ‚dS )z[
    Checks the return code and throws an exception if there is an error to
    report
    r   NÚ zOSStatus %s)r   ZSecCopyErrorMessageStringr2   r   r   r!   r"   )ÚerrorZexception_classZcf_error_stringÚoutputr	   r	   r
   Ú_assert_no_error   s    
r6   c                 C   sÚ   |   dd¡} dd„ t | ¡D ƒ}|s.t d¡‚t tjdt 	tj
¡¡}|sTt d¡‚z`|D ]V}t|ƒ}|stt d¡‚t tj|¡}t |¡ |sšt d¡‚t ||¡ t |¡ qZW n  tk
rÔ   t |¡ ‚ Y nX |S )	z‚
    Given a bundle of certs in PEM format, turns them into a CFArray of certs
    that can be used to validate a cert chain.
    s   
ó   
c                 S   s   g | ]}t  | d ¡¡‘qS )r   )Úbase64Ú	b64decodeÚgroup)r   Úmatchr	   r	   r
   Ú
<listcomp>ž   s    z(_cert_array_from_pem.<locals>.<listcomp>zNo root certificates specifiedr   r   zUnable to build cert object!)ÚreplaceÚ_PEM_CERTS_REÚfinditerr!   r"   r   r   r   r   r   r   r   r   ZSecCertificateCreateWithDatar   r   Ú	Exception)Z
pem_bundleZ	der_certsZ
cert_arrayZ	der_bytesZcertdataÚcertr	   r	   r
   Ú_cert_array_from_pem–   s>    ÿ

ý

 ÿ


rB   c                 C   s   t  ¡ }t | ¡|kS )z=
    Returns True if a given CFTypeRef is a certificate.
    )r   ZSecCertificateGetTypeIDr   ÚCFGetTypeID©r$   Úexpectedr	   r	   r
   Ú_is_certÄ   s    rF   c                 C   s   t  ¡ }t | ¡|kS )z;
    Returns True if a given CFTypeRef is an identity.
    )r   ZSecIdentityGetTypeIDr   rC   rD   r	   r	   r
   Ú_is_identityÌ   s    rG   c               
   C   s†   t  d¡} t | dd… ¡ d¡}t | dd… ¡}t ¡ }t j ||¡ 	d¡}t
 ¡ }t
 |t|ƒ|ddt |¡¡}t|ƒ ||fS )a³  
    This function creates a temporary Mac keychain that we can use to work with
    credentials. This keychain uses a one-time password and a temporary file to
    store the data. We expect to have one keychain per socket. The returned
    SecKeychainRef must be freed by the caller, including calling
    SecKeychainDelete.

    Returns a tuple of the SecKeychainRef and the path to the temporary
    directory that contains it.
    é(   Né   r'   F)ÚosÚurandomr8   Ú	b16encoder.   ÚtempfileÚmkdtempÚpathÚjoinÚencoder   ZSecKeychainRefZSecKeychainCreater   r   r   r6   )Zrandom_bytesÚfilenameÚpasswordZtempdirectoryZkeychain_pathÚkeychainÚstatusr	   r	   r
   Ú_temporary_keychainÔ   s     
     ÿrV   c                 C   s   g }g }d}t |dƒ}| ¡ }W 5 Q R X z²t tj|t|ƒ¡}t ¡ }t 	|ddddd| t
 |¡¡}t|ƒ t |¡}	t|	ƒD ]X}
t ||
¡}t
 |tj¡}t|ƒr¼t |¡ | |¡ q€t|ƒr€t |¡ | |¡ q€W 5 |rìt |¡ t |¡ X ||fS )zÊ
    Given a single file, loads all the trust objects from it into arrays and
    the keychain.
    Returns a tuple of lists: the first list is a list of identities, the
    second a list of certs.
    NÚrbr   )ÚopenÚreadr   r   r   r   r   Z
CFArrayRefr   ZSecItemImportr   r   r6   ZCFArrayGetCountÚrangeZCFArrayGetValueAtIndexr(   r   rF   ZCFRetainÚappendrG   )rT   rO   ÚcertificatesÚ
identitiesZresult_arrayÚfZraw_filedataZfiledatar1   Zresult_countÚindexr$   r	   r	   r
   Ú_load_items_from_file÷   sJ      ÿø




r`   c              
   G   sê   g }g }dd„ |D ƒ}z°|D ]&}t| |ƒ\}}| |¡ | |¡ q|sŠt ¡ }t | |d t	 
|¡¡}	t|	ƒ | |¡ t | d¡¡ t tjdt	 
tj¡¡}
t  ||¡D ]}t |
|¡ q®|
W ¢S t  ||¡D ]}t |¡ qÔX dS )zü
    Load certificates and maybe keys from a number of files. Has the end goal
    of returning a CFArray containing one SecIdentityRef, and then zero or more
    SecCertificateRef objects, suitable for use as a client certificate trust
    chain.
    c                 s   s   | ]}|r|V  qd S )Nr	   )r   rO   r	   r	   r
   r   R  s      z*_load_client_cert_chain.<locals>.<genexpr>r   N)Ú	itertoolsÚchainr   r   r`   Úextendr   ZSecIdentityRefZ SecIdentityCreateWithCertificater   r   r6   r[   Úpopr   r   r   r   )rT   Úpathsr\   r]   ÚobjÚ	file_pathZnew_identitiesZ	new_certsZnew_identityrU   Ztrust_chainr$   r	   r	   r
   Ú_load_client_cert_chain.  s8     
  ÿ

ýrh   )r   é   )é   r   )rj   r   )rj   ri   )rj   rj   )ZSSLv2ÚSSLv3ÚTLSv1zTLSv1.1zTLSv1.2c           	      C   sH   t |  \}}d}d}t d||¡}t|ƒ}d}t d||||¡| }|S )z6
    Builds a TLS alert record for an unknown CA.
    ri   é0   z>BBé   z>BBBH)ÚTLS_PROTOCOL_VERSIONSÚstructÚpackr   )	ÚversionZver_majZver_minZseverity_fatalZdescription_unknown_caÚmsgZmsg_lenZrecord_type_alertÚrecordr	   r	   r
   Ú_build_tls_unknown_ca_alert‚  s    ru   )N)Ú__doc__r8   r   ra   rJ   Úrer!   rp   rM   Zbindingsr   r   r   ÚcompileÚDOTALLr>   r   r   r   r&   r2   r6   rB   rF   rG   rV   r`   rh   ro   ru   r	   r	   r	   r
   Ú<module>   s@   	 ÿ

.#7Lû	