o
    _                      @   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ZddlZddlm	Z	 ddlm
Z
 ddlmZ dZdZdZdZd	ZG d
d dejZdS )z4Class to offload the end to end flow of U2F signing.    N)errors)model)baseauthenticatorZSK_SIGNING_PLUGIN   ii  ij  c                   @   sX   e Zd ZdZdd ZejjfddZdd Z	dd	 Z
d
d Zdd Zdd Zdd ZdS )CustomAuthenticatora  Offloads U2F signing to a pluggable command-line tool.

  Offloads U2F signing to a signing plugin which takes the form of a
  command-line tool. The command-line tool is configurable via the
  SK_SIGNING_PLUGIN environment variable.

  The signing plugin should implement the following interface:

  Communication occurs over stdin/stdout, and messages are both sent and
  received in the form:

  [4 bytes - payload size (little-endian)][variable bytes - json payload]

  Signing Request JSON
  {
    "type": "sign_helper_request",
    "signData": [{
        "keyHandle": <url-safe base64-encoded key handle>,
        "appIdHash": <url-safe base64-encoded SHA-256 hash of application ID>,
        "challengeHash": <url-safe base64-encoded SHA-256 hash of ClientData>,
        "version": U2F protocol version (usually "U2F_V2")
        },...],
    "timeoutSeconds": <security key touch timeout>
  }

  Signing Response JSON
  {
    "type": "sign_helper_reply",
    "code": <result code>.
    "errorDetail": <text description of error>,
    "responseData": {
      "appIdHash": <url-safe base64-encoded SHA-256 hash of application ID>,
      "challengeHash": <url-safe base64-encoded SHA-256 hash of ClientData>,
      "keyHandle": <url-safe base64-encoded key handle>,
      "version": <U2F protocol version>,
      "signatureData": <url-safe base64-encoded signature>
    }
  }

  Possible response error codes are:

    NoError            = 0
    UnknownError       = -127
    TouchRequired      = 0x6985
    WrongData          = 0x6a80
  c                 C   s
   || _ d S )N)origin)selfr    r	   Elib/python3.10/site-packages/pyu2f/convenience/customauthenticator.py__init__U   s   
zCustomAuthenticator.__init__c                 C   s|   t jt}|du rtdt| ||| j\}}|d | 	|g|}|d |d f}|| }	|	
 }
| ||
|S )See base class.Nz{} env var is not setz*Please insert and touch your security key
	keyHandlechallengeHash)osenvirongetSK_SIGNING_PLUGIN_ENV_VARr   PluginErrorformat_BuildPluginRequestr   _CallPluginencode_BuildAuthenticatorResponse)r   app_idchallenge_dataZprint_callbackZ
plugin_cmdclient_data_mapZsigning_inputresponsekey_challenge_pairclient_data_jsonclient_datar	   r	   r
   AuthenticateX   s   z CustomAuthenticator.Authenticatec                 C   s   t jtduS )r   N)r   r   r   r   )r   r	   r	   r
   IsAvailablep   s   zCustomAuthenticator.IsAvailablec                 C   s   i }g }|  | |}|D ]6}|d }|  |j}	|d }
ttjj|
| }|  | |}||||	|jd |	|f}|||< qd|t	dd}|t
|fS )z:Builds a JSON request in the form that the plugin expects.keyZ	challenge)Z	appIdHashr   r   versionZsign_helper_requestT)typeZsignDataZtimeoutSecondsZlocalAlways)_Base64Encode_SHA256
key_handler   Z
ClientDataZTYP_AUTHENTICATIONZGetJsonappendr#   U2F_SIGNATURE_TIMEOUT_SECONDSjsondumps)r   r   r   r   r   Zencoded_challengesZapp_id_hash_encodedZchallenge_itemr"   Zkey_handle_encodedZraw_challenger   Zchallenge_hash_encodedr   Zsigning_requestr	   r	   r
   r   t   s>   
z'CustomAuthenticator._BuildPluginRequestc                 C   s4   |  |}t|d }t|d }||||d}|S )z,Builds the response to return to the caller.signatureDatar   )Z
clientDatar,   ZapplicationIdr   )r%   str)r   r   r   Zplugin_responseZencoded_client_dataZsignature_datar'   r   r	   r	   r
   r      s   
z/CustomAuthenticator._BuildAuthenticatorResponsec                 C   s|  t |}td|}||  }tj|tjtjd}||d }| }|dd }	t	d|	d }
|dd }|
t |krKt
d|
t ||z	t| }W n tyc   t
d|w |dd	krst
d
||d}|du rt
d||tkrt
t
jj|tkrt
t
jj|tkrt
d||d||d}|du rt
d||S )z,Calls the plugin and validates the response.z<I)stdinstdoutr   N   zAPlugin response length {} does not match data {} (exit_status={})z/Plugin returned invalid output (exit_status={})r$   Zsign_helper_replyz6Plugin returned invalid response type (exit_status={})codez+Plugin missing result code (exit_status={})z1Plugin failed with error {} - {} (exit_status={})ZerrorDetailZresponseDatazAPlugin returned output with missing responseData (exit_status={}))lenstructpackr   
subprocessPopenPIPEZcommunicatewaitunpackr   r   r   r*   loadsdecode
ValueErrorr    SK_SIGNING_PLUGIN_TOUCH_REQUIREDZU2FErrorZTIMEOUTSK_SIGNING_PLUGIN_WRONG_DATAZDEVICE_INELIGIBLESK_SIGNING_PLUGIN_NO_ERRORZPluginErrors)r   cmdZ
input_jsonZinput_lengthZlength_bytes_leZrequestZsign_processr/   exit_statusZresponse_len_leZresponse_lenr   Zjson_responseZresult_codeZresponse_datar	   r	   r
   r      sh   

zCustomAuthenticator._CallPluginc                 C   s   t  }||  | S )z Helper method to perform SHA256.)hashlibZsha256updater   Zdigest)r   stringZmdr	   r	   r
   r&      s   zCustomAuthenticator._SHA256c                 C   s   t | dS )zKHelper method to base64 encode, strip padding, and return str
      result.=)base64Zurlsafe_b64encoder;   rstrip)r   
bytes_datar	   r	   r
   r%      s   z!CustomAuthenticator._Base64EncodeN)__name__
__module____qualname____doc__r   sysstderrwriter    r!   r   r   r   r&   r%   r	   r	   r	   r
   r   %   s    /
(@r   )rL   rF   rB   r*   r   r3   r5   rM   Zpyu2fr   r   Zpyu2f.conveniencer   r   r)   r?   r=   r>   ZBaseAuthenticatorr   r	   r	   r	   r
   <module>   s"   