U
    <gc                  
   @   s.  d Z ddlZddlZddl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mZmZmZ ddlZddlmZmZmZ ddlm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! ddl"m#Z#m$Z$ ddl%m&Z& z@ddlm'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z- ddlm.Z/ ddlm0Z1 W n. e2k
rJ Z3 ze2de3W 5 dZ3[3X Y nX dddddgZ4e5e6Z7ee e1j8eee9e9f  dddZ:ee e1j8e;dddZ<d1ee1j= ee> ee ee1j8 dddZ?eddG dd  d Z@e*jAe*jBe*jCe*jDe*jEd!ZFe*jGe*jHe*jIe*jJe*jKd!ZLe'jMe'jNe'jOe'jPe'jQd!ZRe*jSe*jTe*jUe*jVe*jWd!ZXe*jYe*jZe*j[e*j\e*j]d!Z^e*j_e*jNe*jOe*jPe*jQd!Z`ejae9e;e@d"d#dZbd2e9ee> ee9 ee ee9ecdf e-d$d%dZdd3e;ee9 eee d&d'd(Zfd4e-ee9 eee d)d*d+Zge9e;d,d-d.ZhG d/d de&ZiG d0d dZjdS )5z
This module provides PKCS#11 integration for pyHanko, by providing a wrapper
for `python-pkcs11 <https://github.com/danni/python-pkcs11>`_ that can be
seamlessly plugged into a :class:`~.signers.PdfSigner`.
    N)	dataclass)AnyCallableDictListOptionalSetTupleUnion)algoscorex509)RSASSAPSSParams)hashes)CertificateStore)PKCS11PinEntryModePKCS11SignatureConfigTokenCriteria)coalesce)SigningErrorget_pyca_cryptography_hash)Signer)MGFPROTECTED_AUTH	Attribute	MechanismObjectClassPKCS11ErrorSession)lib)typeszpyhanko.sign.pkcs11 requires pyHanko to be installed with the [pkcs11] option. You can install missing dependencies by running "pip install 'pyHanko[pkcs11]'".PKCS11Signeropen_pkcs11_sessionPKCS11SigningContext
find_tokenselect_pkcs11_signing_params)criteriatokenreturnc                 C   sd   | d krg S g }| j d k	r6|j | j kr6|d| j f | jd k	r`|j| jkr`|d| j f |S )Nlabelserial)r)   appendr*   hex)r&   r'   Z	err_items r-   7/tmp/pip-unpacked-wheel-w101_d3s/pyhanko/sign/pkcs11.pycriteria_mismatches=   s    r/   c                 C   s   t | | S N)r/   )r&   r'   r-   r-   r.   criteria_satisfied_byL   s    r1   )slotsslot_notoken_criteriar(   c              	   C   s   |dkr0|dkr0t | dkr(| d  S td|dkr~| D ]>}z | }t||r^|W   S W q< tk
rx   Y q<Y q<X q<nl|t | krtd| dt |  | |  }t||}|rddd	 |D }td
| d| d|S dS )a  
    Internal helper method to find a token.

    :param slots:
        The list of slots.
    :param slot_no:
        Slot number to use. If not specified, the first slot containing a token
        satisfying the criteria will be used
    :param token_criteria:
        Criteria the token must satisfy.
    :return:
        A PKCS#11 token object, or ``None`` if none was found.
    N   r   zJModule has more than 1 slot; slot index or token criteria must be providedzSlot index z too large; there are only , c                 s   s    | ]\}}| d |V  qdS )z is not Nr-   ).0fieldvalr-   r-   r.   	<genexpr>~   s    zfind_token.<locals>.<genexpr>zToken in slot z does not satisfy criteria; .)len	get_tokenr   r1   r/   join)r2   r3   r4   Zslotr'   errorserr_strr-   r-   r.   r$   R   s:    


T)frozenc                   @   sN   e Zd ZU dZeeef ed< ee	e
ge
f  ed< ee	e
ge
f  ed< dS )PKCS11SignatureOperationSpeczq
    Internal helper class to describe how to invoke a signature operation on
    a key in a PKCS #11 token.
    sign_kwargspre_sign_transformpost_sign_transformN)__name__
__module____qualname____doc__r   strr   __annotations__r   r   bytesr-   r-   r-   r.   rB      s
   
rB   )sha1sha224sha256sha384sha512)signature_mechanismdigest_algorithmuse_raw_mechanismr(   c                 C   s  ddl m} ddlm} d}d}i }z
| j}W n tk
rL   | d j}Y nX |dkr|rrtj|d< t	|dd	}nt
| |d< nZ|d
kr|rtj|d< t	|dd	}nt| |d< |}n"|dkr|rtj|d< t	|dd	}nt| |d< |}n|dkrp|rtd| d }	||	d d jks(tt| |d< t| }
|	d d d j}t| }|	d j}|
||f|d< nl|dkr|rtdtj|d< nH|dkr|rtdtj|d< tdddd|d< ntd| dt|||dS )aZ  
    Internal helper function to set up a PKCS #11 signing operation.

    :param signature_mechanism:
        The signature mechanism to use (as an ASN.1 value)
    :param digest_algorithm:
        The digest algorithm to use
    :param use_raw_mechanism:
        Whether to attempt to use the raw mechanism on pre-hashed data.
    :return:
    r   )encode_dsa_signature)encode_ecdsa_signatureN	algorithmZrsassa_pkcs1v15Z	mechanismT)wrap_digest_infodsaFZecdsaZ
rsassa_pssz$RSASSA-PSS not available in raw mode
parametershash_algorithmZmask_gen_algorithmsalt_lengthZmechanism_paramed25519z!Ed25519 not available in raw modeed448zEd448 not available in raw modez@?LPzSignature algorithm 'z' is not supported.)rC   rD   rE   )Zpkcs11.util.dsarU   Zpkcs11.util.ecrV   signature_algo
ValueErrorZnativer   ZRSA_PKCS_hash_fullyRSA_MECH_MAPDSADSA_MECH_MAPECDSAECDSA_MECH_MAPNotImplementedErrorAssertionErrorRSASSA_PSS_MECH_MAPDIGEST_MECH_MAPMGF_MECH_MAPZEDDSAstructpackrB   )rR   rS   rT   rU   rV   rD   rE   kwargsr_   paramsZpss_digest_paramZmgf_valZpss_mgf_paramZpss_salt_lenr-   r-   r.   r%      s    

 
 
 






)lib_locationr3   token_labelr4   user_pinr(   c           	      C   s   t | }|dkr.|dk	r.tdt t|d}| }t|||d}|dkrht|dk	rbd|dndi }|dk	r|||d< |jf |S )	a  
    Open a PKCS#11 session

    :param lib_location:
        Path to the PKCS#11 module.
    :param slot_no:
        Slot number to use. If not specified, the first slot containing a token
        labelled ``token_label`` will be used.
    :param token_label:
        .. deprecated:: 0.14.0
            Use ``token_criteria`` instead.

        Label of the token to use. If ``None``, there is no constraint.
    :param token_criteria:
        Criteria that the token should match.
    :param user_pin:
        User PIN to use, or :attr:`.PROTECTED_AUTH`. If ``None``, authentication
        is skipped.

        .. note::
            Some PKCS#11 implementations do not require PIN when the token
            is opened, but will prompt for it out-of-band when signing.
            Whether :attr:`.PROTECTED_AUTH` or ``None`` is used in this case
            depends on the implementation.
    :return:
        An open PKCS#11 session object.
    Nz9'token_label' is deprecated, use 'token_criteria' instead)r)   )r3   r4   zNo token matching criteria z foundzNo token foundrr   )	p11_libwarningswarnDeprecationWarningr   Z	get_slotsr$   r   open)	rp   r3   rq   r4   rr   r   r2   r'   rn   r-   r-   r.   r"   @  s&    "

no_resultsr)   cert_idc                 C   s~   g }|d k	r| d| d |d k	rD| dt|d d |rXdd| nd}| rnd| d	}nd
| d	}|S )Nzlabel ''zID 'asciiz with r6    zCould not find certr;   zFound more than one cert)r+   binasciihexlifydecoder>   )ry   r)   rz   Z	info_strsZ	qualifiererrr-   r-   r.   _format_pull_err_msg{  s    r   )pkcs11_sessionr)   rz   c                 C   s   t jtji}|d k	r||t j< |d k	r0||t j< | |}t|}t|dkrh|d }t	j
|t j S t| ||d}t|d S )Nr5   r   rx   )r   CLASSr   CERTIFICATELABELZIDget_objectslistr<   r   CertificateloadVALUEr   r   )r   r)   rz   Zquery_paramsqresultscert_objr   r-   r-   r.   
_pull_cert  s     


  r   )rS   rX   c                   s$   t  ttd fdd}|S )N)datar(   c                    sJ   t }||  | }rBt  t d|d	 S |S d S )N)rW   rZ   )rS   digest)
r   Hashupdatefinalizer   Z
DigestInfolowerr   ZNulldump)r   hr   rS   Zmd_specrX   r-   r.   _h  s    


z_hash_fully.<locals>._h)r   rL   )rS   rX   r   r-   r   r.   ra     s    ra   c                       s   e Zd ZdZdeee eej ee ee	 ee	 ee
j d fddZd	d
 ZeedddZedd ZeedddZde	ee	dddZeej dddZdd Zdd Zdd Z  ZS ) r!   a  
    Signer implementation for PKCS11 devices.

    :param pkcs11_session:
        The PKCS11 session object to use.
    :param cert_label:
        The label of the certificate that will be used for signing, to
        be pulled from the PKCS#11 token.
    :param cert_id:
        ID of the certificate object that will be used for signing, to
        be pulled from the PKCS#11 token.
    :param signing_cert:
        The signer's certificate. If the signer's certificate is provided via
        this parameter, the ``cert_label`` and ``cert_id`` parameters will not
        be used to retrieve the signer's certificate.
    :param ca_chain:
        Set of other relevant certificates
        (as :class:`.asn1crypto.x509.Certificate` objects).
    :param key_label:
        The label of the key that will be used for signing.
        Defaults to the value of ``cert_label`` if left unspecified and
        ``key_id`` is also unspecified.

        .. note::
            At least one of ``key_id``, ``key_label`` and ``cert_label`` must
            be supplied.
    :param key_id:
        ID of the private key object (optional).
    :param other_certs_to_pull:
        List labels of other certificates to pull from the PKCS#11 device.
        Defaults to the empty tuple. If ``None``, pull *all* certificates.
    :param bulk_fetch:
        Boolean indicating the fetching strategy.
        If ``True``, fetch all certs and filter the unneeded ones.
        If ``False``, fetch the requested certs one by one.
        Default value is ``True``, unless ``other_certs_to_pull`` has one or
        fewer elements, in which case it is always treated as ``False``.
    :param use_raw_mechanism:
        Use the 'raw' equivalent of the selected signature mechanism. This is
        useful when working with tokens that do not support a hash-then-sign
        mode of operation.

        .. note::
            This functionality is only available for ECDSA at this time.
            Support for other signature schemes will be added on an as-needed
            basis.
    NFTr-   )r   
cert_labelsigning_cert	key_labelkey_idrz   rR   c                    s   t ||s|nd| _t |
|s |nd| _t ||s4|
nd| _t ||
sH|nd| _|| _|| _d| _|dk	r~t|dkr~d| _	n|	| _	|| _
d| _d| _d| _t j||||d |dk	r| j| |dk	r| j| dS )z-
        Initialise a PKCS11 signer.
        NFr5   )
prefer_pssembed_rootsr   rR   )r   r   r   rz   r   r   other_certs_other_certs_loadedr<   
bulk_fetchrT   _key_handle_loaded_PKCS11Signer__loading_eventsuper__init___cert_registryregister_multipleregister)selfr   r   r   ca_chainr   r   r   other_certs_to_pullr   r   rz   rT   rR   	__class__r-   r.   r     s6     
zPKCS11Signer.__init__c                 C   s&   | j s |  }| j| d| _ | jS )NT)r   _load_other_certsr   r   )r   certsr-   r-   r.   _init_cert_registry   s
    z PKCS11Signer._init_cert_registryr(   c                 C   s   |   S r0   )r   r   r-   r-   r.   cert_registry)  s    zPKCS11Signer.cert_registryc                 C   s   |    | jS r0   )_load_objects_signing_certr   r-   r-   r.   r   /  s    zPKCS11Signer.signing_cert)rS   r(   c                 C   s   |  }t| ||| jdS )N)rT   )r   r%   Z"get_signature_mechanism_for_digestrT   )r   rS   r-   r-   r.   _select_pkcs11_signing_params4  s    z*PKCS11Signer._select_pkcs11_signing_params)r   rS   r(   c                    sp   |rdS |   I d H  ddlm} | j| |jd k	rF   fdd}t }|d |I d H S )Ns   00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000r   )	SignMixinc                     s(   j  fj} jd k	r$| } | S r0   )signrC   rE   )	signaturer   khspecr-   r.   _perform_signatureN  s    

z7PKCS11Signer.async_sign_raw.<locals>._perform_signature)	ensure_objects_loadedpkcs11r   r   r   rD   asyncioget_running_looprun_in_executor)r   r   rS   dry_runr   r   loopr-   r   r.   async_sign_raw>  s    


zPKCS11Signer.async_sign_rawc                 C   s   t |  S r0   )set_PKCS11Signer__pullr   r-   r-   r.   r   W  s    zPKCS11Signer._load_other_certsc                 c   s   | j }|d k	rt|dkrd S |d ks,| jr| jtjtji}t	
d |D ]H}|tj }|d ksl||krNd| d}t	
| tj|tj V  qNn.|D ](}d| d}t	
| t| j|V  qd S )Nr   z.Pulling all certificates from PKCS#11 token...zFound certificate with label 'z' on token.z Pulling certificate with label 'z' from PKCS#11 token...)r   r<   r   r   r   r   r   r   r   loggerdebugr   r   r   r   r   r   )r   Zother_cert_labelsr   r   r)   msgr-   r-   r.   Z__pullZ  s&    





zPKCS11Signer.__pullc                    s\   | j r
dS | jdkrHt  | _}t }|d| jI dH  |  n| j I dH  dS )a  
        Async method that, when awaited, ensures that objects
        (relevant certificates, key handles, ...) are loaded.

        This coroutine is guaranteed to be called & awaited in :meth:`sign_raw`,
        but some property implementations may cause object loading to be
        triggered synchronously (for backwards compatibility reasons).
        This blocks the event loop the first time it happens.

        To avoid this behaviour, asynchronous code should ideally perform
        `await signer.ensure_objects_loaded()` after instantiating the signer.

        .. note::
            The asynchronous context manager on :class:`PKCS11SigningContext`
            takes care of that automatically.
        N)	r   r   r   Eventr   r   r   r   wait)r   eventr   r-   r-   r.   r   }  s    

z"PKCS11Signer.ensure_objects_loadedc                 C   sZ   | j r
d S |   | jd kr2t| j| j| jd| _| jjtj	| j
| jd}|| _d| _ d S )N)r)   rz   )r)   idT)r   r   r   r   r   r   rz   get_keyr   ZPRIVATE_KEYr   r   r   )r   r   r-   r-   r.   r     s     
    zPKCS11Signer._load_objects)NNNNFTr-   TNNFN)F)rF   rG   rH   rI   r   r   rJ   r   r   rL   r   SignedDigestAlgorithmr   r   propertyr   r   r   rB   r   r   r   r   r   r   r   __classcell__r-   r-   r   r.   r!     sP   3            /	
  #c                   @   s\   e Zd ZdZdeee dddZdd Ze	dd	d
Z
dd Zdd Zdd Zdd ZdS )r#   z+Context manager for PKCS#11 configurations.N)configrr   c                 C   s   || _ d | _|| _d S r0   )r   _session	_user_pin)r   r   rr   r-   r-   r.   r     s    zPKCS11SigningContext.__init__c                 C   s<   | j p| jj}|d k	r t|}n| jjtjkr4t}nd }|S r0   )r   r   rr   rJ   Z
prompt_pinr   ZDEFERr   )r   pinr-   r-   r.   _handle_pin  s    
z PKCS11SigningContext._handle_pinr   c                 C   s   | j }|  }z t|j|j|j|d | _}W nH tjk
rv } z(t	d|j dt
|j d| |W 5 d }~X Y nX t||j|j|j|j|j|j|j|j|j|j|jdS )N)r3   r4   rr   z'PKCS#11 error while opening session to z: [z] )
r   r   r   rT   r   r   r   rz   r   rR   )r   r   r"   module_pathr3   r4   r   r   r   r   typerF   r!   r   r   r   r   Zraw_mechanismr   r   r   rz   Zsigning_certificaterR   )r   r   r   sessionexr-   r-   r.   _instantiate  s:    z!PKCS11SigningContext._instantiatec                 C   s   |   S r0   )r   r   r-   r-   r.   	__enter__  s    zPKCS11SigningContext.__enter__c                    s.   t  }|d | jI d H }| I d H  |S r0   )r   r   r   r   r   )r   r   Zsignerr-   r-   r.   
__aenter__  s    zPKCS11SigningContext.__aenter__c                 C   s   | j   d S r0   r   closer   exc_typeexc_valexc_tbr-   r-   r.   __exit__  s    zPKCS11SigningContext.__exit__c                    s   | j   d S r0   r   r   r-   r-   r.   	__aexit__  s    zPKCS11SigningContext.__aexit__)N)rF   rG   rH   rI   r   r   rJ   r   r   r!   r   r   r   r   r   r-   r-   r-   r.   r#     s     )NN)NNNN)NN)NN)krI   r   r~   loggingrl   rt   dataclassesr   typingr   r   r   r   r   r   r	   r
   r   Z
asn1cryptor   r   r   Zasn1crypto.algosr   Zcryptography.hazmat.primitivesr   Zpyhanko_certvalidator.registryr   Zpyhanko.config.pkcs11r   r   r   Zpyhanko.pdf_utils.miscr   Zpyhanko.sign.generalr   r   Zpyhanko.sign.signersr   r   r   r   r   r   r   r   r   rs   r    Z	p11_typesImportErrore__all__	getLoggerrF   r   TokenrJ   r/   boolr1   ZSlotintr$   rB   ZSHA1_RSA_PKCSZSHA224_RSA_PKCSZSHA256_RSA_PKCSZSHA384_RSA_PKCSZSHA512_RSA_PKCSrb   ZSHA1_RSA_PKCS_PSSZSHA224_RSA_PKCS_PSSZSHA256_RSA_PKCS_PSSZSHA384_RSA_PKCS_PSSZSHA512_RSA_PKCS_PSSri   SHA1SHA224SHA256SHA384SHA512rk   Z
ECDSA_SHA1ZECDSA_SHA224ZECDSA_SHA256ZECDSA_SHA384ZECDSA_SHA512rf   ZDSA_SHA1Z
DSA_SHA224Z
DSA_SHA256Z
DSA_SHA384Z
DSA_SHA512rd   ZSHA_1rj   r   r%   objectr"   rL   r   r   ra   r!   r#   r-   r-   r-   r.   <module>   s   ($	
    6				
n    =     n