]>
git.zerfleddert.de Git - proxmark3-svn/blob - client/cmdhffido.c
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: %04x - %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 (%04x - %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: %04x - %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: %04x - %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 %2x" , 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
!= 130 ) {
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: %04x - %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: %04x - %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
);