U
    ;gDV                     @   s`  d dl Z d dlZd dlmZ d dlmZmZmZmZm	Z	m
Z
 d dlmZ d dlmZ ddlmZmZ ddlmZ dd	lmZ dd
lmZ ddlmZmZ G dd de jZG dd dee jZG dd deZee
ejef  Z G dd dZ!G dd de!Z"G dd deZ#G dd dZ$G dd dZ%G dd dZ&G dd dee Z'G d d! d!eZ(dS )"    N)defaultdict)AsyncGeneratorIterableIteratorListOptionalUnion)x509)
trust_list   )CertTrustAnchorTrustAnchor)PathBuildingError)CertificateFetcher)ValidationPath)CancelableAsyncIteratorConsListc                   @   sD   e Zd ZdZedddZedddZejddd	Z	d
d Z
dS )CertificateCollectionzS
    Abstract base class for read-only access to a collection of certificates.
    key_identifierc                 C   s   |  |}|sdS |d S dS )z
        Retrieves a cert via its key identifier

        :param key_identifier:
            A byte string of the key identifier

        :return:
            None or an asn1crypto.x509.Certificate object
        Nr   )retrieve_many_by_key_identifier)selfr   
candidates r   B/tmp/pip-unpacked-wheel-hgp_x7fx/pyhanko_certvalidator/registry.pyretrieve_by_key_identifier   s    

z0CertificateCollection.retrieve_by_key_identifierc                 C   s   t dS )z
        Retrieves possibly multiple certs via the corresponding key identifiers

        :param key_identifier:
            A byte string of the key identifier

        :return:
            A list of asn1crypto.x509.Certificate objects
        NNotImplementedErrorr   r   r   r   r   r   '   s    
z5CertificateCollection.retrieve_many_by_key_identifiernamec                 C   s   t dS )z
        Retrieves a list certs via their subject name

        :param name:
            An asn1crypto.x509.Name object

        :return:
            A list of asn1crypto.x509.Certificate objects
        Nr   r   r    r   r   r   retrieve_by_name3   s    
z&CertificateCollection.retrieve_by_namec                 C   s   t dS )a]  
        Retrieve a certificate by its ``issuer_serial`` value.

        :param issuer_serial:
            The ``issuer_serial`` value of the certificate.
        :return:
            The certificate corresponding to the ``issuer_serial`` key
            passed in.
        :return:
            None or an asn1crypto.x509.Certificate object
        Nr   r   issuer_serialr   r   r   retrieve_by_issuer_serial?   s    z/CertificateCollection.retrieve_by_issuer_serialN)__name__
__module____qualname____doc__bytesr   r   r	   Namer"   r%   r   r   r   r   r      s
   r   c                   @   s:   e Zd ZejedddZeej dddZdd Z	d	S )
CertificateStorecertreturnc                 C   s   t dS )
        Register a single certificate.

        :param cert:
            Certificate to add.
        :return:
            ``True`` if the certificate was added, ``False`` if it already
            existed in this store.
        Nr   r   r.   r   r   r   registerO   s    
zCertificateStore.registercertsc                 C   s    d}|D ]}||  |O }q|S )a  
        Register multiple certificates.

        :param certs:
            Certificates to register.
        :return:
            ``True`` if at least one certificate was added, ``False``
            if all certificates already existed in this store.
        Fr2   )r   r4   addedr.   r   r   r   register_multiple[   s    z"CertificateStore.register_multiplec                 C   s   t d S Nr   r   r   r   r   __iter__k   s    zCertificateStore.__iter__N)
r&   r'   r(   r	   Certificateboolr2   r   r7   r:   r   r   r   r   r,   N   s   r,   c                   @   sl   e Zd ZdZedd Zdd Zeje	dddZ
d	d
 Zdd ZedddZejdddZdd ZdS )SimpleCertificateStorez-
    Simple trustless certificate store.
    c                 C   s   |  }|D ]}| | q
|S r8   r5   )clsr4   resultr.   r   r   r   
from_certst   s    z!SimpleCertificateStore.from_certsc                 C   s   i | _ tt| _tt| _d S r8   )r4   r   list_subject_map_key_identifier_mapr9   r   r   r   __init__{   s    
zSimpleCertificateStore.__init__r-   c                 C   sb   |j | jkrdS || j|j < | j|jj | |jrJ| j|j | n| j|jj	 | dS )r0   FT)
r$   r4   rB   subjecthashableappendr   rC   
public_keysha1r1   r   r   r   r2      s    
zSimpleCertificateStore.registerc                 C   s
   | j | S r8   r3   )r   itemr   r   r   __getitem__   s    z"SimpleCertificateStore.__getitem__c                 C   s   t | j S r8   )iterr4   valuesr9   r   r   r   r:      s    zSimpleCertificateStore.__iter__r   c                 C   s
   | j | S r8   )rC   r   r   r   r   r      s    z6SimpleCertificateStore.retrieve_many_by_key_identifierr   c                 C   s   | j |j S r8   )rB   rF   r!   r   r   r   r"      s    z'SimpleCertificateStore.retrieve_by_namec                 C   s&   z
| | W S  t k
r    Y d S X d S r8   )KeyErrorr#   r   r   r   r%      s    
z0SimpleCertificateStore.retrieve_by_issuer_serialN)r&   r'   r(   r)   classmethodr@   rD   r	   r;   r<   r2   rK   r:   r*   r   r+   r"   r%   r   r   r   r   r=   o   s   
r=   c                   @   s8   e Zd ZdZejedddZejee	 dddZ
dS )TrustManagerz%
    Abstract trust manager API.
    r-   c                 C   s   t dS )
        Checks if a certificate is in the list of trust roots in this registry

        :param cert:
            An asn1crypto.x509.Certificate object

        :return:
            A boolean - if the certificate is in the CA list
        Nr   r1   r   r   r   is_root   s    
zTrustManager.is_rootc                 C   s   t dS )z
        Find potential issuers that might have (directly) issued
        a particular certificate.

        :param cert:
            Issued certificate.
        :return:
            An iterator with potentially relevant trust anchors.
        Nr   r1   r   r   r   find_potential_issuers   s    z#TrustManager.find_potential_issuersN)r&   r'   r(   r)   r	   r;   r<   rR   r   r   rS   r   r   r   r   rP      s
   rP   c                   @   s   e Zd ZdZdd Zedee ee d dddZe	e
ejf dd	d
ZejdddZeej dddZejee
 dddZdS )SimpleTrustManagerzk
    Trust manager backed by a list of trust roots, possibly in addition to the
    system trust list.
    c                 C   s   t  | _tt| _d S r8   )set_rootsr   rA   _root_subject_mapr9   r   r   r   rD      s    zSimpleTrustManager.__init__N)trust_rootsextra_trust_rootsr/   c                 C   sT   |dkrdd t  D }nt|}|dk	r6|| t }|D ]}|| q@|S )a  
        :param trust_roots:
            If the operating system's trust list should not be used, instead
            pass a list of asn1crypto.x509.Certificate objects. These
            certificates will be used as the trust roots for the path being
            built.

        :param extra_trust_roots:
            If the operating system's trust list should be used, but augmented
            with one or more extra certificates. This should be a list of
            asn1crypto.x509.Certificate objects.
        :return:
        Nc                 S   s   g | ]}|d  qS )r   r   ).0er   r   r   
<listcomp>   s     z,SimpleTrustManager.build.<locals>.<listcomp>)r
   Zget_listrA   extendrT   _register_root)r>   rX   rY   manager
trust_rootr   r   r   build   s    
zSimpleTrustManager.build)r`   c                 C   sL   t |tr|}nt|}|| jkrH|j}| j| | j|jj 	| d S r8   )

isinstancer   r   rV   	authorityaddrW   r    rF   rG   )r   r`   anchorrc   r   r   r   r^      s    

z!SimpleTrustManager._register_rootr.   c                 C   s   t || jkS )rQ   )r   rV   r1   r   r   r   rR      s    zSimpleTrustManager.is_rootr/   c                 C   s   dd | j D S )Nc                 s   s   | ]}t |tr|jV  qd S r8   )rb   r   certificate)rZ   rootr   r   r   	<genexpr>  s   
z0SimpleTrustManager.iter_certs.<locals>.<genexpr>)rV   r9   r   r   r   
iter_certs  s    zSimpleTrustManager.iter_certsr-   c                 c   s.   |j j}| j| D ]}|j|r|V  qd S r8   )issuerrF   rW   rc   Zis_potential_issuer_of)r   r.   issuer_hashableri   r   r   r   rS     s    z)SimpleTrustManager.find_potential_issuers)NN)r&   r'   r(   r)   rD   rO   r   TrustRootListra   r   r   r	   r;   r^   rR   r   rk   rS   r   r   r   r   rT      s      
rT   c                       s   e Zd ZdZddee d fddZedddee	j
 ee ddd	Zde	jee	j
 d
 fddZe	j
eeeee	j
f  dddZe	j
dddZ  ZS )CertificateRegistryz
    Contains certificate lists used to build validation paths, and
    is also capable of fetching missing certificates if a certificate
    fetcher is supplied.
    Ncert_fetcherc                   s   t    || _d S r8   )superrD   fetcher)r   rq   	__class__r   r   rD   #  s    
zCertificateRegistry.__init__r   )r4   rq   c                C   s(   | |d}|D ]}| | q||_|S )a  
        Convenience method to set up a certificate registry and import
        certs into it.

        :param certs:
            Initial list of certificates to import.
        :param cert_fetcher:
            Certificate fetcher to handle retrieval of missing certificates
            (in situations where that is possible).
        :return:
            A populated certificate registry.
        rp   )r2   rs   )r>   r4   rq   r?   r.   r   r   r   ra   '  s
    
zCertificateRegistry.build)r    first_certificatec                    sN   g }d}t  |D ]$}|r.|j|jkr.|}q|| q|rJ|d| |S )af  
        Retrieves a list certs via their subject name

        :param name:
            An asn1crypto.x509.Name object

        :param first_certificate:
            An asn1crypto.x509.Certificate object that if found, should be
            placed first in the result list

        :return:
            A list of asn1crypto.x509.Certificate objects
        Nr   )rr   r"   sha256rG   insert)r   r    rv   outputfirstr.   rt   r   r   r"   B  s    z$CertificateRegistry.retrieve_by_name)r.   trust_managerr/   c                 c   sn   |j j}||E d H  | j| D ]F}||r2q"|jrN|jrN|j|jkrbq"n|jrb|j|jkrbq"|V  q"d S r8   )	rl   rF   rS   rB   rR   Zauthority_key_identifierr   Zauthority_issuer_serialr$   )r   r.   r{   rm   rl   r   r   r   rS   `  s    
z*CertificateRegistry.find_potential_issuersrf   c                 C  sH   | j d krd S dd | j |2 I d H }| | |D ]
}|V  q8d S )Nc                    s   g | z3 d H W }|q6 S r8   r   )rZ   rl   r   r   r   r\   |  s    zGCertificateRegistry.fetch_missing_potential_issuers.<locals>.<listcomp>)rs   Zfetch_cert_issuersr7   )r   r.   Zissuersrl   r   r   r   fetch_missing_potential_issuersx  s    


z3CertificateRegistry.fetch_missing_potential_issuers)r   )N)r&   r'   r(   r)   r   r   rD   rO   r   r	   r;   ra   r+   r"   rP   r   r   r   rS   r|   __classcell__r   r   rt   r   ro     s(      ro   c                   @   sN   e Zd ZdZeedddZdd Zej	ddd	Z
ej	ee d
ddZdS )PathBuilderz(
    Class to handle path building.
    r{   registryc                 C   s   || _ || _d S r8   r   )r   r{   r   r   r   r   rD     s    zPathBuilder.__init__c                 C   s   t | |S )a  
        Builds a list of ValidationPath objects from a certificate in the
        operating system trust store to the end-entity certificate

        .. note::
            This is a synchronous equivalent of :meth:`async_build_paths`
            that calls the latter in a new event loop. As such, it can't be used
            from within asynchronous code.

        :param end_entity_cert:
            A byte string of a DER or PEM-encoded X.509 certificate, or an
            instance of asn1crypto.x509.Certificate

        :return:
            A list of pyhanko_certvalidator.path.ValidationPath objects that
            represent the possible paths from the end-entity certificate to one
            of the CA certs.
        )asynciorunasync_build_paths)r   end_entity_certr   r   r   build_paths  s    zPathBuilder.build_paths)r   c                    s,   g }|  |2 z3 dH W }|| q6 |S )a1  
        Builds a list of ValidationPath objects from a certificate in the
        operating system trust store to the end-entity certificate, returning
        all paths in a single list.

        :param end_entity_cert:
            A byte string of a DER or PEM-encoded X.509 certificate, or an
            instance of asn1crypto.x509.Certificate

        :return:
            A list of pyhanko_certvalidator.path.ValidationPath objects that
            represent the possible paths from the end-entity certificate to one
            of the CA certs.
        N)async_build_paths_lazyrG   )r   r   pathsr?   r   r   r   r     s    zPathBuilder.async_build_paths)r   r/   c                 C   s(   t | t|t|jg d}t||S )a  
        Builds a list of ValidationPath objects from a certificate in the
        operating system trust store to the end-entity certificate, and emit
        them as an asynchronous generator.

        :param end_entity_cert:
            A byte string of a DER or PEM-encoded X.509 certificate, or an
            instance of asn1crypto.x509.Certificate

        :return:
            An asynchronous iterator that yields
            pyhanko_certvalidator.path.ValidationPath objects that
            represent the possible paths from the end-entity certificate to one
            of the CA certs, and raises PathBuildingError
            if no paths could be built
        )path
certs_seenfailed_paths)_PathWalkerr   Zsingr$   LazyPathIterator)r   r   walkerr   r   r   r     s    
z"PathBuilder.async_build_paths_lazyN)r&   r'   r(   r)   rP   ro   rD   r   r	   r;   r   r   r   r   r   r   r   r   r~     s    r~   c                   @   sx   e Zd Zdejee dddZedd Z	dd Z
d	d
 Zeeejf dddZeeejf dddZdd ZdS )_IssuerFetcherr~   )path_builderr.   r   c                 C   sL   || _ || _|| _| jj|| jj}t|| _d| _d| _	d | _
d| _d S )Nr   F)r.   r   r   r   rS   r{   rL   local_iss_iterlocal_issuers_foundfetched_issuers_found_fetched_cas_fetching_done)r   r   r.   r   Zlocal_issuersr   r   r   rD     s     
z_IssuerFetcher.__init__c                 C   s   | j | j S r8   )r   r   r9   r   r   r   issuers_found  s    z_IssuerFetcher.issuers_foundc                 C   s   | S r8   r   r9   r   r   r   	__aiter__  s    z_IssuerFetcher.__aiter__c                 C   s   | S r8   r   r9   r   r   r   r:     s    z_IssuerFetcher.__iter__rg   c                 C   sF   | j D ]6}t|tjr(|j}|| jkr(q|  jd7  _|  S td S )Nr   )r   rb   r	   r;   r$   r   r   StopIterationr   rl   Zcert_idr   r   r   __next__  s    

z_IssuerFetcher.__next__c                    s   z
t | W S  tk
r   Y nX | jd krH| jsH| jsH| jj| j| _| jd k	r| j2 z23 d H W }|j	}|| j
krvqX|  jd7  _|  S 6 d| _td S )Nr   T)nextr   r   r   r   r   r   r|   r.   r$   r   r   StopAsyncIterationr   r   r   r   	__anext__  s.    



z_IssuerFetcher.__anext__c                    s*   | j d k	r&| j  I d H  d | _ d| _d S )NT)r   acloser   r9   r   r   r   cancel  s    
z_IssuerFetcher.cancelN)r&   r'   r(   r	   r;   r   r*   rD   propertyr   r   r:   r   r   r   r   r   r   r   r   r   r     s   

r   c                   @   sL   e Zd Zdeej ee eeej  dddZdd Z	dd Z
d	d
 ZdS )r   r~   )r   r   r   r   c                 C   sF   || _ || _|| _|j}t|tjs(tt|||| _	|| _
d | _d S r8   )r   r   r   headrb   r	   r;   AssertionErrorr   _issuer_fetcherr   _next_level)r   r   r   r   r   r.   r   r   r   rD   %  s    z_PathWalker.__init__c                    sD   | j d k	r | j  I d H  d | _ | jd k	r@| j I d H  d | _d S r8   )r   r   r   r9   r   r   r   r   5  s    

z_PathWalker.cancelc                 C   s   | S r8   r   r9   r   r   r   r   =  s    z_PathWalker.__aiter__c              
      s  | j d krtd }|d kr| jd krz| j  I d H }W nB tk
r| } z$| j jsb| j| j d | _ |W 5 d }~X Y nX t|t	rt
| j}t||d d |d S t| j| j|| j|j| j| _z| j I d H }W q tk
r    d | _Y qX q|S )N)r   r   r   r   r   r   rG   r   rb   r   rA   r   r   r   Zconsr   r$   )r   	next_pathZnext_issuerr[   r4   r   r   r   r   @  s4    





z_PathWalker.__anext__N)r&   r'   r(   r   r	   r;   r*   r   rD   r   r   r   r   r   r   r   r   $  s   r   c                   @   sN   e Zd ZU dZee ed< eej	dddZ
dd Zdd	 Zed
ddZdS )r   N_as_root)r   r.   c                 C   s:   |j j|r tt|g d | _|| _d| _|jj	| _
d S )Nr   )r   r{   rR   r   r   r   _walkeremitted_countrE   human_friendly_name)r   r   r.   r   r   r   rD   f  s
    zLazyPathIterator.__init__c                    s   | j d k	r| j  I d H  d S r8   )r   r   r9   r   r   r   r   n  s    
zLazyPathIterator.cancelc                 C   s   | S r8   r   r9   r   r   r   r   r  s    zLazyPathIterator.__aiter__rg   c                    s   | j d krtn$| jd k	r4|  jd7  _d | _ | jS z$| j  I d H }|  jd7  _|W S  tk
rl   Y nX | jdkr| j jd j}t|tj	st
|jj}d | _ td| j d| dtd S )Nr   r   z7Unable to build a validation path for the certificate "z" - no issuer matching "z" was found)r   r   r   r   r   r   r   rb   r	   r;   r   rl   r   r   r   )r   r   Z	path_headZmissing_issuer_namer   r   r   r   u  s*    


zLazyPathIterator.__anext__)r&   r'   r(   r   r   r   __annotations__r   r	   r;   rD   r   r   r   r   r   r   r   r   c  s
   
r   c                   @   sH   e Zd ZdZee dddZedddZe	j
dd	d
Zdd ZdS )LayeredCertificateStorezi
    Trustless certificate store that looks up certificates in other stores
    in a specific order.
    )storesc                 C   s
   || _ d S r8   )_stores)r   r   r   r   r   rD     s    z LayeredCertificateStore.__init__r   c                    s    fdd}t | S )Nc                  3   s    j D ]} |  E d H  qd S r8   )r   r   storer   r   r   r   _gen  s    
zELayeredCertificateStore.retrieve_many_by_key_identifier.<locals>._genrA   )r   r   r   r   r   r   r     s    z7LayeredCertificateStore.retrieve_many_by_key_identifierr   c                    s    fdd}t | S )Nc                  3   s    j D ]} |  E d H  qd S r8   )r   r"   r   r    r   r   r   r     s    
z6LayeredCertificateStore.retrieve_by_name.<locals>._genr   )r   r    r   r   r   r   r"     s    z(LayeredCertificateStore.retrieve_by_namec                 C   s*   | j D ]}||}|d k	r|  S qd S r8   )r   r%   )r   r$   r   r?   r   r   r   r%     s
    


z1LayeredCertificateStore.retrieve_by_issuer_serialN)r&   r'   r(   r)   r   r   rD   r*   r   r	   r+   r"   r%   r   r   r   r   r     s
   r   ))abcr   collectionsr   typingr   r   r   r   r   r   Z
asn1cryptor	   Zoscryptor
   rc   r   r   errorsr   Zfetchersr   r   r   utilr   r   ABCr   r,   r=   r;   rn   rP   rT   ro   r~   r   r   r   r   r   r   r   r   <module>   s,    <!8 RiSL?.