]>
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"
31 #include <mbedtls/x509_crt.h>
32 #include <mbedtls/x509.h>
33 #include <mbedtls/pk.h>
38 #include "proxmark3.h"
40 #include "emv/emvcore.h"
41 #include "emv/emvjson.h"
43 #include "emv/apduinfo.h"
44 #include "cliparser/cliparser.h"
45 #include "crypto/asn1utils.h"
46 #include "crypto/libpcrypto.h"
47 #include "fido/cbortools.h"
48 #include "fido/fidocore.h"
49 #include "fido/cose.h"
51 static int CmdHelp ( const char * Cmd
);
53 int CmdHFFidoInfo ( const char * cmd
) {
55 if ( cmd
&& strlen ( cmd
) > 0 )
56 PrintAndLog ( "WARNING: command don't have any parameters. \n " );
58 // info about 14a part
62 PrintAndLog ( "--------------------------------------------" );
63 SetAPDULogging ( false );
65 uint8_t buf
[ APDU_RESPONSE_LEN
] = { 0 };
68 int res
= FIDOSelect ( true , true , buf
, sizeof ( buf
), & len
, & sw
);
77 PrintAndLog ( "Not a FIDO card! APDU response: %04x - %s" , sw
, GetAPDUCodeDescription ( sw
>> 8 , sw
& 0xff ));
79 PrintAndLog ( "APDU exchange error. Card returns 0x0000." );
85 if (! strncmp (( char *) buf
, "U2F_V2" , 7 )) {
86 if (! strncmp (( char *) buf
, "FIDO_2_0" , 8 )) {
87 PrintAndLog ( "FIDO2 authenricator detected. Version: %.*s" , len
, buf
);
89 PrintAndLog ( "FIDO authenricator detected (not standard U2F)." );
90 PrintAndLog ( "Non U2F authenticator version:" );
91 dump_buffer (( const unsigned char *) buf
, len
, NULL
, 0 );
94 PrintAndLog ( "FIDO U2F authenricator detected. Version: %.*s" , len
, buf
);
97 res
= FIDO2GetInfo ( buf
, sizeof ( buf
), & len
, & sw
);
103 PrintAndLog ( "FIDO2 version not exists (%04x - %s)." , sw
, GetAPDUCodeDescription ( sw
>> 8 , sw
& 0xff ));
109 PrintAndLog ( "FIDO2 ger version error: %d - %s" , buf
[ 0 ], fido2GetCmdErrorDescription ( buf
[ 0 ]));
115 // PrintAndLog("FIDO2 version: (len=%d)", len);
116 // dump_buffer((const unsigned char *)buf, len, NULL, 0);
119 PrintAndLog ( "FIDO2 version CBOR decoded:" );
120 TinyCborPrintFIDOPackage ( fido2CmdGetInfo
, true , & buf
[ 1 ], len
- 1 );
122 PrintAndLog ( "FIDO2 version length error" );
128 json_t
* OpenJson ( int paramnum
, char * fname
, void * argtable
[], bool * err
) {
133 uint8_t jsonname
[ 250 ] ={ 0 };
134 char * cjsonname
= ( char *) jsonname
;
137 // CLIGetStrWithReturn(paramnum, jsonname, &jsonnamelen);
138 if ( CLIParamStrToBuf ( arg_get_str ( paramnum
), jsonname
, sizeof ( jsonname
), & jsonnamelen
)) {
143 // current path + file name
144 if (! strstr ( cjsonname
, ".json" ))
145 strcat ( cjsonname
, ".json" );
148 strcpy ( fname
, get_my_executable_directory ());
149 strcat ( fname
, cjsonname
);
150 if ( access ( fname
, F_OK
) != - 1 ) {
151 root
= json_load_file ( fname
, 0 , & error
);
153 PrintAndLog ( "ERROR: json error on line %d: %s" , error
. line
, error
. text
);
158 if (! json_is_object ( root
)) {
159 PrintAndLog ( "ERROR: Invalid json format. root must be an object." );
166 root
= json_object ();
172 int CmdHFFidoRegister ( const char * cmd
) {
173 uint8_t data
[ 64 ] = { 0 };
175 uint8_t cdata
[ 250 ] = { 0 };
177 uint8_t adata
[ 250 ] = { 0 };
180 CLIParserInit ( "hf fido reg" ,
181 "Initiate a U2F token registration. Needs two 32-byte hash number. \n challenge parameter (32b) and application parameter (32b)." ,
182 "Usage: \n\t hf fido reg -> execute command with 2 parameters, filled 0x00 \n "
183 " \t hf fido reg 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with parameters"
184 " \t hf fido reg -p s0 s1 -> execute command with plain parameters" );
188 arg_lit0 ( "aA" , "apdu" , "show APDU reqests and responses" ),
189 arg_litn ( "vV" , "verbose" , 0 , 2 , "show technical data. vv - show full certificates data" ),
190 arg_lit0 ( "pP" , "plain" , "send plain ASCII to challenge and application parameters instead of HEX" ),
191 arg_lit0 ( "tT" , "tlv" , "Show DER certificate contents in TLV representation" ),
192 arg_str0 ( "jJ" , "json" , "fido.json" , "JSON input / output file name for parameters." ),
193 arg_str0 ( NULL
, NULL
, "<HEX/ASCII challenge parameter (32b HEX/1..16 chars)>" , NULL
),
194 arg_str0 ( NULL
, NULL
, "<HEX/ASCII application parameter (32b HEX/1..16 chars)>" , NULL
),
197 CLIExecWithReturn ( cmd
, argtable
, true );
199 bool APDULogging
= arg_get_lit ( 1 );
200 bool verbose
= arg_get_lit ( 2 );
201 bool verbose2
= arg_get_lit ( 2 ) > 1 ;
202 bool paramsPlain
= arg_get_lit ( 3 );
203 bool showDERTLV
= arg_get_lit ( 4 );
205 char fname
[ 250 ] = { 0 };
207 root
= OpenJson ( 5 , fname
, argtable
, & err
);
212 JsonLoadBufAsHex ( root
, "$.ChallengeParam" , data
, 32 , & jlen
);
213 JsonLoadBufAsHex ( root
, "$.ApplicationParam" , & data
[ 32 ], 32 , & jlen
);
217 memset ( cdata
, 0x00 , 32 );
218 CLIGetStrWithReturn ( 6 , cdata
, & chlen
);
219 if ( chlen
&& chlen
> 16 ) {
220 PrintAndLog ( "ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d" , chlen
);
224 CLIGetHexWithReturn ( 6 , cdata
, & chlen
);
225 if ( chlen
&& chlen
!= 32 ) {
226 PrintAndLog ( "ERROR: challenge parameter length must be 32 bytes only." );
231 memmove ( data
, cdata
, 32 );
235 memset ( adata
, 0x00 , 32 );
236 CLIGetStrWithReturn ( 7 , adata
, & applen
);
237 if ( applen
&& applen
> 16 ) {
238 PrintAndLog ( "ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d" , applen
);
242 CLIGetHexWithReturn ( 7 , adata
, & applen
);
243 if ( applen
&& applen
!= 32 ) {
244 PrintAndLog ( "ERROR: application parameter length must be 32 bytes only." );
249 memmove (& data
[ 32 ], adata
, 32 );
253 SetAPDULogging ( APDULogging
);
255 // 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
256 // application parameter [32 bytes] - The application parameter is the SHA-256 hash of the UTF-8 encoding of the application identity
258 uint8_t buf
[ 2048 ] = { 0 };
263 int res
= FIDOSelect ( true , true , buf
, sizeof ( buf
), & len
, & sw
);
266 PrintAndLog ( "Can't select authenticator. res=%x. Exit..." , res
);
272 PrintAndLog ( "Can't select FIDO application. APDU response status: %04x - %s" , sw
, GetAPDUCodeDescription ( sw
>> 8 , sw
& 0xff ));
277 res
= FIDORegister ( data
, buf
, sizeof ( buf
), & len
, & sw
);
280 PrintAndLog ( "Can't execute register command. res=%x. Exit..." , res
);
285 PrintAndLog ( "ERROR execute register command. APDU response status: %04x - %s" , sw
, GetAPDUCodeDescription ( sw
>> 8 , sw
& 0xff ));
291 PrintAndLog ( "---------------------------------------------------------------" );
292 PrintAndLog ( "data len: %d" , len
);
294 PrintAndLog ( "--------------data----------------------" );
295 dump_buffer (( const unsigned char *) buf
, len
, NULL
, 0 );
296 PrintAndLog ( "--------------data----------------------" );
299 if ( buf
[ 0 ] != 0x05 ) {
300 PrintAndLog ( "ERROR: First byte must be 0x05, but it %2x" , buf
[ 0 ]);
303 PrintAndLog ( "User public key: %s" , sprint_hex (& buf
[ 1 ], 65 ));
305 uint8_t keyHandleLen
= buf
[ 66 ];
306 PrintAndLog ( "Key handle[%d]: %s" , keyHandleLen
, sprint_hex (& buf
[ 67 ], keyHandleLen
));
308 int derp
= 67 + keyHandleLen
;
309 int derLen
= ( buf
[ derp
+ 2 ] << 8 ) + buf
[ derp
+ 3 ] + 4 ;
311 PrintAndLog ( "DER certificate[%d]: \n ------------------DER-------------------" , derLen
);
312 dump_buffer_simple (( const unsigned char *)& buf
[ derp
], derLen
, NULL
);
313 PrintAndLog ( " \n ----------------DER---------------------" );
316 PrintAndLog ( "------------------DER-------------------" );
317 PrintAndLog ( "DER certificate[%d]: %s..." , derLen
, sprint_hex (& buf
[ derp
], 20 ));
320 // check and print DER certificate
321 uint8_t public_key
[ 65 ] = { 0 };
323 // print DER certificate in TLV view
325 PrintAndLog ( "----------------DER TLV-----------------" );
326 asn1_print (& buf
[ derp
], derLen
, " " );
327 PrintAndLog ( "----------------DER TLV-----------------" );
330 FIDOCheckDERAndGetKey (& buf
[ derp
], derLen
, verbose
, public_key
, sizeof ( public_key
));
333 int hashp
= 1 + 65 + 1 + keyHandleLen
+ derLen
;
334 PrintAndLog ( "Hash[%d]: %s" , len
- hashp
, sprint_hex (& buf
[ hashp
], len
- hashp
));
336 // check ANSI X9.62 format ECDSA signature (on P-256)
337 uint8_t rval
[ 300 ] = { 0 };
338 uint8_t sval
[ 300 ] = { 0 };
339 res
= ecdsa_asn1_get_signature (& buf
[ hashp
], len
- hashp
, rval
, sval
);
342 PrintAndLog ( " r: %s" , sprint_hex ( rval
, 32 ));
343 PrintAndLog ( " s: %s" , sprint_hex ( sval
, 32 ));
346 uint8_t xbuf
[ 4096 ] = { 0 };
348 res
= FillBuffer ( xbuf
, sizeof ( xbuf
), & xbuflen
,
350 & data
[ 32 ], 32 , // application parameter
351 & data
[ 0 ], 32 , // challenge parameter
352 & buf
[ 67 ], keyHandleLen
, // keyHandle
353 & buf
[ 1 ], 65 , // user public key
355 //PrintAndLog("--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen));
356 res
= ecdsa_signature_verify ( public_key
, xbuf
, xbuflen
, & buf
[ hashp
], len
- hashp
);
358 if ( res
== - 0x4e00 ) {
359 PrintAndLog ( "Signature is NOT VALID." );
361 PrintAndLog ( "Other signature check error: %x %s" , ( res
< 0 )?- res
: res
, ecdsa_get_error ( res
));
364 PrintAndLog ( "Signature is OK." );
368 PrintAndLog ( "Invalid signature. res=%d." , res
);
371 PrintAndLog ( " \n auth command: " );
372 printf ( "hf fido auth %s%s" , paramsPlain
? "-p " : "" , sprint_hex_inrow (& buf
[ 67 ], keyHandleLen
));
374 printf ( " %s" , paramsPlain
?( char *) cdata
: sprint_hex_inrow ( cdata
, 32 ));
376 printf ( " %s" , paramsPlain
?( char *) adata
: sprint_hex_inrow ( adata
, 32 ));
380 JsonSaveBufAsHex ( root
, "ChallengeParam" , data
, 32 );
381 JsonSaveBufAsHex ( root
, "ApplicationParam" , & data
[ 32 ], 32 );
382 JsonSaveBufAsHexCompact ( root
, "PublicKey" , & buf
[ 1 ], 65 );
383 JsonSaveInt ( root
, "KeyHandleLen" , keyHandleLen
);
384 JsonSaveBufAsHexCompact ( root
, "KeyHandle" , & buf
[ 67 ], keyHandleLen
);
385 JsonSaveBufAsHexCompact ( root
, "DER" , & buf
[ 67 + keyHandleLen
], derLen
);
387 res
= json_dump_file ( root
, fname
, JSON_INDENT ( 2 ));
389 PrintAndLog ( "ERROR: can't save the file: %s" , fname
);
392 PrintAndLog ( "File `%s` saved." , fname
);
401 int CmdHFFidoAuthenticate ( const char * cmd
) {
402 uint8_t data
[ 512 ] = { 0 };
403 uint8_t hdata
[ 250 ] = { 0 };
404 bool public_key_loaded
= false ;
405 uint8_t public_key
[ 65 ] = { 0 };
407 uint8_t keyHandleLen
= 0 ;
410 CLIParserInit ( "hf fido auth" ,
411 "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)." ,
412 "Usage: \n\t hf fido auth 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with 2 parameters, filled 0x00 and key handle \n "
413 " \t hf fido auth 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f "
414 "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with parameters" );
418 arg_lit0 ( "aA" , "apdu" , "show APDU reqests and responses" ),
419 arg_lit0 ( "vV" , "verbose" , "show technical data" ),
420 arg_lit0 ( "pP" , "plain" , "send plain ASCII to challenge and application parameters instead of HEX" ),
421 arg_rem ( "default mode:" , "dont-enforce-user-presence-and-sign" ),
422 arg_lit0 ( "uU" , "user" , "mode: enforce-user-presence-and-sign" ),
423 arg_lit0 ( "cC" , "check" , "mode: check-only" ),
424 arg_str0 ( "jJ" , "json" , "fido.json" , "JSON input / output file name for parameters." ),
425 arg_str0 ( "kK" , "key" , "public key to verify signature" , NULL
),
426 arg_str0 ( NULL
, NULL
, "<HEX key handle (var 0..255b)>" , NULL
),
427 arg_str0 ( NULL
, NULL
, "<HEX/ASCII challenge parameter (32b HEX/1..16 chars)>" , NULL
),
428 arg_str0 ( NULL
, NULL
, "<HEX/ASCII application parameter (32b HEX/1..16 chars)>" , NULL
),
431 CLIExecWithReturn ( cmd
, argtable
, true );
433 bool APDULogging
= arg_get_lit ( 1 );
434 bool verbose
= arg_get_lit ( 2 );
435 bool paramsPlain
= arg_get_lit ( 3 );
436 uint8_t controlByte
= 0x08 ;
442 char fname
[ 250 ] = { 0 };
444 root
= OpenJson ( 7 , fname
, argtable
, & err
);
449 JsonLoadBufAsHex ( root
, "$.ChallengeParam" , data
, 32 , & jlen
);
450 JsonLoadBufAsHex ( root
, "$.ApplicationParam" , & data
[ 32 ], 32 , & jlen
);
451 JsonLoadBufAsHex ( root
, "$.KeyHandle" , & data
[ 65 ], 512 - 67 , & jlen
);
452 keyHandleLen
= jlen
& 0xff ;
453 data
[ 64 ] = keyHandleLen
;
454 JsonLoadBufAsHex ( root
, "$.PublicKey" , public_key
, 65 , & jlen
);
455 public_key_loaded
= ( jlen
> 0 );
459 CLIGetHexWithReturn ( 8 , hdata
, & hdatalen
);
460 if ( hdatalen
&& hdatalen
!= 65 ) {
461 PrintAndLog ( "ERROR: public key length must be 65 bytes only." );
465 memmove ( public_key
, hdata
, hdatalen
);
466 public_key_loaded
= true ;
469 CLIGetHexWithReturn ( 9 , hdata
, & hdatalen
);
470 if ( hdatalen
> 255 ) {
471 PrintAndLog ( "ERROR: application parameter length must be less than 255." );
475 keyHandleLen
= hdatalen
;
476 data
[ 64 ] = keyHandleLen
;
477 memmove (& data
[ 65 ], hdata
, keyHandleLen
);
481 memset ( hdata
, 0x00 , 32 );
482 CLIGetStrWithReturn ( 9 , hdata
, & hdatalen
);
483 if ( hdatalen
&& hdatalen
> 16 ) {
484 PrintAndLog ( "ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d" , hdatalen
);
488 CLIGetHexWithReturn ( 10 , hdata
, & hdatalen
);
489 if ( hdatalen
&& hdatalen
!= 32 ) {
490 PrintAndLog ( "ERROR: challenge parameter length must be 32 bytes only." );
495 memmove ( data
, hdata
, 32 );
498 memset ( hdata
, 0x00 , 32 );
499 CLIGetStrWithReturn ( 11 , hdata
, & hdatalen
);
500 if ( hdatalen
&& hdatalen
> 16 ) {
501 PrintAndLog ( "ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d" , hdatalen
);
505 CLIGetHexWithReturn ( 10 , hdata
, & hdatalen
);
506 if ( hdatalen
&& hdatalen
!= 32 ) {
507 PrintAndLog ( "ERROR: application parameter length must be 32 bytes only." );
512 memmove (& data
[ 32 ], hdata
, 32 );
516 SetAPDULogging ( APDULogging
);
518 // (in parameter) conrtol byte 0x07 - check only, 0x03 - user presense + cign. 0x08 - sign only
519 // challenge parameter [32 bytes]
520 // application parameter [32 bytes]
521 // key handle length [1b] = N
524 uint8_t datalen
= 32 + 32 + 1 + keyHandleLen
;
526 uint8_t buf
[ 2048 ] = { 0 };
531 int res
= FIDOSelect ( true , true , buf
, sizeof ( buf
), & len
, & sw
);
534 PrintAndLog ( "Can't select authenticator. res=%x. Exit..." , res
);
540 PrintAndLog ( "Can't select FIDO application. APDU response status: %04x - %s" , sw
, GetAPDUCodeDescription ( sw
>> 8 , sw
& 0xff ));
545 res
= FIDOAuthentication ( data
, datalen
, controlByte
, buf
, sizeof ( buf
), & len
, & sw
);
548 PrintAndLog ( "Can't execute authentication command. res=%x. Exit..." , res
);
553 PrintAndLog ( "ERROR execute authentication command. APDU response status: %04x - %s" , sw
, GetAPDUCodeDescription ( sw
>> 8 , sw
& 0xff ));
557 PrintAndLog ( "---------------------------------------------------------------" );
558 PrintAndLog ( "User presence: %s" , ( buf
[ 0 ]? "verified" : "not verified" ));
559 uint32_t cntr
= ( uint32_t ) bytes_to_num (& buf
[ 1 ], 4 );
560 PrintAndLog ( "Counter: %d" , cntr
);
561 PrintAndLog ( "Hash[%d]: %s" , len
- 5 , sprint_hex (& buf
[ 5 ], len
- 5 ));
563 // check ANSI X9.62 format ECDSA signature (on P-256)
564 uint8_t rval
[ 300 ] = { 0 };
565 uint8_t sval
[ 300 ] = { 0 };
566 res
= ecdsa_asn1_get_signature (& buf
[ 5 ], len
- 5 , rval
, sval
);
569 PrintAndLog ( " r: %s" , sprint_hex ( rval
, 32 ));
570 PrintAndLog ( " s: %s" , sprint_hex ( sval
, 32 ));
572 if ( public_key_loaded
) {
573 uint8_t xbuf
[ 4096 ] = { 0 };
575 res
= FillBuffer ( xbuf
, sizeof ( xbuf
), & xbuflen
,
576 & data
[ 32 ], 32 , // application parameter
577 & buf
[ 0 ], 1 , // user presence
578 & buf
[ 1 ], 4 , // counter
579 data
, 32 , // challenge parameter
581 //PrintAndLog("--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen));
582 res
= ecdsa_signature_verify ( public_key
, xbuf
, xbuflen
, & buf
[ 5 ], len
- 5 );
584 if ( res
== - 0x4e00 ) {
585 PrintAndLog ( "Signature is NOT VALID." );
587 PrintAndLog ( "Other signature check error: %x %s" , ( res
< 0 )?- res
: res
, ecdsa_get_error ( res
));
590 PrintAndLog ( "Signature is OK." );
593 PrintAndLog ( "No public key provided. can't check signature." );
596 PrintAndLog ( "Invalid signature. res=%d." , res
);
600 JsonSaveBufAsHex ( root
, "ChallengeParam" , data
, 32 );
601 JsonSaveBufAsHex ( root
, "ApplicationParam" , & data
[ 32 ], 32 );
602 JsonSaveInt ( root
, "KeyHandleLen" , keyHandleLen
);
603 JsonSaveBufAsHexCompact ( root
, "KeyHandle" , & data
[ 65 ], keyHandleLen
);
604 JsonSaveInt ( root
, "Counter" , cntr
);
606 res
= json_dump_file ( root
, fname
, JSON_INDENT ( 2 ));
608 PrintAndLog ( "ERROR: can't save the file: %s" , fname
);
611 PrintAndLog ( "File `%s` saved." , fname
);
619 void CheckSlash ( char * fileName
) {
620 if (( fileName
[ strlen ( fileName
) - 1 ] != '/' ) &&
621 ( fileName
[ strlen ( fileName
) - 1 ] != ' \\ ' ))
622 strcat ( fileName
, "/" );
625 int GetExistsFileNameJson ( char * prefixDir
, char * reqestedFileName
, char * fileName
) {
627 strcpy ( fileName
, get_my_executable_directory ());
628 CheckSlash ( fileName
);
630 strcat ( fileName
, prefixDir
);
631 CheckSlash ( fileName
);
633 strcat ( fileName
, reqestedFileName
);
634 if (! strstr ( fileName
, ".json" ))
635 strcat ( fileName
, ".json" );
637 if ( access ( fileName
, F_OK
) < 0 ) {
638 strcpy ( fileName
, get_my_executable_directory ());
639 CheckSlash ( fileName
);
641 strcat ( fileName
, reqestedFileName
);
642 if (! strstr ( fileName
, ".json" ))
643 strcat ( fileName
, ".json" );
645 if ( access ( fileName
, F_OK
) < 0 ) {
646 return 1 ; // file not found
652 int CmdHFFido2MakeCredential ( const char * cmd
) {
655 char fname
[ 300 ] = { 0 };
657 CLIParserInit ( "hf fido make" ,
658 "Execute a FIDO2 Make Credentional command. Needs json file with parameters. Sample file `fido2.json`. File can be placed in proxmark directory or in `proxmark/fido` directory." ,
659 "Usage: \n\t hf fido make -> execute command default parameters file `fido2.json` \n "
660 " \t hf fido make test.json -> execute command with parameters file `text.json`" );
664 arg_lit0 ( "aA" , "apdu" , "show APDU reqests and responses" ),
665 arg_litn ( "vV" , "verbose" , 0 , 2 , "show technical data. vv - show full certificates data" ),
666 arg_lit0 ( "tT" , "tlv" , "Show DER certificate contents in TLV representation" ),
667 arg_lit0 ( "cC" , "cbor" , "show CBOR decoded data" ),
668 arg_str0 ( NULL
, NULL
, "<json file name>" , "JSON input / output file name for parameters. Default `fido2.json`" ),
671 CLIExecWithReturn ( cmd
, argtable
, true );
673 bool APDULogging
= arg_get_lit ( 1 );
674 bool verbose
= arg_get_lit ( 2 );
675 bool verbose2
= arg_get_lit ( 2 ) > 1 ;
676 bool showDERTLV
= arg_get_lit ( 3 );
677 bool showCBOR
= arg_get_lit ( 4 );
679 uint8_t jsonname
[ 250 ] ={ 0 };
680 char * cjsonname
= ( char *) jsonname
;
682 CLIGetStrWithReturn ( 5 , jsonname
, & jsonnamelen
);
685 strcat ( cjsonname
, "fido2" );
686 jsonnamelen
= strlen ( cjsonname
);
691 SetAPDULogging ( APDULogging
);
693 int res
= GetExistsFileNameJson ( "fido" , cjsonname
, fname
);
695 PrintAndLog ( "ERROR: Can't found the json file." );
698 PrintAndLog ( "fname: %s \n " , fname
);
699 root
= json_load_file ( fname
, 0 , & error
);
701 PrintAndLog ( "ERROR: json error on line %d: %s" , error
. line
, error
. text
);
705 uint8_t data
[ 2048 ] = { 0 };
707 uint8_t buf
[ 2048 ] = { 0 };
712 res
= FIDOSelect ( true , true , buf
, sizeof ( buf
), & len
, & sw
);
715 PrintAndLog ( "Can't select authenticator. res=%x. Exit..." , res
);
721 PrintAndLog ( "Can't select FIDO application. APDU response status: %04x - %s" , sw
, GetAPDUCodeDescription ( sw
>> 8 , sw
& 0xff ));
726 res
= FIDO2CreateMakeCredentionalReq ( root
, data
, sizeof ( data
), & datalen
);
731 PrintAndLog ( "CBOR make credentional request:" );
732 PrintAndLog ( "---------------- CBOR ------------------" );
733 TinyCborPrintFIDOPackage ( fido2CmdMakeCredential
, false , data
, datalen
);
734 PrintAndLog ( "---------------- CBOR ------------------" );
737 res
= FIDO2MakeCredential ( data
, datalen
, buf
, sizeof ( buf
), & len
, & sw
);
740 PrintAndLog ( "Can't execute make credential command. res=%x. Exit..." , res
);
745 PrintAndLog ( "ERROR execute make credential command. APDU response status: %04x - %s" , sw
, GetAPDUCodeDescription ( sw
>> 8 , sw
& 0xff ));
750 PrintAndLog ( "FIDO2 make credential error: %d - %s" , buf
[ 0 ], fido2GetCmdErrorDescription ( buf
[ 0 ]));
754 PrintAndLog ( "MakeCredential result (%d b) OK." , len
);
756 PrintAndLog ( "CBOR make credentional response:" );
757 PrintAndLog ( "---------------- CBOR ------------------" );
758 TinyCborPrintFIDOPackage ( fido2CmdMakeCredential
, true , & buf
[ 1 ], len
- 1 );
759 PrintAndLog ( "---------------- CBOR ------------------" );
762 // parse returned cbor
763 FIDO2MakeCredentionalParseRes ( root
, & buf
[ 1 ], len
- 1 , verbose
, verbose2
, showCBOR
, showDERTLV
);
766 res
= json_dump_file ( root
, fname
, JSON_INDENT ( 2 ));
768 PrintAndLog ( "ERROR: can't save the file: %s" , fname
);
771 PrintAndLog ( "File `%s` saved." , fname
);
779 int CmdHFFido2GetAssertion ( const char * cmd
) {
782 char fname
[ 300 ] = { 0 };
784 CLIParserInit ( "hf fido assert" ,
785 "Execute a FIDO2 Get Assertion command. Needs json file with parameters. Sample file `fido2.json`. File can be placed in proxmark directory or in `proxmark/fido` directory." ,
786 "Usage: \n\t hf fido assert -> execute command default parameters file `fido2.json` \n "
787 " \t hf fido assert test.json -l -> execute command with parameters file `text.json` and add to request CredentialId" );
791 arg_lit0 ( "aA" , "apdu" , "show APDU reqests and responses" ),
792 arg_litn ( "vV" , "verbose" , 0 , 2 , "show technical data. vv - show full certificates data" ),
793 arg_lit0 ( "cC" , "cbor" , "show CBOR decoded data" ),
794 arg_lit0 ( "lL" , "list" , "add CredentialId from json to allowList. Needs if `rk` option is `false` (authenticator don't store credential to its memory)" ),
795 arg_str0 ( NULL
, NULL
, "<json file name>" , "JSON input / output file name for parameters. Default `fido2.json`" ),
798 CLIExecWithReturn ( cmd
, argtable
, true );
800 bool APDULogging
= arg_get_lit ( 1 );
801 bool verbose
= arg_get_lit ( 2 );
802 bool verbose2
= arg_get_lit ( 2 ) > 1 ;
803 bool showCBOR
= arg_get_lit ( 3 );
804 bool createAllowList
= arg_get_lit ( 4 );
806 uint8_t jsonname
[ 250 ] ={ 0 };
807 char * cjsonname
= ( char *) jsonname
;
809 CLIGetStrWithReturn ( 5 , jsonname
, & jsonnamelen
);
812 strcat ( cjsonname
, "fido2" );
813 jsonnamelen
= strlen ( cjsonname
);
818 SetAPDULogging ( APDULogging
);
820 int res
= GetExistsFileNameJson ( "fido" , "fido2" , fname
);
822 PrintAndLog ( "ERROR: Can't found the json file." );
825 PrintAndLog ( "fname: %s \n " , fname
);
826 root
= json_load_file ( fname
, 0 , & error
);
828 PrintAndLog ( "ERROR: json error on line %d: %s" , error
. line
, error
. text
);
832 uint8_t data
[ 2048 ] = { 0 };
834 uint8_t buf
[ 2048 ] = { 0 };
839 res
= FIDOSelect ( true , true , buf
, sizeof ( buf
), & len
, & sw
);
842 PrintAndLog ( "Can't select authenticator. res=%x. Exit..." , res
);
848 PrintAndLog ( "Can't select FIDO application. APDU response status: %04x - %s" , sw
, GetAPDUCodeDescription ( sw
>> 8 , sw
& 0xff ));
853 res
= FIDO2CreateGetAssertionReq ( root
, data
, sizeof ( data
), & datalen
, createAllowList
);
858 PrintAndLog ( "CBOR get assertion request:" );
859 PrintAndLog ( "---------------- CBOR ------------------" );
860 TinyCborPrintFIDOPackage ( fido2CmdGetAssertion
, false , data
, datalen
);
861 PrintAndLog ( "---------------- CBOR ------------------" );
864 res
= FIDO2GetAssertion ( data
, datalen
, buf
, sizeof ( buf
), & len
, & sw
);
867 PrintAndLog ( "Can't execute get assertion command. res=%x. Exit..." , res
);
872 PrintAndLog ( "ERROR execute get assertion command. APDU response status: %04x - %s" , sw
, GetAPDUCodeDescription ( sw
>> 8 , sw
& 0xff ));
877 PrintAndLog ( "FIDO2 get assertion error: %d - %s" , buf
[ 0 ], fido2GetCmdErrorDescription ( buf
[ 0 ]));
881 PrintAndLog ( "GetAssertion result (%d b) OK." , len
);
883 PrintAndLog ( "CBOR get assertion response:" );
884 PrintAndLog ( "---------------- CBOR ------------------" );
885 TinyCborPrintFIDOPackage ( fido2CmdGetAssertion
, true , & buf
[ 1 ], len
- 1 );
886 PrintAndLog ( "---------------- CBOR ------------------" );
889 // parse returned cbor
890 FIDO2GetAssertionParseRes ( root
, & buf
[ 1 ], len
- 1 , verbose
, verbose2
, showCBOR
);
893 res
= json_dump_file ( root
, fname
, JSON_INDENT ( 2 ));
895 PrintAndLog ( "ERROR: can't save the file: %s" , fname
);
898 PrintAndLog ( "File `%s` saved." , fname
);
906 static command_t CommandTable
[] =
908 { "help" , CmdHelp
, 1 , "This help." },
909 { "info" , CmdHFFidoInfo
, 0 , "Info about FIDO tag." },
910 { "reg" , CmdHFFidoRegister
, 0 , "FIDO U2F Registration Message." },
911 { "auth" , CmdHFFidoAuthenticate
, 0 , "FIDO U2F Authentication Message." },
912 { "make" , CmdHFFido2MakeCredential
, 0 , "FIDO2 MakeCredential command." },
913 { "assert" , CmdHFFido2GetAssertion
, 0 , "FIDO2 GetAssertion command." },
914 { NULL
, NULL
, 0 , NULL
}
917 int CmdHFFido ( const char * Cmd
) {
918 ( void ) WaitForResponseTimeout ( CMD_ACK
, NULL
, 100 );
919 CmdsParse ( CommandTable
, Cmd
);
923 int CmdHelp ( const char * Cmd
) {
924 CmdsHelp ( CommandTable
);