]>
 
 
cvs.zerfleddert.de Git - proxmark3-svn/blob - client/cmdhffido.c 
 
 
 
 
 
 
 
357e265c7e79bee7680f90da86745088b575246a
   1  //-----------------------------------------------------------------------------  
   2  // Copyright (C) 2018 Merlok  
   4  // This code is licensed to you under the terms of the GNU GPL, version 2 or,  
   5  // at your option, any later version. See the LICENSE.txt file for the text of  
   7  //-----------------------------------------------------------------------------  
   8  // High frequency MIFARE  Plus commands  
   9  //-----------------------------------------------------------------------------  
  11  //  Documentation here:  
  13  // FIDO Alliance specifications  
  14  // https://fidoalliance.org/download/  
  15  // FIDO NFC Protocol Specification v1.0  
  16  // https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-nfc-protocol-v1.2-ps-20170411.html  
  17  // FIDO U2F Raw Message Formats  
  18  // https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html  
  19  //-----------------------------------------------------------------------------  
  22  #include  "cmdhffido.h"  
  35  #include  "proxmark3.h"  
  38  #include  "emv/emvcore.h"  
  39  #include  "emv/emvjson.h"  
  41  #include  "cliparser/cliparser.h"  
  42  #include  "crypto/asn1utils.h"  
  43  #include  "crypto/libpcrypto.h"  
  44  #include  "fido/additional_ca.h"  
  45  #include  "mbedtls/x509_crt.h"  
  46  #include  "mbedtls/x509.h"  
  47  #include  "mbedtls/pk.h"  
  49  static int  CmdHelp ( const char  * Cmd
);  
  51  int  FIDOSelect ( bool  ActivateField
,  bool  LeaveFieldON
,  uint8_t  * Result
,  size_t  MaxResultLen
,  size_t  * ResultLen
,  uint16_t  * sw
) {  
  52          uint8_t  data
[] = { 0xA0 ,  0x00 ,  0x00 ,  0x06 ,  0x47 ,  0x2F ,  0x00 ,  0x01 };  
  54          return  EMVSelect ( ActivateField
,  LeaveFieldON
,  data
,  sizeof ( data
),  Result
,  MaxResultLen
,  ResultLen
,  sw
,  NULL
);  
  57  int  FIDOExchange ( sAPDU apdu
,  uint8_t  * Result
,  size_t  MaxResultLen
,  size_t  * ResultLen
,  uint16_t  * sw
) {  
  58          int  res 
=  EMVExchange ( true ,  apdu
,  Result
,  MaxResultLen
,  ResultLen
,  sw
,  NULL
);  
  59          if  ( res 
==  5 )  // apdu result (sw) not a 0x9000  
  62          while  (! res 
&& (* sw 
>>  8 ) ==  0x61 ) {  
  63                  size_t  oldlen 
= * ResultLen
;  
  64                  res 
=  EMVExchange ( true , ( sAPDU
){ 0x00 ,  0xC0 ,  0x00 ,  0x00 ,  0x00 ,  NULL
}, & Result
[ oldlen
],  MaxResultLen 
-  oldlen
,  ResultLen
,  sw
,  NULL
);  
  65                  if  ( res 
==  5 )  // apdu result (sw) not a 0x9000  
  69                  if  (* ResultLen 
>  MaxResultLen
)   
  75  int  FIDORegister ( uint8_t  * params
,  uint8_t  * Result
,  size_t  MaxResultLen
,  size_t  * ResultLen
,  uint16_t  * sw
) {  
  76          return  FIDOExchange (( sAPDU
){ 0x00 ,  0x01 ,  0x03 ,  0x00 ,  64 ,  params
},  Result
,  MaxResultLen
,  ResultLen
,  sw
);  
  79  int  FIDOAuthentication ( uint8_t  * params
,  uint8_t  paramslen
,  uint8_t  controlb
,  uint8_t  * Result
,  size_t  MaxResultLen
,  size_t  * ResultLen
,  uint16_t  * sw
) {  
  80          return  FIDOExchange (( sAPDU
){ 0x00 ,  0x02 ,  controlb
,  0x00 ,  paramslen
,  params
},  Result
,  MaxResultLen
,  ResultLen
,  sw
);  
  83  int  FIDO2GetInfo ( uint8_t  * Result
,  size_t  MaxResultLen
,  size_t  * ResultLen
,  uint16_t  * sw
) {  
  84          uint8_t  data
[] = { 0x04 };  
  85          return  FIDOExchange (( sAPDU
){ 0x80 ,  0x10 ,  0x00 ,  0x00 ,  sizeof ( data
),  data
},  Result
,  MaxResultLen
,  ResultLen
,  sw
);  
  88  int  CmdHFFidoInfo ( const char  * cmd
) {  
  90          if  ( cmd 
&&  strlen ( cmd
) >  0 )  
  91                  PrintAndLog ( "WARNING: command don't have any parameters. \n " );  
  93          // info about 14a part  
  97          PrintAndLog ( "--------------------------------------------" );   
  98          SetAPDULogging ( false );  
 100          uint8_t  buf
[ APDU_RES_LEN
] = { 0 };  
 103          int  res 
=  FIDOSelect ( true ,  true ,  buf
,  sizeof ( buf
), & len
, & sw
);  
 112                          PrintAndLog ( "Not a FIDO card! APDU response:  %0 4x -  %s " ,  sw
,  GetAPDUCodeDescription ( sw 
>>  8 ,  sw 
&  0xff ));   
 114                          PrintAndLog ( "APDU exchange error. Card returns 0x0000." );   
 120          if  (! strncmp (( char  *) buf
,  "U2F_V2" ,  7 )) {  
 121                  if  (! strncmp (( char  *) buf
,  "FIDO_2_0" ,  8 )) {  
 122                          PrintAndLog ( "FIDO2 authenricator detected. Version: %.*s" ,  len
,  buf
);   
 124                          PrintAndLog ( "FIDO authenricator detected (not standard U2F)." );   
 125                          PrintAndLog ( "Non U2F authenticator version:" );   
 126                          dump_buffer (( const unsigned char  *) buf
,  len
,  NULL
,  0 );  
 129                  PrintAndLog ( "FIDO U2F authenricator detected. Version: %.*s" ,  len
,  buf
);   
 132          res 
=  FIDO2GetInfo ( buf
,  sizeof ( buf
), & len
, & sw
);  
 138                  PrintAndLog ( "FIDO2 version not exists ( %0 4x -  %s )." ,  sw
,  GetAPDUCodeDescription ( sw 
>>  8 ,  sw 
&  0xff ));   
 143          PrintAndLog ( "FIDO2 version: ( %d )" ,  len
);   
 144          dump_buffer (( const unsigned char  *) buf
,  len
,  NULL
,  0 );  
 149  json_t 
* OpenJson ( int  paramnum
,  char  * fname
,  void *  argtable
[],  bool  * err
) {        
 154          uint8_t  jsonname
[ 250 ] ={ 0 };  
 155          char  * cjsonname 
= ( char  *) jsonname
;  
 158          // CLIGetStrWithReturn(paramnum, jsonname, &jsonnamelen);  
 159          if  ( CLIParamStrToBuf ( arg_get_str ( paramnum
),  jsonname
,  sizeof ( jsonname
), & jsonnamelen
))  {  
 164          // current path + file name  
 165          if  (! strstr ( cjsonname
,  ".json" ))  
 166                  strcat ( cjsonname
,  ".json" );  
 169                  strcpy ( fname
,  get_my_executable_directory ());  
 170                  strcat ( fname
,  cjsonname
);  
 171                  if  ( access ( fname
,  F_OK
) != - 1 ) {  
 172                          root 
=  json_load_file ( fname
,  0 , & error
);  
 174                                  PrintAndLog ( "ERROR: json error on line  %d :  %s " ,  error
. line
,  error
. text
);  
 179                          if  (! json_is_object ( root
)) {  
 180                                  PrintAndLog ( "ERROR: Invalid json format. root must be an object." );  
 187                          root 
=  json_object ();  
 193  int  CmdHFFidoRegister ( const char  * cmd
) {  
 194          uint8_t  data
[ 64 ] = { 0 };  
 196          uint8_t  cdata
[ 250 ] = { 0 };  
 198          uint8_t  adata
[ 250 ] = { 0 };  
 201          CLIParserInit ( "hf fido reg" ,   
 202                  "Initiate a U2F token registration. Needs two 32-byte hash number.  \n challenge parameter (32b) and application parameter (32b)." ,   
 203                  "Usage: \n\t hf fido reg -> execute command with 2 parameters, filled 0x00 \n "  
 204                          " \t hf fido reg 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with parameters"  
 205                          " \t hf fido reg -p s0 s1 -> execute command with plain parameters" );  
 209                  arg_lit0 ( "aA" ,   "apdu" ,      "show APDU reqests and responses" ),  
 210                  arg_litn ( "vV" ,   "verbose" ,   0 ,  2 ,  "show technical data. vv - show full certificates data" ),  
 211                  arg_lit0 ( "pP" ,   "plain" ,     "send plain ASCII to challenge and application parameters instead of HEX" ),  
 212                  arg_lit0 ( "tT" ,   "tlv" ,       "Show DER certificate contents in TLV representation" ),  
 213                  arg_str0 ( "jJ" ,   "json" ,          "fido.json" ,  "JSON input / output file name for parameters." ),  
 214                  arg_str0 ( NULL
,   NULL
,        "<HEX/ASCII challenge parameter (32b HEX/1..16 chars)>" ,  NULL
),  
 215                  arg_str0 ( NULL
,   NULL
,        "<HEX/ASCII application parameter (32b HEX/1..16 chars)>" ,  NULL
),  
 218          CLIExecWithReturn ( cmd
,  argtable
,  true );  
 220          bool  APDULogging 
=  arg_get_lit ( 1 );  
 221          bool  verbose 
=  arg_get_lit ( 2 );  
 222          bool  verbose2 
=  arg_get_lit ( 2 ) >  1 ;  
 223          bool  paramsPlain 
=  arg_get_lit ( 3 );  
 224          bool  showDERTLV 
=  arg_get_lit ( 4 );  
 226          char  fname
[ 250 ] = { 0 };  
 228          root 
=  OpenJson ( 5 ,  fname
,  argtable
, & err
);  
 233                  JsonLoadBufAsHex ( root
,  "$.ChallengeParam" ,  data
,  32 , & jlen
);  
 234                  JsonLoadBufAsHex ( root
,  "$.ApplicationParam" , & data
[ 32 ],  32 , & jlen
);  
 238                  memset ( cdata
,  0x00 ,  32 );  
 239                  CLIGetStrWithReturn ( 6 ,  cdata
, & chlen
);  
 240                  if  ( chlen 
&&  chlen 
>  16 ) {  
 241                          PrintAndLog ( "ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of:  %d " ,  chlen
);  
 245                  CLIGetHexWithReturn ( 6 ,  cdata
, & chlen
);  
 246                  if  ( chlen 
&&  chlen 
!=  32 ) {  
 247                          PrintAndLog ( "ERROR: challenge parameter length must be 32 bytes only." );  
 252                  memmove ( data
,  cdata
,  32 );  
 256                  memset ( adata
,  0x00 ,  32 );  
 257                  CLIGetStrWithReturn ( 7 ,  adata
, & applen
);  
 258                  if  ( applen 
&&  applen 
>  16 ) {  
 259                          PrintAndLog ( "ERROR: application parameter length in ASCII mode must be less than 16 chars instead of:  %d " ,  applen
);  
 263                  CLIGetHexWithReturn ( 7 ,  adata
, & applen
);  
 264                  if  ( applen 
&&  applen 
!=  32 ) {  
 265                          PrintAndLog ( "ERROR: application parameter length must be 32 bytes only." );  
 270                  memmove (& data
[ 32 ],  adata
,  32 );  
 274          SetAPDULogging ( APDULogging
);  
 276          // challenge parameter [32 bytes] - The challenge parameter is the SHA-256 hash of the Client Data, a stringified JSON data structure that the FIDO Client prepares  
 277          // application parameter [32 bytes] - The application parameter is the SHA-256 hash of the UTF-8 encoding of the application identity  
 279          uint8_t  buf
[ 2048 ] = { 0 };  
 284          int  res 
=  FIDOSelect ( true ,  true ,  buf
,  sizeof ( buf
), & len
, & sw
);  
 287                  PrintAndLog ( "Can't select authenticator. res= %x . Exit..." ,  res
);  
 293                  PrintAndLog ( "Can't select FIDO application. APDU response status:  %0 4x -  %s " ,  sw
,  GetAPDUCodeDescription ( sw 
>>  8 ,  sw 
&  0xff ));   
 298          res 
=  FIDORegister ( data
,  buf
,   sizeof ( buf
), & len
, & sw
);  
 301                  PrintAndLog ( "Can't execute register command. res= %x . Exit..." ,  res
);  
 306                  PrintAndLog ( "ERROR execute register command. APDU response status:  %0 4x -  %s " ,  sw
,  GetAPDUCodeDescription ( sw 
>>  8 ,  sw 
&  0xff ));   
 312                  PrintAndLog ( "---------------------------------------------------------------" );  
 313          PrintAndLog ( "data len:  %d " ,  len
);  
 315                  PrintAndLog ( "--------------data----------------------" );  
 316                  dump_buffer (( const unsigned char  *) buf
,  len
,  NULL
,  0 );  
 317                  PrintAndLog ( "--------------data----------------------" );  
 320          if  ( buf
[ 0 ] !=  0x05 ) {  
 321                  PrintAndLog ( "ERROR: First byte must be 0x05, but it  %2 x" ,  buf
[ 0 ]);  
 324          PrintAndLog ( "User public key:  %s " ,  sprint_hex (& buf
[ 1 ],  65 ));  
 326          uint8_t  keyHandleLen 
=  buf
[ 66 ];  
 327          PrintAndLog ( "Key handle[ %d ]:  %s " ,  keyHandleLen
,  sprint_hex (& buf
[ 67 ],  keyHandleLen
));  
 329          int  derp 
=  67  +  keyHandleLen
;  
 330          int  derLen 
= ( buf
[ derp 
+  2 ] <<  8 ) +  buf
[ derp 
+  3 ] +  4 ;  
 332                  PrintAndLog ( "DER certificate[ %d ]: \n ------------------DER-------------------" ,  derLen
);  
 333                  dump_buffer_simple (( const unsigned char  *)& buf
[ derp
],  derLen
,  NULL
);  
 334                  PrintAndLog ( " \n ----------------DER---------------------" );  
 337                          PrintAndLog ( "------------------DER-------------------" );  
 338                  PrintAndLog ( "DER certificate[ %d ]:  %s ..." ,  derLen
,  sprint_hex (& buf
[ derp
],  20 ));  
 341          // check and print DER certificate  
 342          uint8_t  public_key
[ 65 ] = { 0 };  
 344          // print DER certificate in TLV view  
 346                  PrintAndLog ( "----------------DER TLV-----------------" );  
 347                  asn1_print (& buf
[ derp
],  derLen
,  "  " );  
 348                  PrintAndLog ( "----------------DER TLV-----------------" );  
 352          mbedtls_x509_crt cacert
;  
 353          mbedtls_x509_crt_init (& cacert
);  
 354          res 
=  mbedtls_x509_crt_parse (& cacert
, ( const unsigned char  *)  additional_ca_pem
,  additional_ca_pem_len
);  
 356                  PrintAndLog ( "ERROR: CA parse certificate returned -0x %x  -  %s " , - res
,  ecdsa_get_error ( res
));  
 359                  PrintAndLog ( "CA load OK.  %d  skipped" ,  res
);  
 361          // load DER certificate from authenticator's data  
 362          mbedtls_x509_crt cert
;  
 363          mbedtls_x509_crt_init (& cert
);  
 364          res 
=  mbedtls_x509_crt_parse_der (& cert
, & buf
[ derp
],  derLen
);  
 366                  PrintAndLog ( "ERROR: DER parse returned 0x %x  -  %s " , ( res
< 0 )?- res
: res
,  ecdsa_get_error ( res
));  
 369          // get certificate info  
 370          char  linfo
[ 300 ] = { 0 };  
 372                  mbedtls_x509_crt_info ( linfo
,  sizeof ( linfo
),  "  " , & cert
);  
 373                  PrintAndLog ( "DER certificate info: \n %s " ,  linfo
);  
 376          // verify certificate  
 377          uint32_t  verifyflags 
=  0 ;  
 378          res 
=  mbedtls_x509_crt_verify (& cert
, & cacert
,  NULL
,  NULL
, & verifyflags
,  NULL
,  NULL
);  
 380                  PrintAndLog ( "ERROR: DER verify returned 0x %x  -  %s " , ( res
< 0 )?- res
: res
,  ecdsa_get_error ( res
));  
 382                  PrintAndLog ( "Certificate OK." );  
 386                  memset ( linfo
,  0x00 ,  sizeof ( linfo
));  
 387                  mbedtls_x509_crt_verify_info ( linfo
,  sizeof ( linfo
),  "  " ,  verifyflags
);  
 388                  PrintAndLog ( "Verification info: \n %s " ,  linfo
);  
 392          res 
=  ecdsa_public_key_from_pk (& cert
. pk
,  public_key
,  sizeof ( public_key
));  
 394                  PrintAndLog ( "ERROR: getting public key from certificate 0x %x  -  %s " , ( res
< 0 )?- res
: res
,  ecdsa_get_error ( res
));  
 397                          PrintAndLog ( "Got a public key from certificate: \n %s " ,  sprint_hex_inrow ( public_key
,  65 ));  
 401                  PrintAndLog ( "------------------DER-------------------" );  
 403          mbedtls_x509_crt_free (& cert
);  
 404          mbedtls_x509_crt_free (& cacert
);  
 407          int  hashp 
=  1  +  65  +  1  +  keyHandleLen 
+  derLen
;  
 408          PrintAndLog ( "Hash[ %d ]:  %s " ,  len 
-  hashp
,  sprint_hex (& buf
[ hashp
],  len 
-  hashp
));  
 410          // check ANSI X9.62 format ECDSA signature (on P-256)  
 411          uint8_t  rval
[ 300 ] = { 0 };   
 412          uint8_t  sval
[ 300 ] = { 0 };   
 413          res 
=  ecdsa_asn1_get_signature (& buf
[ hashp
],  len 
-  hashp
,  rval
,  sval
);  
 416                          PrintAndLog ( "  r:  %s " ,  sprint_hex ( rval
,  32 ));  
 417                          PrintAndLog ( "  s:  %s " ,  sprint_hex ( sval
,  32 ));  
 420                  uint8_t  xbuf
[ 4096 ] = { 0 };  
 422                  res 
=  FillBuffer ( xbuf
,  sizeof ( xbuf
), & xbuflen
,  
 424                          & data
[ 32 ],  32 ,            // application parameter    
 425                          & data
[ 0 ],  32 ,             // challenge parameter  
 426                          & buf
[ 67 ],  keyHandleLen
,   // keyHandle  
 427                          & buf
[ 1 ],  65 ,              // user public key  
 429                  //PrintAndLog("--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen));  
 430                  res 
=  ecdsa_signature_verify ( public_key
,  xbuf
,  xbuflen
, & buf
[ hashp
],  len 
-  hashp
);  
 432                          if  ( res 
== - 0x4e00 ) {  
 433                                  PrintAndLog ( "Signature is NOT VALID." );  
 435                                  PrintAndLog ( "Other signature check error:  %x %s " , ( res
< 0 )?- res
: res
,  ecdsa_get_error ( res
));  
 438                          PrintAndLog ( "Signature is OK." );  
 442                  PrintAndLog ( "Invalid signature. res= %d ." ,  res
);  
 445          PrintAndLog ( " \n auth command: " );  
 446          printf ( "hf fido auth  %s%s " ,  paramsPlain
? "-p " : "" ,  sprint_hex_inrow (& buf
[ 67 ],  keyHandleLen
));  
 448                  printf ( "  %s " ,  paramsPlain
?( char  *) cdata
: sprint_hex_inrow ( cdata
,  32 ));  
 450                  printf ( "  %s " ,  paramsPlain
?( char  *) adata
: sprint_hex_inrow ( adata
,  32 ));  
 454                  JsonSaveBufAsHex ( root
,  "ChallengeParam" ,  data
,  32 );  
 455                  JsonSaveBufAsHex ( root
,  "ApplicationParam" , & data
[ 32 ],  32 );  
 456                  JsonSaveBufAsHexCompact ( root
,  "PublicKey" , & buf
[ 1 ],  65 );  
 457                  JsonSaveInt ( root
,  "KeyHandleLen" ,  keyHandleLen
);  
 458                  JsonSaveBufAsHexCompact ( root
,  "KeyHandle" , & buf
[ 67 ],  keyHandleLen
);  
 459                  JsonSaveBufAsHexCompact ( root
,  "DER" , & buf
[ 67  +  keyHandleLen
],  derLen
);  
 461                  res 
=  json_dump_file ( root
,  fname
,  JSON_INDENT ( 2 ));  
 463                          PrintAndLog ( "ERROR: can't save the file:  %s " ,  fname
);  
 466                  PrintAndLog ( "File ` %s ` saved." ,  fname
);  
 475  int  CmdHFFidoAuthenticate ( const char  * cmd
) {  
 476          uint8_t  data
[ 512 ] = { 0 };  
 477          uint8_t  hdata
[ 250 ] = { 0 };  
 478          bool  public_key_loaded 
=  false ;  
 479          uint8_t  public_key
[ 65 ] = { 0 };   
 481          uint8_t  keyHandleLen 
=  0 ;  
 484          CLIParserInit ( "hf fido auth" ,   
 485                  "Initiate a U2F token authentication. Needs key handle and two 32-byte hash number.  \n key handle(var 0..255), challenge parameter (32b) and application parameter (32b)." ,   
 486                  "Usage: \n\t hf fido auth 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with 2 parameters, filled 0x00 and key handle \n "  
 487                          " \t hf fido auth 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f "  
 488                                  "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with parameters" );  
 492                  arg_lit0 ( "aA" ,   "apdu" ,      "show APDU reqests and responses" ),  
 493                  arg_lit0 ( "vV" ,   "verbose" ,   "show technical data" ),  
 494                  arg_lit0 ( "pP" ,   "plain" ,     "send plain ASCII to challenge and application parameters instead of HEX" ),  
 495                  arg_rem ( "default mode:" ,     "dont-enforce-user-presence-and-sign" ),  
 496                  arg_lit0 ( "uU" ,   "user" ,      "mode: enforce-user-presence-and-sign" ),  
 497                  arg_lit0 ( "cC" ,   "check" ,     "mode: check-only" ),  
 498                  arg_str0 ( "jJ" ,   "json" ,          "fido.json" ,  "JSON input / output file name for parameters." ),  
 499                  arg_str0 ( "kK" ,   "key" ,           "public key to verify signature" ,  NULL
),  
 500                  arg_str0 ( NULL
,   NULL
,        "<HEX key handle (var 0..255b)>" ,  NULL
),  
 501                  arg_str0 ( NULL
,   NULL
,        "<HEX/ASCII challenge parameter (32b HEX/1..16 chars)>" ,  NULL
),  
 502                  arg_str0 ( NULL
,   NULL
,        "<HEX/ASCII application parameter (32b HEX/1..16 chars)>" ,  NULL
),  
 505          CLIExecWithReturn ( cmd
,  argtable
,  true );  
 507          bool  APDULogging 
=  arg_get_lit ( 1 );  
 508          bool  verbose 
=  arg_get_lit ( 2 );  
 509          bool  paramsPlain 
=  arg_get_lit ( 3 );  
 510          uint8_t  controlByte 
=  0x08 ;  
 516          char  fname
[ 250 ] = { 0 };  
 518          root 
=  OpenJson ( 7 ,  fname
,  argtable
, & err
);  
 523                  JsonLoadBufAsHex ( root
,  "$.ChallengeParam" ,  data
,  32 , & jlen
);  
 524                  JsonLoadBufAsHex ( root
,  "$.ApplicationParam" , & data
[ 32 ],  32 , & jlen
);  
 525                  JsonLoadBufAsHex ( root
,  "$.KeyHandle" , & data
[ 65 ],  512  -  67 , & jlen
);  
 526                  keyHandleLen 
=  jlen 
&  0xff ;  
 527                  data
[ 64 ] =  keyHandleLen
;  
 528                  JsonLoadBufAsHex ( root
,  "$.PublicKey" ,  public_key
,  65 , & jlen
);  
 529                  public_key_loaded 
= ( jlen 
>  0 );  
 533          CLIGetHexWithReturn ( 8 ,  hdata
, & hdatalen
);  
 534          if  ( hdatalen 
&&  hdatalen 
!=  65 ) {  
 535                  PrintAndLog ( "ERROR: public key length must be 65 bytes only." );  
 539                  memmove ( public_key
,  hdata
,  hdatalen
);  
 540                  public_key_loaded 
=  true ;  
 543          CLIGetHexWithReturn ( 9 ,  hdata
, & hdatalen
);  
 544          if  ( hdatalen 
>  255 ) {  
 545                  PrintAndLog ( "ERROR: application parameter length must be less than 255." );  
 549                  keyHandleLen 
=  hdatalen
;  
 550                  data
[ 64 ] =  keyHandleLen
;  
 551                  memmove (& data
[ 65 ],  hdata
,  keyHandleLen
);  
 555                  memset ( hdata
,  0x00 ,  32 );  
 556                  CLIGetStrWithReturn ( 9 ,  hdata
, & hdatalen
);  
 557                  if  ( hdatalen 
&&  hdatalen 
>  16 ) {  
 558                          PrintAndLog ( "ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of:  %d " ,  hdatalen
);  
 562                  CLIGetHexWithReturn ( 10 ,  hdata
, & hdatalen
);  
 563                  if  ( hdatalen 
&&  hdatalen 
!=  32 ) {  
 564                          PrintAndLog ( "ERROR: challenge parameter length must be 32 bytes only." );  
 569                  memmove ( data
,  hdata
,  32 );  
 572                  memset ( hdata
,  0x00 ,  32 );  
 573                  CLIGetStrWithReturn ( 11 ,  hdata
, & hdatalen
);  
 574                  if  ( hdatalen 
&&  hdatalen 
>  16 ) {  
 575                          PrintAndLog ( "ERROR: application parameter length in ASCII mode must be less than 16 chars instead of:  %d " ,  hdatalen
);  
 579                  CLIGetHexWithReturn ( 10 ,  hdata
, & hdatalen
);  
 580                  if  ( hdatalen 
&&  hdatalen 
!=  32 ) {  
 581                          PrintAndLog ( "ERROR: application parameter length must be 32 bytes only." );  
 586                  memmove (& data
[ 32 ],  hdata
,  32 );  
 590          SetAPDULogging ( APDULogging
);  
 592          // (in parameter) conrtol byte 0x07 - check only, 0x03 - user presense + cign. 0x08 - sign only  
 593          // challenge parameter [32 bytes]  
 594          // application parameter [32 bytes]  
 595          // key handle length [1b] = N  
 598          uint8_t  datalen 
=  32  +  32  +  1  +  keyHandleLen
;  
 600          uint8_t  buf
[ 2048 ] = { 0 };  
 605          int  res 
=  FIDOSelect ( true ,  true ,  buf
,  sizeof ( buf
), & len
, & sw
);  
 608                  PrintAndLog ( "Can't select authenticator. res= %x . Exit..." ,  res
);  
 614                  PrintAndLog ( "Can't select FIDO application. APDU response status:  %0 4x -  %s " ,  sw
,  GetAPDUCodeDescription ( sw 
>>  8 ,  sw 
&  0xff ));   
 619          res 
=  FIDOAuthentication ( data
,  datalen
,  controlByte
,   buf
,   sizeof ( buf
), & len
, & sw
);  
 622                  PrintAndLog ( "Can't execute authentication command. res= %x . Exit..." ,  res
);  
 627                  PrintAndLog ( "ERROR execute authentication command. APDU response status:  %0 4x -  %s " ,  sw
,  GetAPDUCodeDescription ( sw 
>>  8 ,  sw 
&  0xff ));   
 631          PrintAndLog ( "---------------------------------------------------------------" );  
 632          PrintAndLog ( "User presence:  %s " , ( buf
[ 0 ]? "verified" : "not verified" ));  
 633          uint32_t  cntr 
=  ( uint32_t ) bytes_to_num (& buf
[ 1 ],  4 );  
 634          PrintAndLog ( "Counter:  %d " ,  cntr
);  
 635          PrintAndLog ( "Hash[ %d ]:  %s " ,  len 
-  5 ,  sprint_hex (& buf
[ 5 ],  len 
-  5 ));  
 637          // check ANSI X9.62 format ECDSA signature (on P-256)  
 638          uint8_t  rval
[ 300 ] = { 0 };   
 639          uint8_t  sval
[ 300 ] = { 0 };   
 640          res 
=  ecdsa_asn1_get_signature (& buf
[ 5 ],  len 
-  5 ,  rval
,  sval
);  
 643                          PrintAndLog ( "  r:  %s " ,  sprint_hex ( rval
,  32 ));  
 644                          PrintAndLog ( "  s:  %s " ,  sprint_hex ( sval
,  32 ));  
 646                  if  ( public_key_loaded
) {  
 647                          uint8_t  xbuf
[ 4096 ] = { 0 };  
 649                          res 
=  FillBuffer ( xbuf
,  sizeof ( xbuf
), & xbuflen
,  
 650                                  & data
[ 32 ],  32 ,  // application parameter  
 651                                  & buf
[ 0 ],  1 ,     // user presence  
 652                                  & buf
[ 1 ],  4 ,     // counter  
 653                                  data
,  32 ,       // challenge parameter  
 655                          //PrintAndLog("--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen));  
 656                          res 
=  ecdsa_signature_verify ( public_key
,  xbuf
,  xbuflen
, & buf
[ 5 ],  len 
-  5 );  
 658                                  if  ( res 
== - 0x4e00 ) {  
 659                                          PrintAndLog ( "Signature is NOT VALID." );  
 661                                          PrintAndLog ( "Other signature check error:  %x %s " , ( res
< 0 )?- res
: res
,  ecdsa_get_error ( res
));  
 664                                  PrintAndLog ( "Signature is OK." );  
 667                          PrintAndLog ( "No public key provided. can't check signature." );  
 670                  PrintAndLog ( "Invalid signature. res= %d ." ,  res
);  
 674                  JsonSaveBufAsHex ( root
,  "ChallengeParam" ,  data
,  32 );  
 675                  JsonSaveBufAsHex ( root
,  "ApplicationParam" , & data
[ 32 ],  32 );  
 676                  JsonSaveInt ( root
,  "KeyHandleLen" ,  keyHandleLen
);  
 677                  JsonSaveBufAsHexCompact ( root
,  "KeyHandle" , & data
[ 65 ],  keyHandleLen
);  
 678                  JsonSaveInt ( root
,  "Counter" ,  cntr
);  
 680                  res 
=  json_dump_file ( root
,  fname
,  JSON_INDENT ( 2 ));  
 682                          PrintAndLog ( "ERROR: can't save the file:  %s " ,  fname
);  
 685                  PrintAndLog ( "File ` %s ` saved." ,  fname
);  
 693  static  command_t CommandTable
[] =  
 695    { "help" ,              CmdHelp
,                                  1 ,  "This help." },  
 696    { "info" ,              CmdHFFidoInfo
,                    0 ,  "Info about FIDO tag." },  
 697    { "reg" ,                           CmdHFFidoRegister
,            0 ,  "FIDO U2F Registration Message." },  
 698    { "auth" ,              CmdHFFidoAuthenticate
,    0 ,  "FIDO U2F Authentication Message." },  
 699    { NULL
,                NULL
,                                     0 ,  NULL
}  
 702  int  CmdHFFido ( const char  * Cmd
) {  
 703          ( void ) WaitForResponseTimeout ( CMD_ACK
, NULL
, 100 );  
 704          CmdsParse ( CommandTable
,  Cmd
);  
 708  int  CmdHelp ( const char  * Cmd
) {  
 709    CmdsHelp ( CommandTable
);