
    WwgK                     \   d Z 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
 ddlmZmZ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 ddlmZ g dZ ej>                  e       Z! G d de"      Z# G d de#      Z$ G d de#      Z%d Z& G d de'      Z( G d de"      Z)d Z*d Z+dejX                  dejZ                  fdZ.	 d=dejX                  dej^                  fdZ0dejX                  de
ejb                  ejd                  f   fd Z3d!e
ejh                  ejj                  f   dejX                  de6fd"Z7 G d# d$e"      Z8 G d% d&e8      Z9de
ejt                     fd'Z;	 d>de
ejt                  ef   fd(Z<d)ede=fd*Z>	 d>d+ej~                  fd,Z@dejX                  d-e=dej~                  fd.ZA ed/0       G d1 d2             ZBd3ej                  fd4ZDd5 ZEd6ej                  dej                  fd7ZHd6ej                  deBfd8ZIej                  fd9ed:eeK   d;e=de	eKeLf   fd<ZMy)?a  
General tools related to Cryptographic Message Syntax (CMS) signatures,
not necessarily to the extent implemented in the PDF specification.

CMS is defined in :rfc:`5652`. To parse CMS messages, pyHanko relies heavily on
`asn1crypto <https://github.com/wbond/asn1crypto>`_.
    N)	dataclass)IOIterableListTupleUnion)algoscmstspx509)SignedDigestAlgorithm)hashesserialization)padding)RSAPublicKey)	Prehashed)*)misc)simple_cms_attributefind_cms_attributefind_unique_cms_attributeNonexistentAttributeErrorMultivaluedAttributeErrorSigningErrorUnacceptableSignerErrorSignedDataCertsextract_signer_infoextract_certificate_infoget_cms_hash_algo_for_mechanismget_pyca_cryptography_hash&get_pyca_cryptography_hash_for_signingoptimal_pss_paramsprocess_pss_paramsas_signing_certificateas_signing_certificate_v2match_issuer_serialcheck_ess_certidCMSExtractionErrorbyte_range_digestValueErrorWithMessageCMSStructuralErrorload_cert_from_pemderload_certs_from_pemderload_certs_from_pemder_dataload_private_key_from_pemder!load_private_key_from_pemder_datac                   "     e Zd ZdZ fdZ xZS )r*   z
    Value error with a failure message attribute that can be conveniently
    extracted, instead of having to rely on extracting exception args
    generically.
    c                 D    t        |      | _        t        |   |       y N)strfailure_messagesuper__init__)selfr5   	__class__s     K/var/www/horilla/myenv/lib/python3.12/site-packages/pyhanko/sign/general.pyr7   zValueErrorWithMessage.__init__B   s    "?3)    )__name__
__module____qualname____doc__r7   __classcell__r9   s   @r:   r*   r*   ;   s    * *r;   r*   c                       e Zd ZdZy)r+   z!Structural error in a CMS object.Nr<   r=   r>   r?    r;   r:   r+   r+   G   s    +r;   r+   c                       e Zd Zy)r(   Nr<   r=   r>   rD   r;   r:   r(   r(   K       r;   r(   c                 Z    t        j                  t        j                  |       |fd      S )a  
    Convenience method to quickly construct a CMS attribute object with
    one value.

    :param attr_type:
        The attribute type, as a string or OID.
    :param value:
        The value.
    :return:
        A :class:`.cms.CMSAttribute` object.
    )typevalues)r
   CMSAttributeCMSAttributeType)	attr_typevalues     r:   r   r   O   s,     %%i0UHE r;   c                       e Zd Zy)r   NrF   rD   r;   r:   r   r   `   rG   r;   r   c                       e Zd Zy)r   NrF   rD   r;   r:   r   r   d   rG   r;   r   c                     d}| r0| D ]+  }|d   j                   |k(  s|t        d|d      |d   }- ||S t        d| d      )a  
    Find and return CMS attribute values of a given type.

    .. note::
        This function will also check for duplicates, but not in the sense
        of multivalued attributes. In other words: multivalued attributes
        are allowed; listing the same attribute OID more than once is not.

    :param attrs:
        The :class:`.cms.CMSAttributes` object.
    :param name:
        The attribute type as a string (as defined in ``asn1crypto``).
    :return:
        The values associated with the requested type, if present.
    :raise NonexistentAttributeError:
        Raised when no such type entry could be found in the
        :class:`.cms.CMSAttributes` object.
    :raise CMSStructuralError:
        Raised if the given OID occurs more than once.
    NrI   z
Attribute z was duplicatedrJ   zUnable to locate attribute .)nativer+   r   )attrsnamefound_valuesattrs       r:   r   r   h   sz    , L 	.DF|""d*+,$THO<   $H~	. '*EdV1(MNNr;   c                 v    t        | |      }t        |      dk7  rt        d| dt        |       d      |d   S )a   
    Find and return a unique CMS attribute value of a given type.

    :param attrs:
        The :class:`.cms.CMSAttributes` object.
    :param name:
        The attribute type as a string (as defined in ``asn1crypto``).
    :return:
        The value associated with the requested type, if present.
    :raise NonexistentAttributeError:
        Raised when no such type entry could be found in the
        :class:`.cms.CMSAttributes` object.
    :raise MultivaluedAttributeError:
        Raised when the attribute's cardinality is not 1.
       zExpected single-valued z attribute, but found z valuesr   )r   lenr   )rT   rU   rJ   s      r:   r   r      sO       t,F
6{a'%dV+A6{m7$
 	
 !9r;   certreturnc           
         t        j                  dt        j                  t        j                  | j                               j                         t        j                  d| j                  i      g| d   d   dd      gi      S )a  
    Format an ASN.1 ``SigningCertificate`` object, where the certificate
    is identified by its SHA-1 digest.

    :param cert:
        An X.509 certificate.
    :return:
        A :class:`tsp.SigningCertificate` object referring to the original
        certificate.
    certsdirectory_nametbs_certificateserial_numberissuerra   )	cert_hashissuer_serial)
r   SigningCertificate	ESSCertIDhashlibsha1dumpdigestr   GeneralNamerc   )r[   s    r:   r$   r$      s     !!%,\\$))+%>%E%E%G !% 0 0%5t{{$C!"'
 .22C-D /.	*	
 r;   c                 T   t        |      }t        j                  |      }|j                  | j	                                |j                         }t        j                  dt        j                  d|i|t        j                  d| j                  i      g| d   d   dd      gi      S )a  
    Format an ASN.1 ``SigningCertificateV2`` value, where the certificate
    is identified by the hash algorithm specified.

    :param cert:
        An X.509 certificate.
    :param hash_algo:
        Hash algorithm to use to digest the certificate.
        Default is SHA-256.
    :return:
        A :class:`tsp.SigningCertificateV2` object referring to the original
        certificate.
    r^   	algorithmr_   r`   ra   rb   )hash_algorithmrd   re   )r    r   Hashupdaterj   finalizer   SigningCertificateV2ESSCertIDv2r   rl   rc   )r[   	hash_algo	hash_specmddigest_values        r:   r%   r%      s    $ +95I	Y	BIIdiik;;=L##+6	*B%1 !% 0 0%5t{{$C!"'
 .22C-D /.	*	
 r;   certidc                 T   t        |t        j                        rd}n|d   d   j                  }t	        |      }t        j                  |      }|j                  | j                                |j                         }|d   j                  }||k7  ry|d   }| xs t        ||       S )a  
    Match an ``ESSCertID`` value against a certificate.

    :param cert:
        The certificate to match against.
    :param certid:
        The ``ESSCertID`` value.
    :return:
        ``True`` if the ``ESSCertID`` matches the certificate,
        ``False`` otherwise.
    ri   ro   rn   rd   Fre   )
isinstancer   rg   rS   r    r   rp   rq   rj   rr   r&   )r[   ry   ru   rv   rw   rx   expected_digest_valueexpected_issuer_serials           r:   r'   r'      s     &#--(	+,[9@@	*95I	Y	BIIdiik;;=L";/66,,/5o/F%% )<* r;   r}   c                 d   |d   d   }| d   }t        |t        j                        r0t        |      dk7  s|d   j                  dk7  ry|d   j
                  }	 |j                         |j                  j                         k(  xs ||j                  k(  }|xr | d   |k(  S # t        $ r d}Y w xY w)a~  
    Match the issuer and serial number of an X.509 certificate against some
    expected identifier.

    :param expected_issuer_serial:
        A certificate identifier, either :class:`cms.IssuerAndSerialNumber`
        or :class:`tsp.IssuerSerial`.
    :param cert:
        An :class:`x509.Certificate`.
    :return:
        ``True`` if there's a match, ``False`` otherwise.
    r`   ra   rc   rY   r   r_   F)	r{   r   GeneralNamesrZ   rU   chosenrj   rc   
ValueError)r}   r[   serial_asn1expected_issuerissuer_matchs        r:   r&   r&     s    & ()/:K,X6O /4#4#45 A%q!&&*::)!,33  "dkk&6&6&88 .$++- 	 	O/@KO  s   <B! !B/.B/c                   (     e Zd ZdZdef fdZ xZS )r   z1
    Error encountered while signing a file.
    msgc                 4    || _         t        |   |g|  y r3   )r   r6   r7   )r8   r   argsr9   s      r:   r7   zSigningError.__init__Q  s    $t$r;   )r<   r=   r>   r?   r4   r7   r@   rA   s   @r:   r   r   L  s    %C % %r;   r   c                       e Zd ZdZy)r   z=
    Error raised when a signer was judged unacceptable.
    NrC   rD   r;   r:   r   r   V  s     	r;   r   c                     | j                         dv rt        j                  d      S  t        t        | j	                                      S )N)shake256shake256_len@   )digest_size)lowerr   SHAKE256getattrupperrn   s    r:   r    r    ^  s<    88 2..1wvy0133r;   c                 6    t        |       }|rt        |      S |S r3   )r    r   )rn   	prehashedru   s      r:   r!   r!   g  s      +95I#,9Y;);r;   mechc                 J    | j                   }|dk(  ry|dk(  ry| j                  S )a%  
    Internal function that takes a :class:`.SignedDigestAlgorithm` instance
    and returns the name of the digest algorithm that has to be used to compute
    the ``messageDigest`` attribute.

    :param mech:
        A signature mechanism.
    :return:
        A digest algorithm name.
    ed25519sha512ed448r   )signature_algoru   )r   sig_algos     r:   r   r   n  s/     ""H9	W	~~r;   paramsc                    | d   }|d   j                   }|j                         |j                         k7  rt        d| d| d      | d   }|d   j                   dk(  st        d      |d	   d   j                   }||k7  rt        j                  d
| d| d       | d   j                   }t        |      }t        ||      }	t        j                  t        j                  |      |      }
|
|	fS )zs
    Extract PSS padding settings and message digest from an
    ``RSASSAPSSParams`` value.

    Internal API.
    ro   rn   zPSS MD 'z ' must agree with signature MD 'z'.mask_gen_algorithmmgf1zOnly MFG1 is supported
parameterszMessage digest for MGF1 is z", and the one used for signing is zL. If these do not agree, some software may refuse to validate the signature.salt_length)r   r   )mgfr   )rS   casefoldr   NotImplementedErrorloggerwarningr    r!   r   PSSMGF1)r   digest_algorithmr   ru   md_namemgamgf_md_namesalt_lenmgf_mdrw   pss_paddings              r:   r#   r#     s     (..>'?I$++G-6688wi  #$B(
 	
 #))=">C{""f,!":;;l#K077Kg)+ 7! #01	

 =)00H'4F	/9	MB++LL6*K ?r;   r   c           
         |j                         }t        j                  | j                  j	                               }t        |t              st        dt        |             t        |      }t        j                  ||      }t        j                  t        j                  d|i      t        j                  dt        j                  d|i      d      |d      S )a"  
    Figure out the optimal RSASSA-PSS parameters for a given certificate.
    The subject's public key must be an RSA key.

    :param cert:
        An RSA X.509 certificate.
    :param digest_algorithm:
        The digest algorithm to use.
    :return:
        RSASSA-PSS parameters.
    z&Expected RSA key, but got key of type rn   r   )rn   r   )ro   r   r   )r   r   load_der_public_key
public_keyrj   r{   r   r   rI   r    r   calculate_max_pss_salt_lengthr	   RSASSAPSSParamsDigestAlgorithmMaskGenAlgorithm)r[   r   keyrw   optimal_salt_lens        r:   r"   r"     s     (--/

+
+DOO,@,@,B
CCc<(CDI;OPP	#$4	5B <<S"E  #33./ #("8"8!'"'"7"7$&67## ,	
 r;   T)frozenc                   |    e Zd ZU dZej
                  ed<   	 eej
                     ed<   	 eej                     ed<   y)r   zT
    Value type to describe certificates included in a CMS signed data payload.
    signer_certother_certsattribute_certsN)
r<   r=   r>   r?   r   Certificate__annotations__r   r
   AttributeCertificateV2rD   r;   r:   r   r     sJ     !!! d&&'' #4455r;   r   sidc                       j                   dk(  r fdS  j                   dk(  r0 j                  j                  t        j	                  d       fdS t
        )Nissuer_and_serial_numberc                 0    t        j                  |       S r3   )r&   r   )cr   s    r:   <lambda>z'_get_signer_predicate.<locals>.<lambda>  s    ,SZZ; r;   subject_key_identifierzThe signature in this SignedData value seems to be identified by a subject key identifier --- this is legal in CMS, but many PDF viewers and SDKs do not support this feature.c                 "    | j                   k(  S r3   )key_identifier)r   skis    r:   r   z'_get_signer_predicate.<locals>.<lambda>  s    ))S0 r;   )rU   r   rS   r   r   r   )r   r   s   `@r:   _get_signer_predicater     sS    
xx--;;	-	- jj<	

 10
r;   c                     t        |d         }d }g }| D ]  } ||      r|}|j                  |         |t        d      ||fS )Nr   z,signer certificate not included in signature)r   appendr(   )r^   signer_info	predicater[   r   r   s         r:   _partition_certsr     sd    
 &k%&89IDK "Q<Dq!	"
 | !OPPr;   signed_datac                 F    	 | d   \  }|S # t         $ r t        d      w xY w)a5  
    Extract the unique ``SignerInfo`` entry of a CMS signed data value, or
    throw a ``ValueError``.

    :param signed_data:
        A CMS ``SignedData`` value.
    :return:
        A CMS ``SignerInfo`` value.
    :raises ValueError:
        If the number of ``SignerInfo`` values is not exactly one.
    signer_infosz-signer_infos should contain exactly one entry)r   r(   )r   r   s     r:   r   r     s8    
$^4 
 ;
 	

s     c                 *   g }g }| d   D ]^  }|j                   j                         }|j                  dk(  r|j                  |       >|j                  dk(  sN|j                  |       ` t	        |       }t        ||      \  }}t        |||      }|S )a  
    Extract and classify embedded certificates found in the ``certificates``
    field of the signed data value.

    :param signed_data:
        A CMS ``SignedData`` value.
    :return:
        A :class:`SignedDataCerts` object containing the embedded certificates.
    certificatescertificatev2_attr_cert)r   r   r   )r   untagrU   r   r   r   r   )	r   r^   
attr_certsr   r[   r   r   r   	cert_infos	            r:   r   r   #  s     EJ( $xx~~66]"LLVV~%d#$ &k2K/{CK"I
 r;   stream
byte_rangemd_algorithmc                    t        |      }t        j                  |      }d}t        |      }t	        j
                  |      D ]4  \  }}	| j                  |       t	        j                  || ||	       ||	z  }6 ||j                         fS )a  
    Internal API to compute byte range digests. Potentially dangerous if used
    without due caution.

    :param stream:
        Stream over which to compute the digest. Must support seeking and
        reading.
    :param byte_range:
        The byte range, as a list of (offset, length) pairs, flattened.
    :param md_algorithm:
        The message digest algorithm to use.
    :param chunk_size:
        The I/O chunk size to use.
    :return:
        A tuple of the total digested length, and the actual digest.
    r   )max_read)	r    r   rp   	bytearrayr   	pair_iterseekchunked_digestrr   )
r   r   r   
chunk_sizemd_specrw   	total_len	chunk_buflo	chunk_lens
             r:   r)   r)   @  s    , )6G	W	B
 I*%I
3 IBIvrIFY	
 bkkm##r;   )sha256)F)Nr?   rh   loggingdataclassesr   typingr   r   r   r   r   
asn1cryptor	   r
   r   r   asn1crypto.algosr   cryptography.hazmat.primitivesr   r   )cryptography.hazmat.primitives.asymmetricr   -cryptography.hazmat.primitives.asymmetric.rsar   /cryptography.hazmat.primitives.asymmetric.utilsr   pyhanko.keyspyhanko.pdf_utilsr   __all__	getLoggerr<   r   r   r*   r+   r(   r   KeyErrorr   r   r   r   r   rf   r$   rs   r%   rg   rt   r'   IssuerAndSerialNumberIssuerSerialboolr&   r   r   HashAlgorithmr    r!   r4   r   r   r#   r"   r   SignerIdentifierr   r   
SignedData
SignerInfor   r   DEFAULT_CHUNK_SIZEintbytesr)   rD   r;   r:   <module>r     s     ! 3 3 , , 2 @ = F E  "@ 
		8	$	*J 	*,. ,	. 	"	 		
 	#OL2 !1!1  c6L6L  H '/+


++\


$)#--*H$I@1!#";";S=M=M"MN1


1 
1h%: %	l 	4U63G3G-H 4 <
6*+<*? C 0 @E$!!$N'


'.1'
'T $  *s33  $
S^^ 
 
*#.. _ B &&	#$#$#$ #$
 3:#$r;   