o
    Õl>j—<  ã                   @  sF  d dl m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
 d dlmZ d dlmZ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 ddl m!Z!m"Z"m#Z#m$Z$ ddl%m&Z& e 'e(¡Z)d!dd„Z*G dd„ dej+ƒZ,eG dd„ dƒƒZ-G dd„ de,ƒZ.G dd„ de.ƒZ/G dd „ d ƒZ0dS )"é    )ÚannotationsN)Ú	dataclass)ÚIntEnumÚIntFlagÚunique)ÚEvent)ÚAnyÚCallableÚClassVarÚMapping)Údefault_backend)Úhashes)Úec)ÚCipherÚ
algorithmsÚmodes)ÚHKDFé   )ÚCoseKey)Ú	bytes2intÚhmac_sha256Ú	int2bytesÚsha256é   )ÚCtap2ÚpinÚstrÚreturnÚbytesc                 C  sn   t | tƒstdt› ƒ‚t| ƒdk rtdƒ‚|  ¡  dd¡}|dt|ƒd  d  7 }t|ƒdkr5tdƒ‚|S )	NzPIN of wrong type, expecting é   zPIN must be >= 4 charactersé@   ó    é   éÿ   zPIN must be <= 255 bytes)Ú
isinstancer   Ú
ValueErrorÚlenÚencodeÚljust)r   Ú
pin_padded© r*   úD/home/thesage/.local/lib/python3.10/site-packages/fido2/ctap2/pin.pyÚ_pad_pin3   s   
r,   c                   @  sf   e Zd ZU ded< ejddd„ƒZejddd„ƒZejddd„ƒZejddd„ƒZ	ejddd„ƒZ
dS )ÚPinProtocolzClassVar[int]ÚVERSIONÚpeer_cose_keyr   r   útuple[Mapping[int, Any], bytes]c                 C  ó   dS )zuGenerates an encapsulation of the public key.
        Returns the message to transmit and the shared secret.
        Nr*   )Úselfr/   r*   r*   r+   ÚencapsulateB   ó    zPinProtocol.encapsulateÚkeyr   Ú	plaintextc                 C  r1   )zEncrypts dataNr*   )r2   r5   r6   r*   r*   r+   ÚencryptH   r4   zPinProtocol.encryptÚ
ciphertextc                 C  r1   )zDecrypts encrypted dataNr*   )r2   r5   r8   r*   r*   r+   ÚdecryptL   r4   zPinProtocol.decryptÚmessagec                 C  r1   )z$Computes a MAC of the given message.Nr*   ©r2   r5   r:   r*   r*   r+   ÚauthenticateP   r4   zPinProtocol.authenticateÚtokenc                 C  r1   )znValidates that a token is well-formed.
        Returns the token, or if invalid, raises a ValueError.
        Nr*   ©r2   r=   r*   r*   r+   Úvalidate_tokenT   r4   zPinProtocol.validate_tokenN)r/   r   r   r0   )r5   r   r6   r   r   r   )r5   r   r8   r   r   r   )r5   r   r:   r   r   r   )r=   r   r   r   )Ú__name__Ú
__module__Ú__qualname__Ú__annotations__ÚabcÚabstractmethodr3   r7   r9   r<   r?   r*   r*   r*   r+   r-   ?   s   
 r-   c                   @  s   e Zd ZU ded< ded< dS )Ú_PinUvr-   Úprotocolr   r=   N)r@   rA   rB   rC   r*   r*   r*   r+   rF   [   s   
 rF   c                   @  sR   e Zd ZdZdZdZddd„Zd	d
„ Zdd„ Zdd„ Z	dd„ Z
dd„ Zdd„ ZdS )ÚPinProtocolV1zèImplementation of the CTAP2 PIN/UV protocol v1.

    :param ctap: An instance of a CTAP2 object.
    :cvar VERSION: The version number of the PIV/UV protocol.
    :cvar IV: An all-zero IV used for some cryptographic operations.
    r   s                   Úzr   r   c                 C  s   t |ƒS ©N)r   )r2   rI   r*   r*   r+   Úkdfl   s   zPinProtocolV1.kdfc           
      C  s   t ƒ }t t ¡ |¡}| ¡  ¡ }dddt|jdƒt|jdƒdœ}t	|d ƒ}t	|d ƒ}t 
||t ¡ ¡ |¡}|  | t ¡ |¡¡}	||	fS )Nr   içÿÿÿr   é    )r   é   éÿÿÿÿéþÿÿÿéýÿÿÿrO   rP   )r   r   Úgenerate_private_keyÚ	SECP256R1Ú
public_keyÚpublic_numbersr   ÚxÚyr   ÚEllipticCurvePublicNumbersrK   ÚexchangeÚECDH)
r2   r/   ÚbeÚskÚpnÚkey_agreementrU   rV   ÚpkÚshared_secretr*   r*   r+   r3   o   s   

ûzPinProtocolV1.encapsulatec                 C  s    t ƒ }tt |¡t tj¡|ƒS rJ   )r   r   r   ÚAESr   ÚCBCrH   ÚIV)r2   ÚsecretrZ   r*   r*   r+   Ú_get_cipher_v1   s   zPinProtocolV1._get_cipher_v1c                 C  ó$   |   |¡}| ¡ }| |¡| ¡  S rJ   )rd   Ú	encryptorÚupdateÚfinalize)r2   r5   r6   ÚcipherÚencr*   r*   r+   r7   …   ó   
zPinProtocolV1.encryptc                 C  re   rJ   )rd   Ú	decryptorrg   rh   )r2   r5   r8   ri   Údecr*   r*   r+   r9   Š   rk   zPinProtocolV1.decryptc                 C  s   t ||ƒd d… S )Nr"   ©r   r;   r*   r*   r+   r<      s   zPinProtocolV1.authenticatec                 C  s   t |ƒdvr
tdƒ‚|S )N)r"   rL   z#PIN/UV token must be 16 or 32 bytes©r&   r%   r>   r*   r*   r+   r?   ’   ó   zPinProtocolV1.validate_tokenN)rI   r   r   r   )r@   rA   rB   Ú__doc__r.   rb   rK   r3   rd   r7   r9   r<   r?   r*   r*   r*   r+   rH   a   s    
rH   c                   @  sP   e Zd ZdZdZdZdZdZdd„ Zdd	„ Z	d
d„ Z
dd„ Zdd„ Zdd„ ZdS )ÚPinProtocolV2zèImplementation of the CTAP2 PIN/UV protocol v2.

    :param ctap: An instance of a CTAP2 object.
    :cvar VERSION: The version number of the PIV/UV protocol.
    :cvar IV: An all-zero IV used for some cryptographic operations.
    r   s                                    s   CTAP2 HMAC keys   CTAP2 AES keyc                 C  sN   t ƒ }tt ¡ dtjtj|d |¡}tt ¡ dtjtj|d |¡}|| S )NrL   )Ú	algorithmÚlengthÚsaltÚinfoÚbackend)	r   r   r   ÚSHA256rr   Ú	HKDF_SALTÚHKDF_INFO_HMACÚderiveÚHKDF_INFO_AES)r2   rI   rZ   Úhmac_keyÚaes_keyr*   r*   r+   rK   ¥   s(   ûúûúzPinProtocolV2.kdfc                 C  s   t ƒ }tt |¡t |¡|ƒS rJ   )r   r   r   r`   r   ra   )r2   rc   ÚivrZ   r*   r*   r+   Ú_get_cipher_v2·   s   zPinProtocolV2._get_cipher_v2c                 C  s@   |dd … }t  d¡}|  ||¡}| ¡ }|| |¡ | ¡  S ©NrL   r"   )ÚosÚurandomr€   rf   rg   rh   )r2   r5   r6   r~   r   ri   rj   r*   r*   r+   r7   »   s
   
zPinProtocolV2.encryptc                 C  sL   |dd … }|d d… |dd … }}|   ||¡}| ¡ }| |¡| ¡  S r   )r€   rl   rg   rh   )r2   r5   r8   r~   r   ri   rm   r*   r*   r+   r9   Ã   s
   zPinProtocolV2.decryptc                 C  s   |d d… }t ||ƒS )NrL   rn   )r2   r5   r:   r}   r*   r*   r+   r<   Ê   s   
zPinProtocolV2.authenticatec                 C  s   t |ƒdkr
tdƒ‚|S )NrL   zPIN/UV token must be 32 bytesro   r>   r*   r*   r+   r?   Î   rp   zPinProtocolV2.validate_tokenN)r@   rA   rB   rq   r.   ry   rz   r|   rK   r€   r7   r9   r<   r?   r*   r*   r*   r+   rr   ˜   s    rr   c                   @  sÌ   e Zd ZdZeegZeG dd„ deƒƒZ	eG dd„ deƒƒZ
eG dd„ deƒƒZedd	„ ƒZed
d„ ƒZd2d3dd„Zdd„ Z		d4d5dd„Z				d6d7d#d$„Zd8d&d'„Zd9d)d*„Zd:d,d-„Zd;d0d1„ZdS )<Ú	ClientPina!  Implementation of the CTAP2 Client PIN API.

    :param ctap: An instance of a CTAP2 object.
    :param protocol: An optional instance of a PinUvAuthProtocol object. If None is
        provided then the latest protocol supported by both library and Authenticator
        will be used.
    c                   @  s,   e Zd ZdZdZdZdZdZdZdZ	dZ
d	S )
zClientPin.CMDr   r   rM   r   é   é   é   é	   N)r@   rA   rB   ÚGET_PIN_RETRIESÚGET_KEY_AGREEMENTÚSET_PINÚ
CHANGE_PINÚGET_TOKEN_USING_PIN_LEGACYÚGET_TOKEN_USING_UVÚGET_UV_RETRIESÚGET_TOKEN_USING_PINr*   r*   r*   r+   ÚCMDß   s    r‘   c                   @  s    e Zd ZdZdZdZdZdZdS )zClientPin.RESULTr   r   rM   r   r…   N)r@   rA   rB   ÚKEY_AGREEMENTÚPIN_UV_TOKENÚPIN_RETRIESÚPOWER_CYCLE_STATEÚ
UV_RETRIESr*   r*   r*   r+   ÚRESULTê   s    r—   c                   @  s(   e Zd ZdZdZdZdZdZdZdZ	dS )	zClientPin.PERMISSIONr   r   r   é   r"   rL   r    N)
r@   rA   rB   ÚMAKE_CREDENTIALÚGET_ASSERTIONÚCREDENTIAL_MGMTÚ
BIO_ENROLLÚLARGE_BLOB_WRITEÚAUTHENTICATOR_CFGÚPERSISTENT_CREDENTIAL_MGMTr*   r*   r*   r+   Ú
PERMISSIONò   s    r    c                 C  s
   d| j v S )zÌChecks if ClientPin functionality is supported.

        Note that the ClientPin function is still usable without support for client
        PIN functionality, as UV token may still be supported.
        Ú	clientPin)Úoptions©rv   r*   r*   r+   Úis_supportedü   s   
zClientPin.is_supportedc                 C  s   | j  d¡du S )z&Checks if pinUvAuthToken is supported.ÚpinUvAuthTokenT)r¢   Úgetr£   r*   r*   r+   Úis_token_supported  s   zClientPin.is_token_supportedNÚctapr   rG   úPinProtocol | Nonec                 C  sH   || _ |d u rtjD ]}|j|jjv r|ƒ | _ d S q
tdƒ‚|| _d S )Nz)No compatible PIN/UV protocols supported!)r¨   r„   Ú	PROTOCOLSr.   rv   Úpin_uv_protocolsrG   r%   )r2   r¨   rG   Úprotor*   r*   r+   Ú__init__
  s   
þ
zClientPin.__init__c                 C  s.   | j  | jjtjj¡}|tjj }| j 	|¡S rJ   )
r¨   Ú
client_pinrG   r.   r„   r‘   rŠ   r—   r’   r3   )r2   Úrespr^   r*   r*   r+   Ú_get_shared_secret  s
   ÿzClientPin._get_shared_secretr   r   ÚpermissionsúClientPin.PERMISSION | NoneÚpermissions_rpidú
str | Noner   r   c                 C  sÂ   t  | jj¡stdƒ‚|  ¡ \}}t| ¡ ƒdd… }| j 	||¡}t  
| jj¡r2|dur2t jj}nt jj}d}d}| jj| jj|||||d}	|	t jj }
t d|› ¡ | j | j ||
¡¡S )a-  Get a PIN/UV token from the authenticator using PIN.

        :param pin: The PIN of the authenticator.
        :param permissions: The permissions to associate with the token.
        :param permissions_rpid: The permissions RPID to associate with the token.
        :return: A PIN/UV token.
        z,Authenticator does not support get_pin_tokenNr"   )r]   Úpin_hash_encr±   r³   zGot PIN token for permissions: )r„   r¤   r¨   rv   r%   r°   r   r'   rG   r7   r§   r‘   r   r   r®   r.   r—   r“   ÚloggerÚdebugr?   r9   )r2   r   r±   r³   r]   r_   Úpin_hashrµ   Úcmdr¯   Úpin_token_encr*   r*   r+   Úget_pin_token  s.   
úÿzClientPin.get_pin_tokenÚeventúEvent | NoneÚon_keepaliveúCallable[[int], None] | Nonec           	   	   C  sv   t  | jj¡stdƒ‚|  ¡ \}}| jj| jjt j	j
|||||d}|t jj }t d|› ¡ | j | j ||¡¡S )aH  Get a PIN/UV token from the authenticator using built-in UV.

        :param permissions: The permissions to associate with the token.
        :param permissions_rpid: The permissions RPID to associate with the token.
        :param event: An optional threading.Event which can be used to cancel
            the invocation.
        :param on_keepalive: An optional callback to handle keep-alive messages
            from the authenticator. The function is only called once for
            consecutive keep-alive messages with the same status.
        :return: A PIN/UV token.
        z+Authenticator does not support get_uv_token)r]   r±   r³   r¼   r¾   zGot UV token for permissions: )r„   r§   r¨   rv   r%   r°   r®   rG   r.   r‘   rŽ   r—   r“   r¶   r·   r?   r9   )	r2   r±   r³   r¼   r¾   r]   r_   r¯   rº   r*   r*   r+   Úget_uv_tokenI  s"   ù
ÿzClientPin.get_uv_tokenútuple[int, int | None]c                 C  s0   | j  | jjtjj¡}|tjj | 	tjj
¡fS )zÇGet the number of PIN retries remaining.

        :return: A tuple of the number of PIN attempts remaining until the
        authenticator is locked, and the power cycle state, if available.
        )r¨   r®   rG   r.   r„   r‘   r‰   r—   r”   r¦   r•   ©r2   r¯   r*   r*   r+   Úget_pin_retriesp  s   ÿ
þzClientPin.get_pin_retriesÚintc                 C  s"   | j  | jjtjj¡}|tjj S )zÅGet the number of UV retries remaining.

        :return: A tuple of the number of UV attempts remaining until the
        authenticator is locked, and the power cycle state, if available.
        )	r¨   r®   rG   r.   r„   r‘   r   r—   r–   rÂ   r*   r*   r+   Úget_uv_retries~  s   zClientPin.get_uv_retriesÚNonec                 C  sn   t  | jj¡stdƒ‚|  ¡ \}}| j |t|ƒ¡}| j 	||¡}| jj
| jjt jj|||d t d¡ dS )z­Set the PIN of the autenticator.

        This only works when no PIN is set. To change the PIN when set, use
        change_pin.

        :param pin: A PIN to set.
        ú(Authenticator does not support ClientPin)r]   Únew_pin_encÚpin_uv_paramzPIN has been setN)r„   r¤   r¨   rv   r%   r°   rG   r7   r,   r<   r®   r.   r‘   r‹   r¶   )r2   r   r]   r_   Úpin_encrÉ   r*   r*   r+   Úset_pin‡  s   ûzClientPin.set_pinÚold_pinÚnew_pinc           	      C  s–   t  | jj¡stdƒ‚|  ¡ \}}t| ¡ ƒdd… }| j 	||¡}| j 	|t
|ƒ¡}| j ||| ¡}| jj| jjt jj||||d t d¡ dS )zäChange the PIN of the authenticator.

        This only works when a PIN is already set. If no PIN is set, use
        set_pin.

        :param old_pin: The currently set PIN.
        :param new_pin: The new PIN to set.
        rÇ   Nr"   )r]   rµ   rÈ   rÉ   zPIN has been changed)r„   r¤   r¨   rv   r%   r°   r   r'   rG   r7   r,   r<   r®   r.   r‘   rŒ   r¶   )	r2   rÌ   rÍ   r]   r_   r¸   rµ   rÈ   rÉ   r*   r*   r+   Ú
change_pinŸ  s$   	ÿúzClientPin.change_pinrJ   )r¨   r   rG   r©   )NN)r   r   r±   r²   r³   r´   r   r   )NNNN)
r±   r²   r³   r´   r¼   r½   r¾   r¿   r   r   )r   rÁ   )r   rÄ   )r   r   r   rÆ   )rÌ   r   rÍ   r   r   rÆ   )r@   rA   rB   rq   rr   rH   rª   r   r   r‘   r—   r   r    Ústaticmethodr¤   r§   r­   r°   r»   rÀ   rÃ   rÅ   rË   rÎ   r*   r*   r*   r+   r„   Ô   s6    
	

ü-û
'

	r„   )r   r   r   r   )1Ú
__future__r   rD   Úloggingr‚   Údataclassesr   Úenumr   r   r   Ú	threadingr   Útypingr   r	   r
   r   Úcryptography.hazmat.backendsr   Úcryptography.hazmat.primitivesr   Ú)cryptography.hazmat.primitives.asymmetricr   Ú&cryptography.hazmat.primitives.ciphersr   r   r   Ú'cryptography.hazmat.primitives.kdf.hkdfr   Úcoser   Úutilsr   r   r   r   Úbaser   Ú	getLoggerr@   r¶   r,   ÚABCr-   rF   rH   rr   r„   r*   r*   r*   r+   Ú<module>   s0   

7<