U
    c                  
   @   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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( ddl)m*Z*m+Z+m,Z, ddl-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5 ddl6m7Z7 ddl8m9Z9m:Z:m;Z; dddddddgZ<e =e>Z?eej@ dddZAee  dddZBej@eCdd dZDG d!d dZEedd"d#gZFeeeF d$d%dZGeEd&d'd(ZHeEeeId)d*dZJd+d, ZKd2eEeeeee7eIe:d.d/dZLd3eEeeeIe9d0d1dZMdS )4    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)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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-0kb_yl26/pyhanko/sign/validation/pdf_embedded.py_extract_reference_dictB   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   
ValueErrorr7   r   )r9   r;   Z	raw_permser<   r<   r=   _extract_docmdp_for_sigN   s    

 rE   )
sig_objectr6   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)Zdecryptz+Could not read /Contents entry in signaturez/Contents must be string-like)rB   r   ZEncryptedObjAccessZRAWr7   r   PdfReadError
isinstanceZTextStringObjectZByteStringObjectoriginal_bytes)rF   cms_contentr<   r<   r=   r4   [   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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/Z/dS )1r.   zA
    Class modelling a signature embedded in a PDF document.
    	sig_fieldrF   signed_data)readerrK   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 S )Nz/Vz
/ByteRangez,Could not read /ByteRange entry in signaturecontentZdigest_algorithm	algorithmZencap_content_infocontent_typedataZtst_infoZmessage_imprintZhash_algorithmF)+rM   rH   r   ZIndirectObjectr8   rK   rB   rF   DictionaryObjectAssertionError
byte_ranger7   r   rG   r4   pkcs7_contentr   ZContentInfoloadrL   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_checkedrN   )selfrM   rK   rN   Zsig_object_refrF   rJ   messagerL   Zdigest_algoZecirQ   mir<   r<   r=   __init__   sR    






zEmbeddedPdfSignature.__init__c                 C   s   | j d krt| j| _ d S )N)rY   r&   rL   rk   r<   r<   r=   _init_cert_info   s    
z$EmbeddedPdfSignature._init_cert_infor5   c                 C   s   |    t| jjS )z2
        Embedded attribute certificates.
        )rp   listrY   Zattribute_certsro   r<   r<   r=   embedded_attr_certs   s    z(EmbeddedPdfSignature.embedded_attr_certsc                 C   s   |    t| jjS )zQ
        Embedded X.509 certificates, excluding than that of the signer.
        )rp   rq   rY   Zother_certsro   r<   r<   r=   other_embedded_certs   s    z)EmbeddedPdfSignature.other_embedded_certsc                 C   s   |    | jjS )z,
        Certificate of the signer.
        )rp   rY   signer_certro   r<   r<   r=   rt      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)rF   getr   ro   r<   r<   r=   sig_object_type   s    
z$EmbeddedPdfSignature.sig_object_typec                 C   s   | j S )zC
        :return:
            Name of the signature field.
        )rN   ro   r<   r<   r=   
field_name   s    zEmbeddedPdfSignature.field_namec                 C   sF   t | j}|dk	r|S z| jd }t|W S  tk
r@   Y nX dS )z
        :return:
            The signing time as reported by the signer, if embedded in the
            signature's signed attributes.
        Nz/M)r'   rX   rF   r   Zparse_pdf_dater7   )rk   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(   rX   ro   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_coveragera   r   evaluate_modificationsri   rj   )rk   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)ra   	docmdp_okri   )rj   r   docmdp_levelri   ra   rH   r   Zmodification_levelr   OTHERvaluer-   ENTIRE_REVISIONENTIRE_FILE)rk   docmdpri   ra   r   Z	mod_levelstatus_kwargsr<   r<   r=   summarise_integrity_info3  s.    	


 z-EmbeddedPdfSignature.summarise_integrity_infoc                 C   s0   z| j d }W n tk
r$   Y d S X t|S )Nz/SV)rK   r7   r   from_pdf_object)rk   Zsig_sv_dictr<   r<   r=   seed_value_spec_  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.

        )r9   Nz/LockrA   T)rf   rd   rE   rF   rK   r   r7   )rk   r   Z	lock_dictr<   r<   r=   r   g  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	/FieldMDPTNr@   z!Failed to read /FieldMDP settings)	rg   re   r>   rF   r   r   rC   r7   r   )rk   Zref_dictsprD   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)rU   r[   )rb   r   rM   streamrU   r\   rc   rk   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)rh   r%   rX   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   )rM   r^   r   lenrU   r-   ZUNCLEARseekosSEEK_ENDrV   tellr   r`   r   Zget_startxref_for_revisionZCONTIGUOUS_BLOCK_FROM_STARTr   rG   rangeZget_xref_container_infoZend_locationr   )rk   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.)rM   strictr^   Zhybrid_xrefs_presentr   )rk   rM   r<   r<   r=   r|     s
    z0EmbeddedPdfSignature._enforce_hybrid_xref_policy)r   r6   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)ra   r-   r   r   r   r   r   NONEsetZreview_filerM   r`   r   r   )rk   r   r<   r<   r=   r     s      z+EmbeddedPdfSignature.evaluate_modifications)NF)0__name__
__module____qualname____doc__r   rS   __annotations__r   Z
SignedDatar   strrn   rp   propertyr   ZAttributeCertificateV2rr   r   ZCertificaters   rt   Z
NameObjectrw   rx   r   r   rz   r{   r   dictr   r   r   r   r   r   r   bytesr}   r~   r-   r   r|   r   r   r   r   r   r<   r<   r<   r=   r.   v   sL   



 F

,H
Z
permissionZ
author_sig)rM   r6   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``.
    /Permsr?   N)rootr7   rE   r/   )rM   Zcertification_sigpermr<   r<   r=   r0   3  s    	)emb_sigc              
   C   s  | j }| j}|jd k	rVz|j|| W n, tk
rT } zt||W 5 d }~X Y nX |sh|jrht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rdd }td|| d||
 d	|r,|jj}| j}||kr,td
| d| d|j}|s<d S |d }t|}|tj@ r|jd k	r|jstt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!@ rJ|j"d k	rJ| j}|j"t#j$kr(|t%j&kr(td|j"t#j'krJ|t%j&krJtd| j(}|tj)@ r|j*d k	rd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rtdtj.j |tj/@ r0|j0d k	r0| j12 }||j0kr0td| |tj3@ r|j4 pP|j4dgk}|5d}|rt|d k	rttd|s||j4krtd|f d S ) NznThe seed value dictionary requires a trusted timestamp, but none was found, or the timestamp did not validate.r   r?   Fc                 S   s   | rdS dS )Nza certificationzan approvalr<   )Zcertifyr<   r<   r=   _typea  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   rt   certsatisfied_byr   r    Ztimestamp_requiredrF   Zseed_signature_typeZcertification_signaturerM   r   Zget_value_as_referenceZcontainer_refr7   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_LOCKrX   ZADD_REV_INFOZadd_rev_infoZpyhanko.sign.validation.ltvr   r!   ADOBE_PKCS7_DETACHEDZDIGEST_METHODZdigest_methodsr[   rZ   ZREASONSZreasonsrv   )r   validation_pathtimestamp_foundsv_specZsigning_certrD   Zsig_objZ
sv_certifyZpermsZcert_sig_refZwas_certifiedr   Zsv_mdp_permr   r   Zselected_sf_strZselected_sfZmandated_sfrX   r   Zrevinfo_foundZselected_mdZ	must_omitZreason_givenr<   r<   r=   _validate_sv_constraintsE  s   






 


r   )embedded_sigr   r   c              
   C   sh   | j }|dkri S zt| ||d d}W n4 tk
r\ } ztjd|d |}W 5 d}~X Y nX d|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.
    N)r   zError in seed value validation.)exc_infoT)Zhas_seed_valuesZseed_value_constraint_error)r   r   r    r   r   )r   r   r   r   Zsv_errrD   r<   r<   r=   r3     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   rC   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   r6   c                    sB  | j }| jdkrtd|dd}t|tjtjfd |dkrD|}| j||d | 	 }	t
| j|| 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 )aV  
    .. 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.
    :return:
        The status of the PDF signature in question.
    ru   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   Ztimestamp_validityr   Zsigned_attrs)Zsd_attr_certificatesrt   r   Zsd_signed_attrs)rF   rw   r   rv   r   r   r   ZPADESr   r   r$   rX   rb   updaterz   r,   Zdefault_usage_constraintsr"   rL   ZvalidZtrustedr3   Zcertificate_registryZregister_multiplers   r#   rr   rt   )r   r   r   r   r   r   r   rF   r   r   Zts_status_kwargsr   Ztst_validityr   Z	sv_updater<   r<   r=   r1     sz    -

  
    


)r   r   r   r   r6   c                    sr   | j dkrtd| jdd}t|tjfd | j||d t| j	|| 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   ra   ri   )rw   r   rF   rv   r   r   ZETSI_RFC3161r   r)   rL   rb   ra   ri   r+   )r   r   r   r   r   r   r<   r<   r=   r2   |  s,    
   


)NNNNNF)NNF)N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   errorsr   r    r!   Zgeneric_cmsr"   r#   r$   r%   r&   r'   r(   r)   settingsr*   statusr+   r,   r-   __all__	getLoggerr   r   rS   r>   rE   r   r4   r.   r/   r0   r   boolr3   r   r1   r2   r<   r<   r<   r=   <module>   s    (
    
   7 	  !       m   