U
    <g                     @   sT  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mZ d dl	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mZ d dlmZmZmZmZmZ d dlmZm Z m!Z!m"Z"m#Z#m$Z$ d dl%m&Z&m'Z'm(Z(m)Z) ddl*m+Z+m,Z,m-Z- ddl.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6 ddl7m8Z8 ddl9m:Z:m;Z;m<Z< ddl=m>Z> dddddddgZ?e @eAZBeejC dddZDee  dddZEejCeFd d!dZGG d"d dZHedd#d$gZIeeeI d%d&dZJeHd'd(d)ZKeHeeLd*d+dZMd,d- ZNd3eHee ee ee ee ee8 eLee> e;d/	d0dZOd4eHee ee eLe:d1d2dZPdS )5    N)
namedtuple)datetime)ListOptionalUnion)cmsx509)ValidationContext)ValidationPath)genericmisc)pdf_name)PdfFileReaderprocess_data_at_eof)DEFAULT_DIFF_POLICY
DiffPolicy
DiffResultModificationLevelSuspiciousModification)FieldMDPSpecMDPPermSeedLockDocumentSigSeedSubFilterSigSeedValFlagsSigSeedValueSpec)SignedDataCertsUnacceptableSignerErrorbyte_range_digestextract_signer_info   )SignatureValidationErrorSigSeedValueValidationErrorValidationInfoReadingError)cms_basic_validationcollect_signer_attr_statuscollect_timing_infocompute_signature_tst_digestextract_certs_for_validationextract_self_reported_tsextract_tst_datavalidate_tst_signed_data)KeyUsageConstraints)DocumentTimestampStatusPdfSignatureStatusSignatureCoverageLevel)CMSAlgorithmUsagePolicyEmbeddedPdfSignature
DocMDPInforead_certification_dataasync_validate_pdf_signatureasync_validate_pdf_timestampreport_seed_value_validationextract_contentsreturnc                 C   sN   z| d }W n t k
r"   Y d S X |D ] }| }|d |kr(|  S q(d S )Nz
/Referencez/TransformMethod)KeyError
get_object)signature_objmethodZsig_refsref r>   H/tmp/pip-unpacked-wheel-w101_d3s/pyhanko/sign/validation/pdf_embedded.py_extract_reference_dictI   s    
r@   c              
   C   sd   t | d}|d krd S z|d d}t|W S  ttfk
r^ } ztd|W 5 d }~X Y nX d S )N/DocMDP/TransformParams/Pz#Failed to read document permissions)r@   raw_getr   
ValueErrorr9   r    )r;   r=   Z	raw_permser>   r>   r?   _extract_docmdp_for_sigW   s    

rG   )
sig_objectr8   c                 C   sX   z| j dtjjd}W n tk
r4   tdY nX t|tjtj	fsRtd|j
S )z
    Internal function to extract the (DER-encoded) signature bytes from a PDF
    signature dictionary.

    :param sig_object:
        A signature dictionary.
    :return:
        The extracted contents as a byte string.
    z	/Contents)decryptz+Could not read /Contents entry in signaturez/Contents must be string-like)rD   r   ZEncryptedObjAccessZRAWr9   r   PdfReadError
isinstanceZTextStringObjectZByteStringObjectoriginal_bytes)rH   cms_contentr>   r>   r?   r6   d   s     
 

c                   @   s  e Zd ZU dZejed< ejed< ejed< e	eje
dddZedd	d
Zeeej dddZeeej dddZeejdddZeejdddZedd Zeee dddZeeej dddZd0ddZedddZeee  ddd Z!eee" dd!d"Z#eee$ dd#d$Z%e&dd%d&Z'ee& dd'd(Z(e)dd)d*Z*d+d, Z+e,e-e.e/f d-d.d/Z0dS )1r0   zA
    Class modelling a signature embedded in a PDF document.
    	sig_fieldrH   signed_data)readerrN   fq_namec                 C   sn  || _ t|tjr| }|| _|d}|  | _}t|tjsHt	z|d| _
W n tk
rv   tdY nX t| | _}tj|}|d }|| _t|| _d | _| jd }	|	d j | _|d }
|
d j}|d	kr| j| _n(|d
kr|
d jd }|d d j| _| j j|j| _d | _ d | _!d | _"d | _#d | _$d | _%| _&d | _'d | _(d| _)|| _*d S )Nz/Vz
/ByteRangez,Could not read /ByteRange entry in signaturecontentZdigest_algorithm	algorithmZencap_content_infocontent_typedataZtst_infoZmessage_imprinthash_algorithmF)+rP   rK   r   ZIndirectObjectr:   rN   rD   rH   DictionaryObjectAssertionError
byte_ranger9   r   rJ   r6   pkcs7_contentr   ZContentInfoloadrO   r   signer_info_sd_cert_infoZnativelowermd_algorithmexternal_md_algorithmparsedxrefsZget_last_change	referencesigned_revisioncoverageexternal_digest	total_len_docmdp	_fieldmdp_docmdp_queried_fieldmdp_queriedtst_signature_digestdiff_result_integrity_checkedrQ   )selfrP   rN   rQ   Zsig_object_refrH   rM   messagerO   Zdigest_algoZecirT   mir>   r>   r?   __init__   sV    






zEmbeddedPdfSignature.__init__r7   c                 C   s   | j d krt| j| _ | j S )N)r]   r'   rO   ro   r>   r>   r?   _init_cert_info   s    
z$EmbeddedPdfSignature._init_cert_infoc                 C   s   t |  jS )z2
        Embedded attribute certificates.
        )listrt   Zattribute_certsrs   r>   r>   r?   embedded_attr_certs   s    z(EmbeddedPdfSignature.embedded_attr_certsc                 C   s   t |  jS )zQ
        Embedded X.509 certificates, excluding than that of the signer.
        )ru   rt   Zother_certsrs   r>   r>   r?   other_embedded_certs   s    z)EmbeddedPdfSignature.other_embedded_certsc                 C   s
   |   jS )z,
        Certificate of the signer.
        )rt   signer_certrs   r>   r>   r?   rx      s    z EmbeddedPdfSignature.signer_certc                 C   s   | j dtdS )a  
        Returns the type of the embedded signature object.
        For ordinary signatures, this will be ``/Sig``.
        In the case of a document timestamp, ``/DocTimeStamp`` is returned.

        :return:
            A PDF name object describing the type of signature.
        z/Type/Sig)rH   getr   rs   r>   r>   r?   sig_object_type   s    
z$EmbeddedPdfSignature.sig_object_typec                 C   s   | j S )zC
        :return:
            Name of the signature field.
        )rQ   rs   r>   r>   r?   
field_name  s    zEmbeddedPdfSignature.field_namec                 C   sP   t | j}|dk	r|S z| jd }tj|| jjdW S  tk
rJ   Y dS X dS )z
        :return:
            The signing time as reported by the signer, if embedded in the
            signature's signed attributes or provided as part of the signature
            object in the PDF document.
        Nz/M)strict)r(   r\   rH   r   Zparse_pdf_daterP   r}   r9   )ro   tsZst_as_pdf_dater>   r>   r?   self_reported_timestamp  s    

 z,EmbeddedPdfSignature.self_reported_timestampc                 C   s
   t | jS )z
        :return:
            The signed data component of the timestamp token embedded in this
            signature, if present.
        )r)   r\   rs   r>   r>   r?   attached_timestamp_data"  s    z,EmbeddedPdfSignature.attached_timestamp_dataNFc                 C   sD   |    |   |   |  | _|p(t}|s:| || _d| _dS )a  
        Compute the various integrity indicators of this signature.

        :param diff_policy:
            Policy to evaluate potential incremental updates that were appended
            to the signed revision of the document.
            Defaults to
            :const:`~pyhanko.sign.diff_analysis.DEFAULT_DIFF_POLICY`.
        :param skip_diff:
            If ``True``, skip the difference analysis step entirely.
        TN)	_enforce_hybrid_xref_policycompute_digestcompute_tst_digestevaluate_signature_coveragere   r   evaluate_modificationsrm   rn   )ro   diff_policy	skip_diffr>   r>   r?   compute_integrity_info+  s    
z+EmbeddedPdfSignature.compute_integrity_infoc                 C   s   | j std| j}| j}| j}d}|dk	rdt|tr<|jntj	}|tj	kp^|dk	o^|j
|j
k }n|tjkrx|tjk}|||d}|S )a  
        Compile the integrity information for this signature into a dictionary
        that can later be passed to :class:`.PdfSignatureStatus` as kwargs.

        This method is only available after calling
        :meth:`.EmbeddedPdfSignature.compute_integrity_info`.
        zGCall compute_integrity_info() before invokingsummarise_integrity_info()N)re   	docmdp_okrm   )rn   r    docmdp_levelrm   re   rK   r   Zmodification_levelr   OTHERvaluer.   ENTIRE_REVISIONENTIRE_FILE)ro   docmdprm   re   r   Z	mod_levelstatus_kwargsr>   r>   r?   summarise_integrity_infoD  s.    	


z-EmbeddedPdfSignature.summarise_integrity_infoc                 C   s0   z| j d }W n tk
r$   Y d S X t|S )Nz/SV)rN   r9   r   from_pdf_object)ro   Zsig_sv_dictr>   r>   r?   seed_value_specq  s
    z$EmbeddedPdfSignature.seed_value_specc                 C   s`   | j r| jS t| jd}|dkrPz| jd }t|d }W n tk
rN   Y nX || _d| _ |S )av  
        :return:
            The document modification policy required by this signature or
            its Lock dictionary.

            .. warning::
                This does not take into account the DocMDP requirements of
                earlier signatures (if present).

                The specification forbids signing with a more lenient DocMDP
                than the one currently in force, so this should not happen
                in a compliant document.
                That being said, any potential violations will still invalidate
                the earlier signature with the stricter DocMDP policy.

        )r;   Nz/LockrC   T)rj   rh   rG   rH   rN   r   r9   )ro   r   Z	lock_dictr>   r>   r?   r   y  s    
z!EmbeddedPdfSignature.docmdp_levelc              
   C   sx   | j r| jS t| jd}d| _ |dkr*dS zt|d }W n0 ttfk
rl } ztd|W 5 d}~X Y nX || _|S )z
        :return:
            Read the field locking policy of this signature, if applicable.
            See also :class:`~.pyhanko.sign.fields.FieldMDPSpec`.
        z	/FieldMDPTNrB   z!Failed to read /FieldMDP settings)	rk   ri   r@   rH   r   r   rE   r9   r    )ro   Zref_dictsprF   r>   r>   r?   fieldmdp  s     zEmbeddedPdfSignature.fieldmdpc                 C   s6   | j dk	r| j S t| jj| j| jd\| _}|| _ |S )z
        Compute the ``/ByteRange`` digest of this signature.
        The result will be cached.

        :return:
            The digest value.
        N)rY   r_   )rf   r   rP   streamrY   r`   rg   ro   digestr>   r>   r?   r     s    
z#EmbeddedPdfSignature.compute_digestc                 C   s$   | j dk	r| j S t| j | _ }|S )a  
        Compute the digest of the signature needed to validate its timestamp
        token (if present).

        .. warning::
            This computation is only relevant for timestamp tokens embedded
            inside a regular signature.
            If the signature in question is a document timestamp (where the
            entire signature object is a timestamp token), this method
            does not apply.

        :return:
            The digest value, or ``None`` if there is no timestamp token.
        N)rl   r&   r\   r   r>   r>   r?   r     s    

z'EmbeddedPdfSignature.compute_tst_digestc                 C   s"  | j j}| j j}t| jdks,| jd dkr2tjS | j\}}}}|dtj	 t| j
d d }|| | }| |k}	|	rtjS ||| k}
|
stjS || | j}z&t|}||}||krtjW S W n tjk
r   tj Y S X t|d D ]"}||}|j|krtj  S qtjS )z
        Internal method used to evaluate the coverage level of a signature.

        :return:
            The coverage level of the signature.
           r      r   )rP   rb   r   lenrY   r.   ZUNCLEARseekosSEEK_ENDrZ   tellr   rd   r   Zget_startxref_for_revisionZCONTIGUOUS_BLOCK_FROM_STARTr   rJ   rangeZget_xref_container_infoZend_locationr   )ro   Z
xref_cacher   _Zlen1Zstart2Zlen2Zembedded_sig_contentZsigned_zone_lenZfile_covered
contiguousZ
signed_revZ	startxrefexpectedrevisionZ	xref_metar>   r>   r?   r     s8    





z0EmbeddedPdfSignature.evaluate_signature_coveragec                 C   s    | j }|jr|jjrtdd S )NzJSettings do not permit validation of signatures in hybrid-reference files.)rP   r}   rb   Zhybrid_xrefs_presentr    )ro   rP   r>   r>   r?   r   "  s
    z0EmbeddedPdfSignature._enforce_hybrid_xref_policy)r   r8   c                 C   sH   | j tjk rtdS | j tjkr.ttjt S |j	| j
| j| j| jdS )zY
        Internal method used to evaluate the modification level of a signature.
        z$Nonstandard signature coverage level)Zfield_mdp_specdoc_mdp)re   r.   r   r   r   r   r   NONEsetZreview_filerP   rd   r   r   )ro   r   r>   r>   r?   r   *  s    z+EmbeddedPdfSignature.evaluate_modifications)NF)1__name__
__module____qualname____doc__r   rW   __annotations__r   Z
SignedDatar   strrr   r   rt   propertyr   ZAttributeCertificateV2rv   r   Certificaterw   rx   Z
NameObjectr{   r|   r   r   r   r   r   dictr   r   r   r   r   r   r   bytesr   r   r.   r   r   r   r   r   r   r   r>   r>   r>   r?   r0      sL   



L

-H	
Z
permissionZ
author_sig)rP   r8   c                 C   s<   z| j d d }W n tk
r(   Y dS X t|}t||S )z
    Read the certification information for a PDF document, if present.

    :param reader:
        Reader representing the input document.
    :return:
        A :class:`.DocMDPInfo` object containing the relevant data, or ``None``.
    /PermsrA   N)rootr9   rG   r1   )rP   Zcertification_sigpermr>   r>   r?   r2   G  s    	)emb_sigc              
   C   s  | j }|d krd S | j}|jd k	rbz|j|| W n, tk
r` } zt||W 5 d }~X Y nX |st|jrttd| j}|jd k	r:|j	 }z$| j
jd }|d}	|	|jk}
W n  ttjtfk
r   d}
Y nX ||
krdd }td|| d||
 d	|r:|jj}| j}||kr:td
| d| d|j}|sJd S |d }t|}|tj@ r|jd k	r|jstd|jd }|d k	r||krtd|j|jf |tj@ r|jd k	rtd |tj@ r|j d k	rtd|tj!@ rX|j"d k	rX| j}|j"t#j$kr6|t%j&kr6td|j"t#j'krX|t%j&krXtd| j(}|tj)@ r|j*d k	rddl+m,} z|| d}W n t-k
r   d}Y nX |j*|krtd|j*rdnd|rdndf |j*r|tj.krtdtj.j |tj/@ r>|j0d k	r>| j12 }||j0kr>td| |tj3@ r|j4pTg }| pf|dgk}|5d}|r|d k	rtd|s||krtd|f d S ) NznThe seed value dictionary requires a trusted timestamp, but none was found, or the timestamp did not validate.r   rA   Fc                 S   s   | rdS dS )Nza certificationzan approvalr>   )Zcertifyr>   r>   r?   _typex  s    z'_validate_sv_constraints.<locals>._typezPThe seed value dictionary's /MDP entry specifies that this field should contain z signature, but z appears to have been used.zaThe seed value dictionary specified that this certification signature should use the MDP policy 'z', but 'z' was used in the signature.
/SubFilterzPThe signature encodings mandated by the seed value dictionary are not supported.r   zVThe seed value dictionary mandates subfilter '%s', but '%s' was used in the signature.zThe signature's seed value dictionary specifies the /AppearanceFilter entry as mandatory, but this constraint is impossible to validate.zpyHanko does not support legal attestations, but the seed value dictionary mandates that they be restricted to a specific subset.z<Document must be locked, but some changes are still allowed.zGDocument must not be locked, but the DocMDP level is set to NO_CHANGES.)retrieve_adobe_revocation_infoTzbThe seed value dict mandates that revocation info %sbe added, but it was %sfound in the signature. znot zdThe seed value dict mandates that Adobe-style revocation info be added; this requires subfilter '%s'zKThe selected message digest %s is not allowed by the seed value dictionary..z/Reasonz@The seed value dictionary prohibits giving a reason for signing.zIThe reason for signing "%s" is not accepted by the seed value dictionary.)6r   rx   certsatisfied_byr   r!   Ztimestamp_requiredrH   Zseed_signature_typeZcertification_signaturerP   r   Zget_value_as_referenceZcontainer_refr9   r   ZIndirectObjectExpectedAttributeErrorZmdp_permr   flagsr   r   Z	SUBFILTERZ
subfiltersNotImplementedErrorr   ZAPPEARANCE_FILTERZ
appearanceloggerwarningZLEGAL_ATTESTATIONZlegal_attestationsZLOCK_DOCUMENTZlock_documentr   ZLOCKr   Z
NO_CHANGESZDO_NOT_LOCKr\   ZADD_REV_INFOZadd_rev_infoZpyhanko.sign.validation.ltvr   r"   ADOBE_PKCS7_DETACHEDZDIGEST_METHODZdigest_methodsr_   r^   ZREASONSreasonsrz   )r   validation_pathtimestamp_foundZsv_specZsigning_certrF   Zsig_objZ
sv_certifyZpermsZcert_sig_refZwas_certifiedr   Zsv_mdp_permr   r   Zselected_sf_strZselected_sfZmandated_sfr\   r   Zrevinfo_foundZselected_mdr   Z	must_omitZreason_givenr>   r>   r?   _validate_sv_constraintsY  s   











	

r   )embedded_sigr   r   c              
   C   s\   zt | ||d d}W n4 tk
rJ } ztjd|d |}W 5 d}~X Y nX | jdk	|dS )a  
    Internal API function to enforce seed value constraints (if present)
    and report on the result(s).

    :param embedded_sig:
        The embedded signature.
    :param validation_path:
        The validation path for the signer's certificate.
    :param timestamp_found:
        Flag indicating whether a valid timestamp was found or not.
    :return:
        A ``status_kwargs`` dict.
    )r   NzError in seed value validation.)exc_info)Zhas_seed_valuesZseed_value_constraint_error)r   r!   r   r   r   )r   r   r   Zsv_errrF   r>   r>   r?   r5     s      c                 C   sJ   zddl m} || |k}W n tk
r4   d}Y nX |sFt||  d S )Nr   )r   F)pyhanko.sign.fieldsr   rE   r    )subfilter_strZpermitted_subfilterserr_msgr   Zsubfilter_okr>   r>   r?   _validate_subfilter$  s    
r   F)	r   signer_validation_contextts_validation_contextac_validation_contextr   key_usage_settingsr   algorithm_policyr8   c                    sF  | j }| jdkrtd|dd}	t|	tjtjfd |dkrD|}| j||d | 	 }
t
| j||  dI dH }|
| d|
kr| j}|dk	r||
d< t|}t| j| j||
||d	I dH }
|
d
d}|dk	o|jo|j}t| |
d |}|
| |dk	r|j| j |
t| j| j|| jd dI dH  tf |
S )a  
    .. versionadded:: 0.9.0

    .. versionchanged: 0.11.0
        Added ``ac_validation_context`` param.


    Validate a PDF signature.

    :param embedded_sig:
        Embedded signature to evaluate.
    :param signer_validation_context:
        Validation context to use to validate the signature's chain of trust.
    :param ts_validation_context:
        Validation context to use to validate the timestamp's chain of trust
        (defaults to ``signer_validation_context``).
    :param ac_validation_context:
        Validation context to use to validate attribute certificates.
        If not supplied, no AC validation will be performed.

        .. note::
            :rfc:`5755` requires attribute authority trust roots to be specified
            explicitly; hence why there's no default.
    :param diff_policy:
        Policy to evaluate potential incremental updates that were appended
        to the signed revision of the document.
        Defaults to
        :const:`~pyhanko.sign.diff_analysis.DEFAULT_DIFF_POLICY`.
    :param key_usage_settings:
        A :class:`.KeyUsageConstraints` object specifying which key usages
        must or must not be present in the signer's certificate.
    :param skip_diff:
        If ``True``, skip the difference analysis step entirely.
    :param algorithm_policy:
        The algorithm usage policy for the signature validation.

        .. warning::
            This is distinct from the algorithm usage policy used for
            certificate validation, but the latter will be used as a fallback
            if this parameter is not specified.

            It is nonetheless recommended to align both policies unless
            there is a clear reason to do otherwise.
    :return:
        The status of the PDF signature in question.
    ry   z"Signature object type must be /Sigr   Nz4%s is not a recognized SubFilter type in signatures.r   r   )
raw_digestsigner_reported_dt)r   validation_contextr   r   r   Ztimestamp_validityr   Zsigned_attrs)Zsd_attr_certificatesrx   r   Zsd_signed_attrs)rH   r{   r    rz   r   r   r   ZPADESr   r   r%   r\   r   updater   r-   Zdefault_usage_constraintsr#   rO   rf   validZtrustedr5   Zcertificate_registryZregister_multiplerw   r$   rv   rx   )r   r   r   r   r   r   r   r   rH   r   r   Zts_status_kwargsr   Ztst_validityr   Z	sv_updater>   r>   r?   r3   0  sv    9

 
  


)r   r   r   r   r8   c                    st   | j dkrtd| jdd}t|tjfd | j||d t| j	|| 
 I dH }| j|d< | j|d< tf |S )	a{  
    .. versionadded:: 0.9.0

    Validate a PDF document timestamp.

    :param embedded_sig:
        Embedded signature to evaluate.
    :param validation_context:
        Validation context to use to validate the timestamp's chain of trust.
    :param diff_policy:
        Policy to evaluate potential incremental updates that were appended
        to the signed revision of the document.
        Defaults to
        :const:`~pyhanko.sign.diff_analysis.DEFAULT_DIFF_POLICY`.
    :param skip_diff:
        If ``True``, skip the difference analysis step entirely.
    :return:
        The status of the PDF timestamp in question.
    z/DocTimeStampz+Signature object type must be /DocTimeStampr   Nz5%s is not a recognized SubFilter type for timestamps.r   re   rm   )r{   r    rH   rz   r   r   ZETSI_RFC3161r   r*   rO   r   re   rm   r,   )r   r   r   r   r   r   r>   r>   r?   r4     s,    
 


)NNNNNFN)NNF)Qloggingr   collectionsr   r   typingr   r   r   Z
asn1cryptor   r   Zpyhanko_certvalidatorr	   Zpyhanko_certvalidator.pathr
   Zpyhanko.pdf_utilsr   r   Zpyhanko.pdf_utils.genericr   Zpyhanko.pdf_utils.readerr   r   Zpyhanko.sign.diff_analysisr   r   r   r   r   r   r   r   r   r   r   r   Zpyhanko.sign.generalr   r   r   r   errorsr    r!   r"   Zgeneric_cmsr#   r$   r%   r&   r'   r(   r)   r*   settingsr+   statusr,   r-   r.   utilsr/   __all__	getLoggerr   r   rW   r@   rG   r   r6   r0   r1   r2   r   boolr5   r   r3   r4   r>   r>   r>   r?   <module>   s    (

   C ,!       }   