o
    l>j5%                     @  s   d dl mZ d dlZd dl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mZ d	d
lmZmZmZ d	dlmZmZ d	dlmZ dZdZdZdZeeZ G dd deZ!dd Z"dS )    )annotationsN)Event)CallableIterator)System)CardConnection)CardConnectionDecorator)ListReadersException   )STATUS
CtapDevice	CtapError)
CAPABILITYCTAPHID)LOG_LEVEL_TRAFFICs     G/ )   r   )   r   a   c                   @  s   e Zd ZdZdGddZdd	 Zd
d ZedHddZedIddZ	edJddZ
edKddZdLddZ	dMdNd d!ZdOdPd%d&ZdQd(d)Z	"dOdRd/d0ZdSd1d2ZdTd3d4Z	"		dUdVd9d:Z	"		dUdWd<d=ZdXdYdAdBZedZd[dEdFZdS )\CtapPcscDevicezo
    CtapDevice implementation using pyscard (PCSC).

    This class is intended for use with NFC readers.
    
connection(CardConnection | CardConnectionDecoratornamestrc                 C  sr   || _ td| _d| _d| _|| _|   z| tj	d |  jtj	O  _W d S  t
y8   | js5tdY d S w )Nr   FT   zUnsupported device)_namer   _capabilitiesuse_ext_apduuse_nfcctap_getresponse_connconnectcallr   CBORr   
ValueError)selfr   r    r$   ?/home/thesage/.local/lib/python3.10/site-packages/fido2/pcsc.py__init__=   s   
zCtapPcscDevice.__init__c                 C  s   | j   |   d S N)r   r   _selectr#   r$   r$   r%   r   L   s   
zCtapPcscDevice.connectc                 C  s   d| j  dS )NzCtapPcscDevice())r   r)   r$   r$   r%   __repr__P   s   zCtapPcscDevice.__repr__returnintc                 C  s   t j| jv rdS dS )zCTAPHID protocol version.   r
   )r   r!   r   r)   r$   r$   r%   versionS   s   zCtapPcscDevice.versionr   c                 C  s   | j S )z%Capabilities supported by the device.)r   r)   r$   r$   r%   capabilitiesX   s   zCtapPcscDevice.capabilities
str | Nonec                 C     dS )zProduct name of device.Nr$   r)   r$   r$   r%   product_name]      zCtapPcscDevice.product_name
int | Nonec                 C  r2   )zSerial number of device.Nr$   r)   r$   r$   r%   serial_numberb   r4   zCtapPcscDevice.serial_numberbytesc                 C  s   t | j pdS )z&Get the ATR/ATS of the connected card.    )r7   r   getATRr)   r$   r$   r%   get_atrg   s   zCtapPcscDevice.get_atrNapduprotocoltuple[bytes, int, int]c                 C  sR   t td|  | jt||\}}}t|}t td| || |||fS )zExchange data with smart card.

        :param apdu: byte string. data to exchange with card
        :return: byte string. response from card
        zSEND: %szRECV: %s SW=%02X%02X)loggerlogr   hexr   transmitlistr7   )r#   r;   r<   respsw1sw2responser$   r$   r%   apdu_exchangek   s
   	
zCtapPcscDevice.apdu_exchanger8   control_codecontrol_datac                 C  sB   t td|  | j|t|}t|}t td|  |S )zSends control sequence to reader's driver.

        :param control_code: int. code to send to reader driver.
        :param control_data: byte string. data to send to driver
        :return: byte string. response
        zSend control: %szControl response: %s)r>   r?   r   r@   r   controlrB   r7   )r#   rH   rI   rF   r$   r$   r%   control_exchange{   s
   zCtapPcscDevice.control_exchangeNonec                 C  s\   dt dtt t }| |\}}}||ftkrtd|dkr,|  jtj	O  _d S d S )Ns     !BzFIDO applet selection failure.s   U2F_V2)
structpacklenAID_FIDO_chained_apdu_exchange
SW_SUCCESSr"   r   r   NMSGr#   r;   rC   rD   rE   r$   r$   r%   r(      s   zCtapPcscDevice._selectclainsp1p2datac              
   C  s:  | j rtd||||dt|}| || \}}}	|||	fS t|dkr[|d d |dd  }
}tdd|B |||t|
}| ||
 \}}}	||	ftkrU|||	fS t|dks%td||||}|rr|tdt|| 7 }| |d \}}}	|tkrd	td|	 }| |\}}}	||7 }|tks|||	fS )
Nz!BBBBBHr      z!BBBBB   z!BBBBrM       s      )r   rN   rO   rP   rG   rS   SW1_MORE_DATA)r#   rV   rW   rX   rY   rZ   headerrC   rD   rE   to_sendr;   lresr$   r$   r%   _chain_apdus   s*   


zCtapPcscDevice._chain_apdusc                 C  s   t |dkr!|d dkr!td|dd d }|dd|  }nt |dkr*d}n|d }|dd|  }|d d \}}}}| |||||S )N      r   z!H   r8   )rP   rN   unpackrb   )r#   r;   data_lenrZ   rV   rW   rX   rY   r$   r$   r%   rR      s   z%CtapPcscDevice._chained_apdu_exchangec                 C  s"   |  |\}}}|td|| S )Nz!BB)rR   rN   rO   rU   r$   r$   r%   
_call_apdu   s   zCtapPcscDevice._call_apdueventEvent | Noneon_keepaliveCallable[[STATUS], None] | Nonec           
   	   C  s   |pt  }| jr
dnd}| dd|d|\}}}d }d}z2||ftkrMt|d }	|r5||	kr5|	}||	 |dr<d}| dd|d\}}}||ftks#W n tyc   td | dddd  w ||ft	krpt
t
jj|S )N   r   r\   g?   z!Keyboard interrupt, cancelling...)r   r   rb   	SW_UPDATEr   waitKeyboardInterruptr>   debugrS   r   ERROTHER)
r#   rZ   ri   rk   rX   rC   rD   rE   last_ka	ka_statusr$   r$   r%   
_call_cbor   s0   

	
zCtapPcscDevice._call_cborcmdc                 C  s8   |t jkr| |||S |t jkr| |S ttjjr'   )r   r!   rw   MSGrh   r   rs   INVALID_COMMAND)r#   rx   rZ   ri   rk   r$   r$   r%   r       s
   


zCtapPcscDevice.callFreleaseboolc                 C  s0   | j   |rt| j dr| j   d S d S d S )Nr{   )r   
disconnecthasattrr{   )r#   r{   r$   r$   r%   close   s   
zCtapPcscDevice.close Iterator[CtapPcscDevice]c                 c  sd    t  D ]+}||jv r/z| | |jV  W q ty. } ztd| W Y d }~qd }~ww qd S )NzError %r)_list_readersr   createConnection	Exceptionr>   rr   )clsr   readerer$   r$   r%   list_devices   s   

zCtapPcscDevice.list_devices)r   r   r   r   )r,   r-   )r,   r   )r,   r1   )r,   r5   )r,   r7   r'   )r;   r7   r<   r5   r,   r=   )r8   )rH   r-   rI   r7   r,   r7   )r,   rL   )rV   r-   rW   r-   rX   r-   rY   r-   rZ   r7   r,   r=   )r;   r7   r,   r=   )r;   r7   r,   r7   )r8   NN)rZ   r7   ri   rj   rk   rl   r,   r7   )
rx   r-   rZ   r7   ri   rj   rk   rl   r,   r7   )F)r{   r|   r,   rL   )r   )r   r   r,   r   )__name__
__module____qualname____doc__r&   r   r+   propertyr/   r0   r3   r6   r:   rG   rK   r(   rb   rR   rh   rw   r    r   classmethodr   r$   r$   r$   r%   r   6   sB    


	

'r   c                  C  s`   zt  W S  ty/ }  zzddlm} d |_t  W W  Y d } ~ S  ty*   | w d } ~ ww )Nr   )PCSCContext)r   readersr	   smartcard.pcsc.PCSCContextr   instanceImportError)r   r   r$   r$   r%   r      s   
r   )#
__future__r   loggingrN   	threadingr   typingr   r   	smartcardr   smartcard.CardConnectionr   !smartcard.CardConnectionDecoratorr   smartcard.pcsc.PCSCExceptionsr	   ctapr   r   r   hidr   r   utilsr   rQ   rS   ro   r^   	getLoggerr   r>   r   r   r$   r$   r$   r%   <module>   s(   
 I