
    ,                     f    d 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 d ZefdZ	 G d de
      Zy)	zHID Transport for U2F.

This module imports the U2F HID Transport protocol as well as methods
for discovering devices implementing this protocol.
    N)errors)hidc                 &    | d   dk(  r	| d   dk(  ryy)N
usage_pagei  usage   TF )devices    %lib/third_party/pyu2f/hidtransport.pyHidUsageSelectorr      s     LV#w4(?	    c              #      K   t        j                         D ]1  } | |      s	 t        j                  |d         }t        |       3 y # t        $ r Y @w xY ww)Npath)r   	EnumerateOpenUsbHidTransportOSError)selectorddevs      r   DiscoverLocalHIDU2FDevicesr   #   sR     ==?a{hhqy!c""	 
  s(    A%A	A	AAAAc                       e Zd ZdZdZdZdZdZdZdZ	dZ
d	Z eg d
      Z edg      Z G d de      Z G d de      ZddZd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zy)r   am  Implements the U2FHID transport protocol.

  This class implements the U2FHID transport protocol from the
  FIDO U2F specs.  This protocol manages fragmenting longer messages
  over a short hid frame (usually 64 bytes).  It exposes an APDU
  channel through the MSG command as well as a series of other commands
  for configuring and interacting with the device.
                          )   r!   r!   r!      c                   ,    e Zd ZdZd Zd Zed        Zy)UsbHidTransport.InitPacketa  Represent an initial U2FHID packet.

    Represent an initial U2FHID packet.  This packet contains
    metadata necessary to interpret the entire packet stream associated
    with a particular exchange (read or write).

    Attributes:
      packet_size: The size of the hid report (packet) used.  Usually 64.
      cid: The channel id for the connection to the device.
      size: The size of the entire message to be sent (including
          all continuation packets)
      payload: The portion of the message to put into the init packet.
          This must be smaller than packet_size - 7 (the overhead for
          an init packet).
    c                     || _         t        |      dk7  s
|dkD  s|dk\  rt        j                         t        |      | j                   dz
  kD  rt        j                         || _        || _        || _        || _        y )N   r!   i      )packet_sizelenr   InvalidPacketErrorcidcmdsizepayload)selfr(   r+   r,   r-   r.   s         r   __init__z#UsbHidTransport.InitPacket.__init__V   sr    $d	SQ#)tu}''))	W((1,	,''))dhdhdidlr   c                    t        d      }| j                  |dd | j                  |d<   t        j                  d|d| j
                         | j                  |ddt        | j                        z    t        t        t        |            S )Serializes the packet.@   r   r&   >H   r'   )	bytearrayr+   r,   struct	pack_intor-   r.   r)   listmapintr/   rets     r   ToWireFormatz'UsbHidTransport.InitPacket.ToWireFormatb   sn    bMcc!Ahxxc!ftS!TYY/%)\\c!ADLL!!"#c3-  r   c                     t        |      }t        |      | k7  rt        j                         |dd }|d   }t	        j
                  dt        |dd             d   }|dd|z    }t        j                  | ||||      S )am  Derializes the packet.

      Deserializes the packet from wire format.

      Args:
        packet_size: The size of all packets (usually 64)
        data: List of ints or bytearray containing the data from the wire.

      Returns:
        InitPacket object for specified data

      Raises:
        InvalidPacketError: if the data isn't a valid InitPacket
      r   r&   r4   r5   r'   )	r6   r)   r   r*   r7   unpackbytesr   
InitPacket)r(   databar+   r,   r-   r.   s          r   FromWireFormatz)UsbHidTransport.InitPacket.FromWireFormatk   s      T?b	RK	''))qGcqEc]]4r!Aw03d1QXg''S#tWMMr   N__name__
__module____qualname____doc__r0   r>   staticmethodrE   r	   r   r   rB   r$   E   s'     
! N Nr   rB   c                   ,    e Zd ZdZd Zd Zed        Zy)UsbHidTransport.ContPacketa  Represents a continutation U2FHID packet.

    Represents a continutation U2FHID packet.  These packets follow
    the intial packet and contains the remaining data in a particular
    message.

    Attributes:
      packet_size: The size of the hid report (packet) used.  Usually 64.
      cid: The channel id for the connection to the device.
      seq: The sequence number for this continuation packet.  The first
          continuation packet is 0 and it increases from there.
      payload:  The payload to put into this continuation packet.  This
          must be less than packet_size - 5 (the overhead of the
          continuation packet is 5).
    c                     || _         || _        || _        || _        t	        |      | j                   dz
  kD  rt        j                         |dkD  rt        j                         y )Nr5      )r(   r+   seqr.   r)   r   r*   )r/   r(   r+   rP   r.   s        r   r0   z#UsbHidTransport.ContPacket.__init__   s`    $ddhdhdl	W((1,	,''))	s'')) 
r   c                     t        | j                        }| j                  |dd | j                  |d<   | j                  |ddt        | j                        z    t        t        t        |            S )r2   r   r&   r5   )	r6   r(   r+   rP   r.   r)   r9   r:   r;   r<   s     r   r>   z'UsbHidTransport.ContPacket.ToWireFormat   s]    d&&'cc!Ahxxc!f%)\\c!ADLL!!"#c3-  r   c                     t        |      }t        |      | k7  rt        j                         |dd }|d   }|dd }t        j                  | |||      S )am  Derializes the packet.

      Deserializes the packet from wire format.

      Args:
        packet_size: The size of all packets (usually 64)
        data: List of ints or bytearray containing the data from the wire.

      Returns:
        InitPacket object for specified data

      Raises:
        InvalidPacketError: if the data isn't a valid ContPacket
      r   r&   r5   N)r6   r)   r   r*   r   
ContPacket)r(   rC   rD   r+   rP   r.   s         r   rE   z)UsbHidTransport.ContPacket.FromWireFormat   s`      T?b	RK	''))qGcqEc
 12g''S#wGGr   NrF   r	   r   r   rS   rM      s'     *! H Hr   rS   c                 *   || _         |j                         }|j                         }||k7  rt        j                  d      |dk(  rt        j                  d      || _        || _        t        j                  d      | _	        | j                          y )Nz6unsupported device with different in/out packet sizes.r   zunable to determine packet sizezpyu2f.hidtransport)
hid_deviceGetInReportDataLengthGetOutReportDataLengthr   HardwareErrorr(   read_timeout_secslogging	getLoggerloggerInternalInit)r/   rU   rY   in_sizeout_sizes        r   r0   zUsbHidTransport.__init__   s     DO..0G002H(  
BD D!|  !BCCD.D##$89DKr   c                 F    | j                  t        j                  |      }|S N)InternalExchanger   
U2FHID_MSG)r/   msgrs      r   SendMsgByteszUsbHidTransport.SendMsgBytes   s    o88#>AHr   c                 V    | j                  t        j                  t        |g            S ra   )rb   r   U2FHID_PROMPTr6   )r/   lengths     r   	SendBlinkzUsbHidTransport.SendBlink   s'      !>!>!*F8!46 6r   c                 T    | j                  t        j                  t        g             S ra   )rb   r   U2FHID_WINKr6   )r/   s    r   SendWinkzUsbHidTransport.SendWink   s      !<!<imLLr   c                 B    | j                  t        j                  |      S ra   )rb   r   U2FHID_PING)r/   rC   s     r   SendPingzUsbHidTransport.SendPing   s      !<!<dCCr   c                 d   t         j                  | _        t        t	        j
                  d            }| j                  t         j                  |      }t        |      dk  rt        j                  d      |dd |k7  rt        j                  d      t        |dd       | _        |d   | _        y)z.Initializes the device and obtains channel id.      zunexpected init reply lenr   znonce mismatch   N)r   U2FHID_BROADCAST_CIDr+   r6   osurandomrb   U2FHID_INITr)   r   HidErroru2fhid_version)r/   noncere   s      r   r]   zUsbHidTransport.InternalInit   s    33DHbjjm$Eo995AA
1v{OO7881vOO,--1R!DHB%Dr   c                    | j                   j                  dt        t        |            z          t	               }||dd t        d      D ]  }| j                  ||       | j                         \  }}|t        j                  k(  rM|t        j                  k(  rt        j                  d       dt        j                  dt        |d         z        ||k7  rt        j                  d      |c S  t        j                  d      )	z-Sends and receives a message from the device.z	payload: N   g      ?zDevice error: %dr   zCommand mismatch!zDevice Busy.  Please retry)r\   debugstrr9   r6   rangeInternalSendInternalRecvr   U2FHID_ERRORERR_CHANNEL_BUSYtimesleepr   ry   r;   )r/   r,   
payload_inr.   _ret_cmdret_payloads          r   rb   z UsbHidTransport.InternalExchange   s     	KKkCZ(8$99:kGGAJ1X
W%!..0g{	O00	0/:::
**S/
oo03{1~3FFGGc>oo122  //6
77r   c                    t        |      }| j                  dz
  }|d| }t        j                  | j                  | j                  |t        |      |      }|d|= |t        |      z  }| j                  |       d}|dkD  rp| j                  dz
  }|d| }|d|= |t        |      z  }t        j                  | j                  | j                  ||      }	| j                  |	       |dz  }|dkD  royy)z8Sends a message to the device, including fragmenting it.r'   r   r5   r   N)r)   r(   r   rB   r+   InternalSendPacketrS   )
r/   r,   r.   length_to_sendmax_payloadfirst_framefirst_packetrP   
next_framenext_packets
             r   r   zUsbHidTransport.InternalSend  s   \N""Q&K!K(K"--d.>.>#.1'lKIL+c+&&NL)
C
1
$$q(k1[)j
!K-
 J'n#..t/?/?3/9;k
k*	Qhc 1
r   c                     |j                         }| j                  j                  dt        |      z          | j                  j                  |       y )Nzsending packet: )r>   r\   r~   r   rU   Write)r/   packetwires      r   r   z"UsbHidTransport.InternalSendPacket  s>     DKK(3t945OO$r   c                     | j                   j                         }| j                  j                  dt	        |      z          |S )Nzrecv: )rU   Readr\   r~   r   )r/   frames     r   InternalReadFramez!UsbHidTransport.InternalReadFrame   s6    
 OO  "EKKhU+,Lr   c                    | j                         }t        j                  j                  | j                  |      }|j
                  }|j                  t        |j
                        z
  }d}|dkD  r| j                         }t        j                  j                  | j                  |      }| j                  |j                  k7  rY||j                  k7  rt        j                  d      |t        |j
                        z  }|j                  |j
                         |dz  }|dkD  r|d|j                   }|j                  |fS )z?Receives a message from the device, including defragmenting it.r   zPackets received out of orderr   )r   r   rB   rE   r(   r.   r-   r)   rS   r+   rP   r   rX   extendr,   )r/   
first_readr   rC   to_readrP   	next_readr   s           r   r   zUsbHidTransport.InternalRecv)  s)   '')J"--<<T=M=M=GIL D#l&:&:";;G
C
A+((*i#..==d>N>N>GIk	[__	$ 			""#BCC [(())g
kk+%%&	Qhc) A+. ,##$Dd##r   N)g      @)rG   rH   rI   rJ   ro   rc   rl   rh   rx   U2FHID_LOCKr   U2FHID_SYNCr6   ru   r   objectrB   rS   r0   rf   rj   rm   rp   r]   rb   r   r   r   r   r	   r   r   r   r   .   s     +*+-++,+"#;<v&=N6 =N~=H6 =H~"6MD 8*. 
"$r   r   )rJ   rZ   rv   r7   r   pyu2fr   r   r   r   r   r   r	   r   r   <module>r      s;   
  	     )9 ]$f ]$r   