U
    g                     @   sh   d Z ddlZddlmZmZmZ ddlmZ ddlm	Z	 ddl
mZmZmZmZ dgZG d	d dZdS )
z
Module to handle the timestamping functionality in pyHanko.

Many PDF signature profiles require trusted timestamp tokens.
The tools in this module allow pyHanko to obtain such tokens from
:rfc:`3161`-compliant time stamping
authorities.
    N)algoscmstsp)CertificateValidator)SimpleCertificateStore   )dummy_digestextract_ts_certs	get_noncehandle_tsp_responseTimeStamperc                   @   sn   e Zd ZdZdddZdd Zdd Zd	d
 Zdd Ze	j
dddZejejdddZe	j
dddZdS )r   z
    .. versionchanged:: 0.9.0
        Made API more asyncio-friendly _(breaking change)_

    Class to make :rfc:`3161` timestamp requests.
    Tc                 C   s   i | _ i | _t | _|| _d S N)_dummy_response_cache_certsr   cert_registryinclude_nonce)selfr    r   ?/tmp/pip-unpacked-wheel-owvgwkas/pyhanko/sign/timestamps/api.py__init__"   s    zTimeStamper.__init__c                 C   sP   dt td|i|ddd}| jr>t }t||d< nd}|t |fS )a&  
        Format the body of an :rfc:`3161` request as a CMS object.
        Subclasses with more specific needs may want to override this.

        :param message_digest:
            Message digest to which the timestamp will apply.
        :param md_algorithm:
            Message digest algorithm to use.

            .. note::
                As per :rfc:`8933`, ``md_algorithm`` should also be the
                algorithm used to compute ``message_digest``.
        :return:
            An :class:`.asn1crypto.tsp.TimeStampReq` object.
        r   	algorithm)Zhash_algorithmZhashed_messageT)versionZmessage_imprintZcert_reqnonceN)	r   ZMessageImprintr   ZDigestAlgorithmr   r
   r   ZIntegerTimeStampReq)r   message_digestmd_algorithmreqr   r   r   r   request_cms(   s    	zTimeStamper.request_cmsc                   sL      I dH   fdd}t| j }t|D ]}|I dH V  q6dS )a+  
        Produce validation paths for the certificates gathered by this
        :class:`.TimeStamper`.

        This is internal API.

        :param validation_context:
            The validation context to apply.
        :return:
            An asynchronous generator of validation paths.
        Nc                    s    t |  jd}|t dhS )N)Zintermediate_certsvalidation_contextZtime_stamping)r   r   Zasync_validate_usageset)certZ	validatorr   r   r   r   _validation_jobZ   s    z5TimeStamper.validation_paths.<locals>._validation_job)_ensure_dummymapr   valuesasyncioZas_completed)r   r   r"   jobsZjobr   r!   r   validation_pathsL   s
    zTimeStamper.validation_pathsc                 C   s,   || j |< t|| jD ]}|| j|j< qd S r   )r   r	   r   r   Zissuer_serial)r   r   dummyr    r   r   r   _register_dummyg   s    
zTimeStamper._register_dummyc                    s&   | j s"ddlm} | |I d H  d S )Nr   )
DEFAULT_MD)r   Zpyhanko.signr+   async_dummy_response)r   r+   r   r   r   r#   l   s    zTimeStamper._ensure_dummy)returnc                    sH   z| j | W S  tk
r6   | t||I dH }Y nX | || |S )a9  
        Return a dummy response for use in CMS object size estimation.

        For every new ``md_algorithm`` passed in, this method will call
        the :meth:`timestamp` method exactly once, with a dummy digest.
        The resulting object will be cached and reused for future invocations
        of :meth:`dummy_response` with the same ``md_algorithm`` value.

        :param md_algorithm:
            Message digest algorithm to use.
        :return:
            A timestamp token, encoded as an
            :class:`.asn1crypto.cms.ContentInfo` object.
        N)r   KeyErrorasync_timestampr   r*   )r   r   r)   r   r   r   r,   s   s     z TimeStamper.async_dummy_response)r   r-   c                    s   t dS )aF  
        Submit the specified timestamp request to the server.

        :param req:
            Request body to submit.
        :return:
            A timestamp response from the server.
        :raises IOError:
            Raised in case of an I/O issue in the communication with the
            timestamping server.
        N)NotImplementedError)r   r   r   r   r   async_request_tsa_response   s    z&TimeStamper.async_request_tsa_responsec                    s*   |  ||\}}| |I dH }t||S )a+  
        Request a timestamp for the given message digest.

        :param message_digest:
            Message digest to which the timestamp will apply.
        :param md_algorithm:
            Message digest algorithm to use.

            .. note::
                As per :rfc:`8933`, ``md_algorithm`` should also be the
                algorithm used to compute ``message_digest``.
        :return:
            A timestamp token, encoded as an
            :class:`.asn1crypto.cms.ContentInfo` object.
        :raises IOError:
            Raised in case of an I/O issue in the communication with the
            timestamping server.
        :raises TimestampRequestError:
            Raised if the timestamp server did not return a success response,
            or if the server's response is invalid.
        N)r   r1   r   )r   r   r   r   r   resr   r   r   r/      s    zTimeStamper.async_timestampN)T)__name__
__module____qualname____doc__r   r   r(   r*   r#   r   ZContentInfor,   r   r   ZTimeStampRespr1   r/   r   r   r   r   r      s   
$)r6   r&   Z
asn1cryptor   r   r   Zpyhanko_certvalidatorr   Zpyhanko_certvalidator.registryr   Zcommon_utilsr   r	   r
   r   __all__r   r   r   r   r   <module>   s   	