
    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ej$                        Zy)z4Class to offload the end to end flow of U2F signing.    N)errors)model)baseauthenticatorSK_SIGNING_PLUGIN   ii  ij  c                   l    e Zd ZdZd Zej                  j                  fdZd Z	d Z
d Zd Zd Zd	 Zy
)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                     || _         y )N)origin)selfr   s     8lib/third_party/pyu2f/convenience/customauthenticator.py__init__zCustomAuthenticator.__init__U   s	    DK    c                 v   t         j                  j                  t              }|(t	        j
                  dj                  t                    | j                  ||| j                        \  }} |d       | j                  |g|      }|d   |d   f}||   }	|	j                         }
| j                  ||
|      S )See base class.z{} 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_datas              r   Authenticatez CustomAuthenticator.AuthenticateX   s    
  9:J6 &'@ AC C &*%=%=&-"O] @Am<H #;//1JK&'9:"))+K++FKJJr   c                 L    t         j                  j                  t              duS )r   N)r   r   r   r   )r   s    r   IsAvailablezCustomAuthenticator.IsAvailablep   s    ::>>34D@@r   c                    i }g }| j                  | j                  |            }|D ]  }|d   }| j                  |j                        }	|d   }
t        j                  t        j                  j
                  |
|      j                         }| j                  | j                  |            }|j                  |||	|j                  d       |	|f}|||<    d|t        dd}|t        j                  |      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_requests                  r   r   z'CustomAuthenticator._BuildPluginRequestt   s   O,,T\\&-AB(5!c--cnn=$[1m))



-
-

 ') 
  $11
,,'
( * *1)[[	! 	 /0FG,<o()1 )6 &&7	O DJJ777r   c                 n    | j                  |      }t        |d         }t        |d         }||||d}|S )z,Builds the response to return to the caller.signatureDatar   )
clientDatarG   applicationIdr   )r5   str)r   r   r'   plugin_responseencoded_client_datasignature_datar7   r$   s           r   r   z/CustomAuthenticator._BuildAuthenticatorResponse   sM    ,,[99:N_[12J *'	H Or   c                 b   t        |      }t        j                  d|      }||j                         z   }t	        j
                  |t        j                  t        j                        }|j                  |      d   }|j                         }|dd }	t        j                  d|	      d   }
|dd }|
t        |      k7  r/t        j                  dj                  |
t        |      |            	 t        j                  |j                               }|j#                  d      d	k7  rAd
j                  |      }|j#                  d      }|r|d|z   z  }t        j                  |      |j#                  d      }|$t        j                  dj                  |            |t$        k(  r-t        j&                  t        j&                  j(                        |t*        k(  r-t        j&                  t        j&                  j,                        |t.        k7  r5t        j                  dj                  ||j#                  d      |            |j#                  d      }|$t        j0                  dj                  |            |S # t         $ r% t        j                  dj                  |            w xY w)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={})r1   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   r=   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_processrP   exit_statusresponse_len_leresponse_lenr$   json_responseerror_stringerror_detailresult_coderesponse_datas                    r   r   zCustomAuthenticator._CallPlugin   sy    z?Lkk$5O
 1 1 33G ##C*4//+5??<L %%g.q1F##%K RajO==7:LabzHs8}$
M6,H{;= =
5jj!23m  $77MTTU`al"&&}5l
5DD|,,  ##F+KL &{ 35 5 66OOFOO3344	4	4OOFOO==>>	2	2
=6+##M2    "%%n5M
M6+    K  5P &{ 35 55s   .#J   .J.c                     t        j                         }|j                  |j                                |j	                         S )z Helper method to perform SHA256.)hashlibsha256updater   digest)r   stringmds      r   r6   zCustomAuthenticator._SHA256   s,    		BIIfmmo99;r   c                 f    t        j                  |      j                         j                  d      S )zKHelper method to base64 encode, strip padding, and return str
      result.=)base64urlsafe_b64encoder`   rstrip)r   
bytes_datas     r   r5   z!CustomAuthenticator._Base64Encode   s)     %%j188:AA#FFr   N)__name__
__module____qualname____doc__r   sysstderrwriter(   r*   r   r   r   r6   r5    r   r   r	   r	   %   sE    -^ #&**"2"2K0A&8P@DGr   r	   )r   r   rx   r=   r   rW   rY   r   pyu2fr   r   pyu2f.conveniencer   r   r<   rg   rb   re   BaseAuthenticatorr	   r   r   r   <module>r      s]    ;    	   
   //  !  #)  % PG+== PGr   