3
2X/                 @   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	m
Z
mZ ejdej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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   )SecurityCoreFoundationCFConsts;   -----BEGIN CERTIFICATE-----
(.*?)
-----END CERTIFICATE-----c             C   s   t j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	   L/usr/lib/python3/dist-packages/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j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
   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   sn   t j| t jt j}tj|tj}|dkrXt jd}tj	||dtj}|sRt
d|j}|dk	rj|j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 CFStringRefzutf-8)ctypescastZPOINTERZc_void_pr   ZCFStringGetCStringPtrr   ZkCFStringEncodingUTF8Zcreate_string_bufferZCFStringGetCStringOSErrorvaluedecode)r   Zvalue_as_void_pstringbufferresultr	   r	   r
   _cf_string_to_unicode;   s"    

r   c             C   s\   | dkrdS t j| d}t|}tj| |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SecCopyErrorMessageStringr   r   	CFReleasesslSSLError)errorZexception_classZcf_error_stringoutputr	   r	   r
   _assert_no_errorX   s    
r"   c             C   s   dd t j| D }|s"tjdtjtjdtjtj	}|sHtjdydx^|D ]V}t
|}|sjtjdtjtj|}tj| |stjdtj|| tj| qPW W n tk
r   tj| 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.
    c             S   s   g | ]}t j|jd qS )r   )base64Z	b64decodegroup)r   matchr	   r	   r
   
<listcomp>s   s   z(_cert_array_from_pem.<locals>.<listcomp>zNo root certificates specifiedr   zUnable to allocate memory!zUnable to build cert object!)_PEM_CERTS_REfinditerr   r   r   CFArrayCreateMutabler   r   byrefkCFTypeArrayCallBacksr   r   ZSecCertificateCreateWithDatar   CFArrayAppendValue	Exception)Z
pem_bundleZ	der_certsZ
cert_arrayZ	der_bytesZcertdataZcertr	   r	   r
   _cert_array_from_pemm   s2    






r.   c             C   s   t j }tj| |kS )z=
    Returns True if a given CFTypeRef is a certificate.
    )r   ZSecCertificateGetTypeIDr   CFGetTypeID)itemexpectedr	   r	   r
   _is_cert   s    r2   c             C   s   t j }tj| |kS )z;
    Returns True if a given CFTypeRef is an identity.
    )r   ZSecIdentityGetTypeIDr   r/   )r0   r1   r	   r	   r
   _is_identity   s    r3   c              C   s   t jd} tj| dd jd}tj| dd }tj }t jj||j	d}t
j }t
j|t||ddtj|}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   zutf-8F)osurandomr#   Z	b64encoder   tempfileZmkdtemppathjoinencoder   ZSecKeychainRefZSecKeychainCreater   r   r*   r"   )Zrandom_bytesfilenameZpasswordZtempdirectoryZkeychain_pathkeychainstatusr	   r	   r
   _temporary_keychain   s    
r?   c             C   s  g }g }d}t |d}|j }W dQ R X ztjtj|t|}tj }tj|ddddd| t	j
|}t| tj|}	xdt|	D ]X}
tj||
}t	j|tj}t|rtj| |j| qt|rtj| |j| qW W d|rtj| tj| 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   Z
CFArrayRefr   ZSecItemImportr   r*   r"   ZCFArrayGetCountrangeZCFArrayGetValueAtIndexr   r   r2   ZCFRetainappendr3   r   )r=   r9   certificates
identitiesZresult_arrayfZraw_filedataZfiledatar   Zresult_countindexr0   r	   r	   r
   _load_items_from_file   sH    




rI   c             G   s   g }g }dd |D }zx.|D ]&}t | |\}}|j| |j| qW |stj }tj| |d tj|}t| |j| t	j
|jd t	jt	jdtjt	j}	x tj||D ]}
t	j|	|
 qW |	S xtj||D ]}t	j
| qW 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   r9   r	   r	   r
   r   /  s    z*_load_client_cert_chain.<locals>.<genexpr>r   N)rI   extendr   ZSecIdentityRefZ SecIdentityCreateWithCertificater   r*   r"   rD   r   r   popr)   r   r+   	itertoolschainr,   )r=   pathsrE   rF   Z	file_pathZnew_identitiesZ	new_certsZnew_identityr>   Ztrust_chainr0   objr	   r	   r
   _load_client_cert_chain  s6     


rP   )N)__doc__r#   r   rL   rer6   r   r8   Zbindingsr   r   r   compileDOTALLr'   r   r   r   r"   r.   r2   r3   r?   rI   rP   r	   r	   r	   r
   <module>	   s(   


+(;