
    CsiC                        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mZmZmZmZ ddlm Z  ddl!m"Z" g dZ# ejH                  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 Z0dejb                  dejd                  fdZ3	 d9dejb                  dejh                  fdZ5dejb                  de
ejl                  ejn                  f   fd Z8d!e
ejr                  ejt                  f   dejb                  de;fd"Z< G d# d$e'      Z= G d% d&e=      Z>d'ede?fd(Z@dejb                  d)e?dej                  fd*ZB ed+,       G d- d.             ZCd/ej                  fd0ZEd1 ZFd2ej                  dej                  fd3ZId2ej                  deCfd4ZJe j                  fd5ed6eeL   d7e?de	eLeMf   fd8ZNy):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)load_cert_from_pemderload_certs_from_pemderload_certs_from_pemder_dataload_private_key_from_pemder!load_private_key_from_pemder_data)misc)get_pyca_cryptography_hash)CMSExtractionErrorCMSStructuralErrorMultivaluedAttributeErrorNonexistentAttributeErrorSignedDataCertsSigningErrorUnacceptableSignerErrorValueErrorWithMessageas_signing_certificateas_signing_certificate_v2byte_range_digestcheck_ess_certidextract_certificate_infoextract_signer_infofind_cms_attributefind_unique_cms_attributeget_cms_hash_algo_for_mechanismr   r   r   r   r   match_issuer_serialoptimal_pss_paramssimple_cms_attributec                   "     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__)selfr1   	__class__s     `/var/www/python-projects/worksol/worksolenv/lib/python3.12/site-packages/pyhanko/sign/general.pyr3   zValueErrorWithMessage.__init__D   s    "?3)    )__name__
__module____qualname____doc__r3   __classcell__r5   s   @r6   r    r    =   s    * *r7   r    c                       e Zd ZdZy)r   z!Structural error in a CMS object.Nr8   r9   r:   r;    r7   r6   r   r   I   s    +r7   r   c                       e Zd Zy)r   Nr8   r9   r:   r@   r7   r6   r   r   M       r7   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     r6   r,   r,   Q   s,     %%i0UHE r7   c                       e Zd Zy)r   NrB   r@   r7   r6   r   r   b   rC   r7   r   c                       e Zd Zy)r   NrB   r@   r7   r6   r   r   f   rC   r7   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.
    NrE   z
Attribute z was duplicatedrF   zUnable to locate attribute .)nativer   r   )attrsnamefound_valuesattrs       r6   r'   r'   j   sz    , L 	.DF|""d*+,$THO<   $H~	. '*EdV1(MNNr7   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   )rP   rQ   rF   s      r6   r(   r(      sO       t,F
6{a'%dV+A6{m7$
 	
 !9r7   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issuerr]   )	cert_hashissuer_serial)
r   SigningCertificate	ESSCertIDhashlibsha1dumpdigestr   GeneralNamer_   )rW   s    r6   r!   r!      s     !!%,\\$))+%>%E%E%G !% 0 0%5t{{$C!"'
 .22C-D /.	*	
 r7   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.
    rZ   	algorithmr[   r\   r]   r^   )hash_algorithmr`   ra   )r   r   Hashupdaterf   finalizer   SigningCertificateV2ESSCertIDv2r   rh   r_   )rW   	hash_algo	hash_specmddigest_values        r6   r"   r"      s    $ +95I	Y	BIIdiik;;=L##+6	*B%1 !% 0 0%5t{{$C!"'
 .22C-D /.	*	
 r7   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.
    re   rk   rj   r`   Fra   )
isinstancer   rc   rO   r   r   rl   rm   rf   rn   r*   )rW   ru   rq   rr   rs   rt   expected_digest_valueexpected_issuer_serials           r6   r$   r$      s     &#--(	+,[9@@	*95I	Y	BIIdiik;;=L";/66,,/5o/F%% )<* r7   ry   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\   r]   r_   rU   r   r[   F)	rw   r   GeneralNamesrV   rQ   chosenrf   r_   
ValueError)ry   rW   serial_asn1expected_issuerissuer_matchs        r6   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 r/   )r   r2   r3   )r4   r   argsr5   s      r6   r3   zSigningError.__init__S  s    $t$r7   )r8   r9   r:   r;   r0   r3   r<   r=   s   @r6   r   r   N  s    %C % %r7   r   c                       e Zd ZdZy)r   z=
    Error raised when a signer was judged unacceptable.
    Nr?   r@   r7   r6   r   r   X  s     	r7   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ed448shake256)signature_algorq   )r   sig_algos     r6   r)   r)   `  s/     ""H9	W	~~r7   digest_algorithmc           
         |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 rj   mgf1)rj   
parameters)rk   mask_gen_algorithmsalt_length)lowerr   load_der_public_key
public_keyrf   rw   r   r   rE   r   r   calculate_max_pss_salt_lengthr	   RSASSAPSSParamsDigestAlgorithmMaskGenAlgorithm)rW   r   keyrs   optimal_salt_lens        r6   r+   r+   w  s     (--/

+
+DOO,@,@,B
CCc<(CDI;OPP	#$4	5B<<S"E  #33./ #("8"8!'"'"7"7$&67## ,	
 r7   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)
r8   r9   r:   r;   r   Certificate__annotations__r   r
   AttributeCertificateV2r@   r7   r6   r   r     sJ     !!! d&&'' #4455r7   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 r/   )r*   r|   )cr   s    r6   <lambda>z'_get_signer_predicate.<locals>.<lambda>  s    ,SZZ; r7   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 r/   )key_identifier)r   skis    r6   r   z'_get_signer_predicate.<locals>.<lambda>  s    ))S0 r7   )rQ   r|   rO   loggerwarningNotImplementedError)r   r   s   `@r6   _get_signer_predicater     sS    
xx--;;	-	- jj<	

 10
r7   c                     t        |d         }d }g }| D ]  } ||      r|}|j                  |         |t        d      ||fS )Nr   z,signer certificate not included in signature)r   appendr   )rZ   signer_info	predicaterW   r   r   s         r6   _partition_certsr     sd    
 &k%&89IDK "Q<Dq!	"
 | !OPPr7   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     r6   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|   untagrQ   r   r&   r   r   )	r   rZ   
attr_certsr   rW   r   r   r   	cert_infos	            r6   r%   r%     s     EJ( $xx~~66]"LLVV~%d#$ &k2K/{CK"I
 r7   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   rl   	bytearrayr   	pair_iterseekchunked_digestrn   )
r   r   r   
chunk_sizemd_specrs   	total_len	chunk_buflo	chunk_lens
             r6   r#   r#   
  s    , )6G	W	B
 I*%I
3 IBIvrIFY	
 bkkm##r7   )sha256)Or;   rd   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   pyhanko.keysr   r   r   r   r   pyhanko.pdf_utilsr   pyhanko_certvalidator.utilr   __all__	getLoggerr8   r   r}   r    r   r   r,   KeyErrorr   r   r'   r(   r   rb   r!   ro   r"   rc   rp   r$   IssuerAndSerialNumberIssuerSerialboolr*   r   r   r0   r)   r   r+   r   SignerIdentifierr   r   
SignedData
SignerInfor&   r%   DEFAULT_CHUNK_SIZEintbytesr#   r@   r7   r6   <module>r      sY     ! 3 3 , , 2 @ = F  # A: 
		8	$	*J 	*,. ,	. 	"	 		
 	#OL2 !1!1  c6L6L  H '/+


++\


$)#--*H$I@1!#";";S=M=M"MN1


1 
1h%: %	l 	*? C .&


&.1&
&R $  *s33  $
S^^ 
 
*#.. _ B &&	#$#$#$ #$
 3:#$r7   