U
    ^Ph`                     @   s  d dl Z d dl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 d d	lmZ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  d dl!m"Z" ddl#m$Z$ ddl%m&Z&m'Z' ddl(m)Z) dddddgZ*ddl+m,Z, ddl-m.Z. e/e0Z1eG dd dZ2dd Z3G d d dZ4d'e)ed"d#dZ5d!d$d!dd!ej6d$fe)ee7d%d&dZ8dS )(    N)	dataclass)field)IterableOptional)crl)ocsp)x509)Certificate)CertificateValidatorValidationContext)ValidationPath)genericmisc)pdf_name)IncrementalPdfFileWriter)get_and_apply)
PdfHandler)BasePdfFileWriter   )extract_certificate_info   )NoDSSFoundErrorValidationInfoReadingError)EmbeddedPdfSignatureVRIDocumentSecurityStoreasync_add_validation_infocollect_validation_infoenumerate_ocsp_certs   )SerialisedCredential)PdfFileReaderc                   @   sX   e Zd ZU dZeedZeed< eedZeed< eedZ	eed< e
jdddZd	S )
r   aA  
    VRI dictionary as defined in PAdES / ISO 32000-2.
    These dictionaries collect data that may be relevant for the validation of
    a specific signature.

    .. note::
        The data are stored as PDF indirect objects, not asn1crypto values.
        In particular, values are tied to a specific PDF handler.
    )default_factorycertsocspscrlsreturnc                 C   sb   t tdtdi}| jr0t | j|td< | jrJt | j|td< t | j|td< |S )zT
        :return:
            A PDF dictionary representing this VRI entry.
        z/Type/VRIz/OCSPz/CRLz/Cert)r   DictionaryObjectr   r$   ArrayObjectr%   r#   )selfvri r-   N/var/www/ecomprj/mb/lib/python3.8/site-packages/pyhanko/sign/validation/dss.pyas_pdf_objectB   s    zVRI.as_pdf_objectN)__name__
__module____qualname____doc__
data_fieldsetr#   __annotations__r$   r%   r   r)   r/   r-   r-   r-   r.   r   '   s
   

c                 c   sD   | d j }|dkr@| d }|d j dkr@|d j}|d E dH  dS )	zJ
    Essentially nabbed from _extract_ocsp_certs in ValidationContext
    Zresponse_statusZ
successfulresponse_bytesZresponse_typeZbasic_ocsp_responseresponser#   N)nativeparsed)Zocsp_responsestatusr7   r8   r-   r-   r.   r   P   s    

c                   @   s  e Zd ZdZd*ee dddZedd Zdd	 Z	d
d Z
dd Zdd ZeejdddZddddddZdd Zeej dddZd+edddZeed ddd Zeddddddd!eed d"d#d$Zedddddd%dddd&	eeee ed'd(d)ZdS ),r   z,
    Representation of a DSS in Python.
    Nwriterc                 C   s   |d k	r|ni | _ |d k	r|ni | _|d k	r0|ng | _|d k	rB|ng | _|| _|d k	rZ|nt | _i }| jD ]}| j	}	|||	< qn|| _
i }
| jD ]}| j	}||
|< q|
| _d| _d S )NF)vri_entriesr#   r$   r%   r=   r   r)   backing_pdf_object
get_objectdata_ocsps_seen
_crls_seen	_modified)r+   r=   r#   r$   r%   r>   r?   Z
ocsps_seenocsp_refZ
ocsp_bytesZ	crls_seencrl_refZ	crl_bytesr-   r-   r.   __init__b   s(    	





zDocumentSecurityStore.__init__c                 C   s   | j S N)rD   r+   r-   r-   r.   modified   s    zDocumentSecurityStore.modifiedc                 C   s(   | j s$d| _ | jd k	r$| j| j d S )NT)rD   r?   r=   Zupdate_containerrI   r-   r-   r.   _mark_modified   s    
z$DocumentSecurityStore._mark_modifiedc              	   c   sn   |D ]d}|  }z|| V  W q tk
rf   | jtj|d}|   |||< || |V  Y qX qd S )NZstream_data)dumpKeyErrorr=   
add_objectr   StreamObjectrK   append)r+   ZobjsseendestobjZ	obj_bytesrefr-   r-   r.   _cms_objects_to_streams   s    

z-DocumentSecurityStore._cms_objects_to_streamsc                    s     fdd}fdd| D S )Nc                  3   s    D ]} t | E d H  qd S rH   )r   )respr$   r-   r.   extra_certs   s    zADocumentSecurityStore._embed_certs_from_ocsp.<locals>.extra_certsc                    s   g | ]}  |qS r-   _embed_cert).0Zcert_rI   r-   r.   
<listcomp>   s     z@DocumentSecurityStore._embed_certs_from_ocsp.<locals>.<listcomp>r-   )r+   r$   rY   r-   )r$   r+   r.   _embed_certs_from_ocsp   s    z,DocumentSecurityStore._embed_certs_from_ocspc                 C   sf   | j d krtdz| j|j W S  tk
r4   Y nX | j tj| d}| 	  || j|j< |S )N"This DSS does not support updates.rL   )
r=   	TypeErrorr#   issuer_serialrN   rO   r   rP   rM   rK   )r+   certrU   r-   r-   r.   r[      s    
z!DocumentSecurityStore._embed_certr&   c                 C   s"   t |    }td| S )a  
        Hash the contents of a signature object to get the corresponding VRI
        identifier.

        This is internal API.

        :param contents:
            Signature contents.
        :return:
            A name object to put into the DSS.
        /)hashlibsha1digesthexupperr   )contentsidentr-   r-   r.   sig_content_identifier   s    z,DocumentSecurityStore.sig_content_identifierr-   r#   r$   r%   c          	         s    j dkrtdt|}t|}t }t } fdd|D }|rZt | j j}|rtt | j j}|	t 
| |dk	rt|||d} j |  j|<    dS )a  
        Register validation information for a set of signing certificates
        associated with a particular signature.

        :param identifier:
            Identifier of the signature object (see `sig_content_identifier`).
            If ``None``, only embed the data into the DSS without associating
            it with any VRI.
        :param certs:
            Certificates to add.
        :param ocsps:
            OCSP responses to add.
        :param crls:
            CRLs to add.
        Nr_   c                    s   h | ]}  |qS r-   rZ   )r\   rb   rI   r-   r.   	<setcomp>   s     z5DocumentSecurityStore.register_vri.<locals>.<setcomp>rl   )r=   r`   listr5   rV   rB   r$   rC   r%   updater^   r   rO   r/   r>   rK   )	r+   
identifierr#   r$   r%   	ocsp_refscrl_refs	cert_refsr,   r-   rI   r.   register_vri   s4    
  
z"DocumentSecurityStore.register_vric                 C   sl   | j }tt| j |d< | jr4t| j|d< | jrNt| j|t	d< | j
rht| j
|t	d< |S )z
        Convert the :class:`.DocumentSecurityStore` object to a python
        dictionary. This method also handles DSS updates.

        :return:
            A PDF object representing this DSS.
        /Certsr(   /OCSPs/CRLs)r?   r   r*   rn   r#   valuesr>   r)   r$   r   r%   )r+   Zpdf_dictr-   r-   r.   r/      s    z#DocumentSecurityStore.as_pdf_objectc                 c   s.   | j  D ]}| }t|j}|V  q
dS )z
        Return a generator that parses and yields all certificates in the DSS.

        :return:
            A generator yielding :class:`.Certificate` objects.
        N)r#   rx   r@   r	   loadrA   )r+   cert_refcert_streamrb   r-   r-   r.   
load_certs	  s    z DocumentSecurityStore.load_certsTc                 C   s   t |}|dg }t|  | }|rt|dd}| jD ]$}| }tj|j	}|
| q>||d< t|dd}	| jD ]$}
|
 }tj|j	}|	
| q|	|d< tf d|i|S )ag  
        Construct a validation context from the data in this DSS.

        :param validation_context_kwargs:
            Extra kwargs to pass to the ``__init__`` function.
        :param include_revinfo:
            If ``False``, revocation info is skipped.
        :return:
            A validation context preloaded with information from this DSS.
        other_certsr$   r-   r%   )dictpoprn   r|   r$   r@   	asn1_ocspOCSPResponsery   rA   rQ   r%   asn1_crlCertificateListr   )r+   Zvalidation_context_kwargsZinclude_revinforY   r#   r$   rE   ocsp_streamrW   r%   rF   
crl_streamr   r-   r-   r.   as_validation_context  s"    

z+DocumentSecurityStore.as_validation_context)handlerr'   c              
   C   sL  z|j d }W n* tk
r8 } zt |W 5 d}~X Y nX i }t|dtg d}|D ]"}| }t|j}|||j	< qRt|dtg d}	g }
|	D ]$}| }t
j|j}|
| qt|dtg d}g }|D ]$}| }tj|j}|| qzt|d }W n tk
r   d}Y nX t|tr0|}nd}| |||	|||d}|S )	a  
        Read a DSS record from a file and add the data to a validation context.

        :param handler:
            PDF handler from which to read the DSS.
        :return:
            A DocumentSecurityStore object describing the current state of the
            DSS.
        /DSSNru   )defaultrv   rw   r(   )r=   r#   r$   r>   r%   r?   )rootrN   r   r   rn   r@   r	   ry   rA   ra   r   r   rQ   r   r   r~   
isinstancer   )clsr   dss_dicters   Zcert_ref_listrz   r{   rb   rq   r$   rE   r   rW   rr   r%   rF   r   r   r>   r=   dssr-   r-   r.   read_dss8  sL    
zDocumentSecurityStore.read_dssr#   r$   r%   pathsvalidation_contextembed_roots)pdf_outr   r'   c                   s   z|  |}	d}
W n" tk
r4   d}
| |d}	Y nX |dk	rJt|}nd}ttj d fdd}fdd	}fd
d}|	j|| | | d |	 }|
r|	|}||j
td< |  |	S )aD  
        Add or update a DSS, and optionally associate the new information with a
        VRI entry tied to a signature object.

        You can either specify the CMS objects to include directly, or
        pass them in as output from `pyhanko_certvalidator`.

        :param pdf_out:
            PDF writer to write to.
        :param sig_contents:
            Contents of the new signature (used to compute the VRI hash), as
            a hexadecimal string, including any padding.
            If ``None``, the information will not be added to any VRI
            dictionary.
        :param certs:
            Certificates to include in the VRI entry.
        :param ocsps:
            OCSP responses to include in the VRI entry.
        :param crls:
            CRLs to include in the VRI entry.
        :param paths:
            Validation paths that have been established, and need to be added
            to the DSS.
        :param validation_context:
            Validation context from which to draw OCSP responses and CRLs.
        :param embed_roots:
            .. versionadded:: 0.9.0

            Option that controls whether the root certificate of each validation
            path should be embedded into the DSS. The default is ``True``.

            .. note::
                Trust roots are configured by the validator, so embedding them
                typically does nothing in a typical validation process.
                Therefore they can be safely omitted in most cases.
                Nonetheless, embedding the roots can be useful for documentation
                purposes.

            .. warning::
                This only applies to paths, not the ``certs`` parameter.

        :return:
            a :class:`DocumentSecurityStore` object containing both the new
            and existing contents of the DSS (if any).
        FTr<   Nr&   c                  3   s>    pdE d H  pdD ]"} t | }s.t| |E d H  qd S Nr-   )iternext)path
path_parts)r#   r   r   r-   r.   _certs  s    z:DocumentSecurityStore.supply_dss_in_writer.<locals>._certsc                   3   s&    pdE d H  d k	r"j E d H  d S r   rX   r-   )r$   r   r-   r.   _ocsps  s    z:DocumentSecurityStore.supply_dss_in_writer.<locals>._ocspsc                   3   s&    pdE d H  d k	r"j E d H  d S r   )r%   r-   )r%   r   r-   r.   _crls  s    z9DocumentSecurityStore.supply_dss_in_writer.<locals>._crlsrl   r   )r   r   r   rk   r   r   r	   rt   r/   rO   r   r   Zupdate_root)r   r   sig_contentsr#   r$   r%   r   r   r   r   createdrp   r   r   r   r   Zdss_refr-   )r#   r%   r   r$   r   r   r.   supply_dss_in_writerv  s4    :

   
z*DocumentSecurityStore.supply_dss_in_writerF)	r#   r$   r%   r   r   force_writer   file_credentialstrict)r   r   r   r   c       	      
   C   sZ   t ||d}|jdk	r*|
dk	r*|j|
 | j||||||||	d}|sN|jrV|  dS )a  
        Wrapper around :meth:`supply_dss_in_writer`.

        The result is applied to the output stream as an incremental update.

        :param output_stream:
            Output stream to write to.
        :param sig_contents:
            Contents of the new signature (used to compute the VRI hash), as
            a hexadecimal string, including any padding.
            If ``None``, the information will not be added to any VRI
            dictionary.
        :param certs:
            Certificates to include in the VRI entry.
        :param ocsps:
            OCSP responses to include in the VRI entry.
        :param crls:
            CRLs to include in the VRI entry.
        :param paths:
            Validation paths that have been established, and need to be added
            to the DSS.
        :param force_write:
            Force a write even if the DSS doesn't have any new content.
        :param validation_context:
            Validation context from which to draw OCSP responses and CRLs.
        :param embed_roots:
            .. versionadded:: 0.9.0

            Option that controls whether the root certificate of each validation
            path should be embedded into the DSS. The default is ``True``.

            .. note::
                Trust roots are configured by the validator, so embedding them
                typically does nothing in a typical validation process.
                Therefore they can be safely omitted in most cases.
                Nonetheless, embedding the roots can be useful for documentation
                purposes.

            .. warning::
                This only applies to paths, not the ``certs`` parameter.
        :param file_credential:
            .. versionadded:: 0.13.0

            Serialised file credential, to update encrypted files.
        :param strict:
            If ``True``, enforce strict validation of the input stream.
            Default is ``True``.
        )r   Nr   )r   Zsecurity_handlerZauthenticater   rJ   write_in_place)r   Zoutput_streamr   r#   r$   r%   r   r   r   r   r   r   r   r   r-   r-   r.   add_dss  s    @

zDocumentSecurityStore.add_dss)NNNNN)T) r0   r1   r2   r3   r   r   rG   propertyrJ   rK   rV   r^   r[   staticmethodr   Z
NameObjectrk   rt   r/   r   r   r	   r|   r   r   classmethodr   r   boolr   r    r   r-   r-   r-   r.   r   ]   sl        "
1 #=h
F)embedded_sigr   c                    s\   j j}|jstd g   fdd}|| jI dH  |sX| jdk	rX|| jI dH   S )a  
    Query revocation info for a PDF signature using a validation context,
    and store the results in a validation context.

    This works by validating the signer's certificate against the provided
    validation context, which causes revocation info to be cached for
    later retrieval.

    .. warning::
        This function does *not* actually validate the signature, but merely
        checks the signer certificate's chain of trust.

    :param embedded_sig:
        Embedded PDF signature to operate on.
    :param validation_context:
        Validation context to use.
    :param skip_timestamp:
        If the signature has a time stamp token attached to it, also collect
        revocation information for the timestamp.
    :return:
        A list of validation paths.
    zfRevocation mode is set to soft-fail/tolerant mode; collected revocation information may be incomplete.c                    sD   t | }|j}|j}t||d}|jt dI d H } | d S )N)Zintermediate_certsr   )Z	key_usage)r   Zsigner_certr}   r
   Zasync_validate_usager5   rQ   )signed_dataZ	cert_inforb   r}   	validatorr   r   r   r-   r.   _validate_signed_dataW  s    z6collect_validation_info.<locals>._validate_signed_dataN)Zrevinfo_policyZrevocation_checking_policyZ	essentialloggerwarningr   Zattached_timestamp_data)r   r   skip_timestampZrevinfo_fetch_policyr   r-   r   r.   r   0  s    T)r   r   r   c	                    s   | j }	|r |	j }
}t| n
t|}
t| ||dI dH }|rT| j d}nd}t	
|	}||_tj|||||d}|s|jr|r|  q||
 n$|s|	jd tt||	j|
 t||
S )aY  
    .. versionadded: 0.9.0

    Add validation info (CRLs, OCSP responses, extra certificates) for a
    signature to the DSS of a document in an incremental update.
    This is a wrapper around :func:`collect_validation_info`.

    :param embedded_sig:
        The signature for which the revocation information needs to be
        collected.
    :param validation_context:
        The validation context to use.
    :param skip_timestamp:
        If ``True``, do not attempt to validate the timestamp attached to
        the signature, if one is present.
    :param add_vri_entry:
        Add a ``/VRI`` entry for this signature to the document security store.
        Default is ``True``.
    :param output:
        Write the output to the specified output stream.
        If ``None``, write to a new :class:`.BytesIO` object.
        Default is ``None``.
    :param in_place:
        Sign the original input stream in-place.
        This parameter overrides ``output``.
    :param chunk_size:
        Chunk size parameter to use when copying output to a new stream
        (irrelevant if ``in_place`` is ``True``).
    :param force_write:
        Force a new revision to be written, even if not necessary (i.e.
        when all data in the validation context is already present in the DSS).
    :param embed_roots:
        Option that controls whether the root certificate of each validation
        path should be embedded into the DSS. The default is ``True``.

        .. note::
            Trust roots are configured by the validator, so embedding them
            typically does nothing in a typical validation process.
            Therefore they can be safely omitted in most cases.
            Nonetheless, embedding the roots can be useful for documentation
            purposes.
    :return:
        The (file-like) output object to which the result was written.
    )r   Nascii)r   r   r   r   )readerstreamr   Z!assert_writable_and_random_accessZprepare_rw_output_streamr   Zpkcs7_contentrg   encoder   Zfrom_readerZIO_CHUNK_SIZEr   r   rJ   r   writeseekZchunked_write	bytearrayZfinalise_output)r   r   r   Zadd_vri_entryZin_placeoutputr   
chunk_sizer   r   Zworking_outputr   r   r   Zresulting_dssr-   r-   r.   r   k  s<    8

  


)F)9rd   loggingdataclassesr   r   r4   typingr   r   Z
asn1cryptor   r   r   r   r   Zasn1crypto.x509r	   Zpyhanko_certvalidatorr
   r   Zpyhanko_certvalidator.pathr   Zpyhanko.pdf_utilsr   r   Zpyhanko.pdf_utils.genericr   Z$pyhanko.pdf_utils.incremental_writerr   Zpyhanko.pdf_utils.miscr   Zpyhanko.pdf_utils.rw_commonr   Zpyhanko.pdf_utils.writerr   Zgeneralr   errorsr   r   Zpdf_embeddedr   __all__Zpdf_utils.cryptr    Zpdf_utils.readerr!   	getLoggerr0   r   r   r   r   r   ZDEFAULT_CHUNK_SIZEr   r   r-   r-   r-   r.   <module>   sh   
(   Y >