o
    S!                     @   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)baseauthenticator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
   N/tmp/google-cloud-sdk/lib/third_party/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_dataprint_callback
plugin_cmdclient_data_map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.key	challenge)	appIdHashr   r   versionsign_helper_requestT)typesignDatatimeoutSecondslocalAlways)_Base64Encode_SHA256
key_handler   
ClientDataTYP_AUTHENTICATIONGetJsonappendr)   U2F_SIGNATURE_TIMEOUT_SECONDSjsondumps)r	   r   r   r   r   encoded_challengesapp_id_hash_encodedchallenge_itemr&   key_handle_encodedraw_challenger"   challenge_hash_encodedr!   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   )
clientDatar@   applicationIdr   )r/   str)r	   r   r#   plugin_responseencoded_client_datasignature_datar1   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rd
|}|d}|r}|d| 7 }t
||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+   sign_helper_replyz6Plugin returned invalid response type (exit_status={})errorDetailz. Additional information:
codez+Plugin missing result code (exit_status={})z1Plugin failed with error {} - {} (exit_status={})responseDatazAPlugin returned output with missing responseData (exit_status={}))lenstructpackr   
subprocessPopenPIPEcommunicatewaitunpackr   r   r   r7   loadsdecode
ValueErrorr    SK_SIGNING_PLUGIN_TOUCH_REQUIREDU2FErrorTIMEOUTSK_SIGNING_PLUGIN_WRONG_DATADEVICE_INELIGIBLESK_SIGNING_PLUGIN_NO_ERRORPluginErrors)r	   cmd
input_jsoninput_lengthlength_bytes_lerequestsign_processrH   exit_statusresponse_len_leresponse_lenr    json_responseerror_stringerror_detailresult_coderesponse_datar
   r
   r   r      sl   




zCustomAuthenticator._CallPluginc                 C   s   t  }||  | S )z Helper method to perform SHA256.)hashlibsha256updater   digest)r	   stringmdr
   r
   r   r0      s   zCustomAuthenticator._SHA256c                 C   s   t | dS )zKHelper method to base64 encode, strip padding, and return str
      result.=)base64urlsafe_b64encoderX   rstrip)r	   
bytes_datar
   r
   r   r/      s   z!CustomAuthenticator._Base64EncodeN)__name__
__module____qualname____doc__r   sysstderrwriter$   r%   r   r   r   r0   r/   r
   r
   r
   r   r   %   s    /
(Br   )r}   rv   ro   r7   r   rO   rQ   r~   pyu2fr   r   pyu2f.conveniencer   r   r6   r_   rZ   r]   BaseAuthenticatorr   r
   r
   r
   r   <module>   s"   