o
    é~®`T6  ã                   @   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)Ú
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 tj|||tjtj¡S )zK
    Given a list of Python tuples, create an associated CFDictionary.
    c                 s   ó   � | ]}|d  V  qdS )r   Nr
   ©Ú.0Útr
   r
   r   Ú	<genexpr>,   ó   € z-_cf_dictionary_from_tuples.<locals>.<genexpr>c                 s   r   )r   Nr
   r   r
   r
   r   r   -   r   )r   r   Ú	CFTypeRefÚCFDictionaryCreater   ÚkCFTypeDictionaryKeyCallBacksÚkCFTypeDictionaryValueCallBacks)ÚtuplesÚdictionary_sizeÚkeysÚvaluesÚcf_keysÚ	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   ÚCFStringCreateWithCStringr   r   ÚkCFStringEncodingUTF8)Úpy_bstrÚc_strÚcf_strr
   r
   r   Ú_cfstr;   s   
ýr%   c              
   C   sª   d}z7t  t jdt t j¡¡}|stdƒ‚| D ]}t|ƒ}|s#tdƒ‚zt  ||¡ W t  	|¡ qt  	|¡ w W |S  t
yT } z|rHt  	|¡ t d|f ¡‚d}~ww )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%   ÚCFArrayAppendValueÚ	CFReleaseÚBaseExceptionÚsslÚSSLError)ÚlstÚcf_arrÚitemr$   Úer
   r
   r   Ú_create_cfstring_arrayI   s0   
ýùü
€ýr4   c                 C   sn   t  | t  t j¡¡}t |tj¡}|du r,t  d¡}t 	||dtj¡}|s)t
dƒ‚|j}|dur5| 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   ÚCFStringGetCStringPtrr   r!   Úcreate_string_bufferÚCFStringGetCStringÚOSErrorÚvalueÚdecode)r=   Úvalue_as_void_pÚstringÚbufferÚresultr
   r
   r   Ú_cf_string_to_unicodeh   s   ÿ

ÿ
rC   c                 C   sX   | dkrdS t  | d¡}t|ƒ}t |¡ |du s|dkr!d|  }|du r(tj}||ƒ‚)z[
    Checks the return code and throws an exception if there is an error to
    report
    r   NÚ zOSStatus %s)r   ÚSecCopyErrorMessageStringrC   r   r,   r.   r/   )ÚerrorÚexception_classÚcf_error_stringÚoutputr
   r
   r   Ú_assert_no_error�   s   
rJ   c                 C   sÖ   |   dd¡} dd„ t | ¡D ƒ}|st d¡‚t tjdt 	tj
¡¡}|s*t d¡‚z1|D ]+}t|ƒ}|s:t d¡‚t tj|¡}t |¡ |sMt d¡‚t ||¡ t |¡ q-W |S  tyj   t |¡ Y |S w )	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   ÚSecCertificateCreateWithDatar,   r+   Ú	Exception)Ú
pem_bundleÚ	der_certsÚ
cert_arrayÚ	der_bytesÚcertdataÚcertr
   r
   r   Ú_cert_array_from_pem–   s@   ÿ

ý

ÿ

ôúúr\   c                 C   ó   t  ¡ }t | ¡|kS )z=
    Returns True if a given CFTypeRef is a certificate.
    )r   ÚSecCertificateGetTypeIDr   ÚCFGetTypeID©r2   Úexpectedr
   r
   r   Ú_is_certÃ   ó   rb   c                 C   r]   )z;
    Returns True if a given CFTypeRef is an identity.
    )r   ÚSecIdentityGetTypeIDr   r_   r`   r
   r
   r   Ú_is_identityË   rc   re   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é   r5   F)ÚosÚurandomrL   Ú	b16encoder>   ÚtempfileÚmkdtempÚpathÚjoinÚencoder   ÚSecKeychainRefÚSecKeychainCreater   r   r(   rJ   )Úrandom_bytesÚfilenameÚpasswordÚtempdirectoryÚkeychain_pathÚkeychainÚstatusr
   r
   r   Ú_temporary_keychainÓ   s   
ÿry   c                 C   s*  g }g }d}t |dƒ�}| ¡ }W d  ƒ n1 sw   Y  zht tj|t|ƒ¡}t ¡ }t |ddddd| t	 
|¡¡}t|ƒ t |¡}	t|	ƒD ],}
t ||
¡}t	 |tj¡}t|ƒrht |¡ | |¡ qJt|ƒrvt |¡ | |¡ qJW |rt |¡ t |¡ ||fS |r�t |¡ t |¡ w )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   Ú
CFArrayRefr   ÚSecItemImportr   r(   rJ   ÚCFArrayGetCountÚrangeÚCFArrayGetValueAtIndexr6   r   rb   ÚCFRetainÚappendre   r,   )rw   rm   ÚcertificatesÚ
identitiesÚresult_arrayÚfÚraw_filedataÚfiledatarB   Úresult_countÚindexr2   r
   r
   r   Ú_load_items_from_fileö   sR   
ÿÿø




€÷

û
rŒ   c              
   G   s   g }g }dd„ |D ƒ}ze|D ]}t | |ƒ\}}| |¡ | |¡ q|sEt ¡ }t | |d t |¡¡}t|ƒ | |¡ t	 
| d¡¡ t	 t	jdt t	j¡¡}	t ||¡D ]}
t	 |	|
¡ qW|	W t ||¡D ]}t	 
|¡ qhS t ||¡D ]}t	 
|¡ qww )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   rm   r
   r
   r   r   Q  r   z*_load_client_cert_chain.<locals>.<genexpr>r   )rŒ   Úextendr   ÚSecIdentityRefÚ SecIdentityCreateWithCertificater   r(   rJ   rƒ   r   r,   Úpopr'   r   r)   Ú	itertoolsÚchainr+   )rw   Úpathsr„   r…   Ú	file_pathÚnew_identitiesÚ	new_certsÚnew_identityrx   Útrust_chainr2   Úobjr
   r
   r   Ú_load_client_cert_chain-  s:    
ÿ

ýÿÿr›   )r   é   )é   r   )r�   r   )r�   rœ   )r�   r�   )Ú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.
    rœ   é0   z>BBé   z>BBBH)ÚTLS_PROTOCOL_VERSIONSÚstructÚpackr   )	ÚversionÚver_majÚver_minÚseverity_fatalÚdescription_unknown_caÚmsgÚmsg_lenÚrecord_type_alertÚrecordr
   r
   r   Ú_build_tls_unknown_ca_alert�  s   r¯   r�   )Ú__doc__rL   r   r’   rh   Úrer.   r¤   rk   Úbindingsr   r   r   ÚcompileÚDOTALLrR   r   r   r%   r4   rC   rJ   r\   rb   re   ry   rŒ   r›   r£   r¯   r
   r
   r
   r   Ú<module>   s@    	ÿ

-#7Lû	