]>
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 "cliparser/cliparser.h"
44 #include "crypto/asn1utils.h"
45 #include "crypto/libpcrypto.h"
46 #include "fido/cbortools.h"
47 #include "fido/fidocore.h"
48 #include "fido/cose.h"
50 static int CmdHelp ( const char * Cmd
);
52 int CmdHFFidoInfo ( const char * cmd
) {
54 if ( cmd
&& strlen ( cmd
) > 0 )
55 PrintAndLog ( "WARNING: command don't have any parameters. \n " );
57 // info about 14a part
61 PrintAndLog ( "--------------------------------------------" );
62 SetAPDULogging ( false );
64 uint8_t buf
[ APDU_RES_LEN
] = { 0 };
67 int res
= FIDOSelect ( true , true , buf
, sizeof ( buf
), & len
, & sw
);
76 PrintAndLog ( "Not a FIDO card! APDU response: %04x - %s" , sw
, GetAPDUCodeDescription ( sw
>> 8 , sw
& 0xff ));
78 PrintAndLog ( "APDU exchange error. Card returns 0x0000." );
84 if (! strncmp (( char *) buf
, "U2F_V2" , 7 )) {
85 if (! strncmp (( char *) buf
, "FIDO_2_0" , 8 )) {
86 PrintAndLog ( "FIDO2 authenricator detected. Version: %.*s" , len
, buf
);
88 PrintAndLog ( "FIDO authenricator detected (not standard U2F)." );
89 PrintAndLog ( "Non U2F authenticator version:" );
90 dump_buffer (( const unsigned char *) buf
, len
, NULL
, 0 );
93 PrintAndLog ( "FIDO U2F authenricator detected. Version: %.*s" , len
, buf
);
96 res
= FIDO2GetInfo ( buf
, sizeof ( buf
), & len
, & sw
);
102 PrintAndLog ( "FIDO2 version not exists (%04x - %s)." , sw
, GetAPDUCodeDescription ( sw
>> 8 , sw
& 0xff ));
108 PrintAndLog ( "FIDO2 ger version error: %d - %s" , buf
[ 0 ], fido2GetCmdErrorDescription ( buf
[ 0 ]));
114 // PrintAndLog("FIDO2 version: (len=%d)", len);
115 // dump_buffer((const unsigned char *)buf, len, NULL, 0);
118 PrintAndLog ( "FIDO2 version CBOR decoded:" );
119 TinyCborPrintFIDOPackage ( fido2CmdGetInfo
, true , & buf
[ 1 ], len
- 1 );
121 PrintAndLog ( "FIDO2 version length error" );
127 json_t
* OpenJson ( int paramnum
, char * fname
, void * argtable
[], bool * err
) {
132 uint8_t jsonname
[ 250 ] ={ 0 };
133 char * cjsonname
= ( char *) jsonname
;
136 // CLIGetStrWithReturn(paramnum, jsonname, &jsonnamelen);
137 if ( CLIParamStrToBuf ( arg_get_str ( paramnum
), jsonname
, sizeof ( jsonname
), & jsonnamelen
)) {
142 // current path + file name
143 if (! strstr ( cjsonname
, ".json" ))
144 strcat ( cjsonname
, ".json" );
147 strcpy ( fname
, get_my_executable_directory ());
148 strcat ( fname
, cjsonname
);
149 if ( access ( fname
, F_OK
) != - 1 ) {
150 root
= json_load_file ( fname
, 0 , & error
);
152 PrintAndLog ( "ERROR: json error on line %d: %s" , error
. line
, error
. text
);
157 if (! json_is_object ( root
)) {
158 PrintAndLog ( "ERROR: Invalid json format. root must be an object." );
165 root
= json_object ();
171 int CmdHFFidoRegister ( const char * cmd
) {
172 uint8_t data
[ 64 ] = { 0 };
174 uint8_t cdata
[ 250 ] = { 0 };
176 uint8_t adata
[ 250 ] = { 0 };
179 CLIParserInit ( "hf fido reg" ,
180 "Initiate a U2F token registration. Needs two 32-byte hash number. \n challenge parameter (32b) and application parameter (32b)." ,
181 "Usage: \n\t hf fido reg -> execute command with 2 parameters, filled 0x00 \n "
182 " \t hf fido reg 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with parameters"
183 " \t hf fido reg -p s0 s1 -> execute command with plain parameters" );
187 arg_lit0 ( "aA" , "apdu" , "show APDU reqests and responses" ),
188 arg_litn ( "vV" , "verbose" , 0 , 2 , "show technical data. vv - show full certificates data" ),
189 arg_lit0 ( "pP" , "plain" , "send plain ASCII to challenge and application parameters instead of HEX" ),
190 arg_lit0 ( "tT" , "tlv" , "Show DER certificate contents in TLV representation" ),
191 arg_str0 ( "jJ" , "json" , "fido.json" , "JSON input / output file name for parameters." ),
192 arg_str0 ( NULL
, NULL
, "<HEX/ASCII challenge parameter (32b HEX/1..16 chars)>" , NULL
),
193 arg_str0 ( NULL
, NULL
, "<HEX/ASCII application parameter (32b HEX/1..16 chars)>" , NULL
),
196 CLIExecWithReturn ( cmd
, argtable
, true );
198 bool APDULogging
= arg_get_lit ( 1 );
199 bool verbose
= arg_get_lit ( 2 );
200 bool verbose2
= arg_get_lit ( 2 ) > 1 ;
201 bool paramsPlain
= arg_get_lit ( 3 );
202 bool showDERTLV
= arg_get_lit ( 4 );
204 char fname
[ 250 ] = { 0 };
206 root
= OpenJson ( 5 , fname
, argtable
, & err
);
211 JsonLoadBufAsHex ( root
, "$.ChallengeParam" , data
, 32 , & jlen
);
212 JsonLoadBufAsHex ( root
, "$.ApplicationParam" , & data
[ 32 ], 32 , & jlen
);
216 memset ( cdata
, 0x00 , 32 );
217 CLIGetStrWithReturn ( 6 , cdata
, & chlen
);
218 if ( chlen
&& chlen
> 16 ) {
219 PrintAndLog ( "ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d" , chlen
);
223 CLIGetHexWithReturn ( 6 , cdata
, & chlen
);
224 if ( chlen
&& chlen
!= 32 ) {
225 PrintAndLog ( "ERROR: challenge parameter length must be 32 bytes only." );
230 memmove ( data
, cdata
, 32 );
234 memset ( adata
, 0x00 , 32 );
235 CLIGetStrWithReturn ( 7 , adata
, & applen
);
236 if ( applen
&& applen
> 16 ) {
237 PrintAndLog ( "ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d" , applen
);
241 CLIGetHexWithReturn ( 7 , adata
, & applen
);
242 if ( applen
&& applen
!= 32 ) {
243 PrintAndLog ( "ERROR: application parameter length must be 32 bytes only." );
248 memmove (& data
[ 32 ], adata
, 32 );
252 SetAPDULogging ( APDULogging
);
254 // 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
255 // application parameter [32 bytes] - The application parameter is the SHA-256 hash of the UTF-8 encoding of the application identity
257 uint8_t buf
[ 2048 ] = { 0 };
262 int res
= FIDOSelect ( true , true , buf
, sizeof ( buf
), & len
, & sw
);
265 PrintAndLog ( "Can't select authenticator. res=%x. Exit..." , res
);
271 PrintAndLog ( "Can't select FIDO application. APDU response status: %04x - %s" , sw
, GetAPDUCodeDescription ( sw
>> 8 , sw
& 0xff ));
276 res
= FIDORegister ( data
, buf
, sizeof ( buf
), & len
, & sw
);
279 PrintAndLog ( "Can't execute register command. res=%x. Exit..." , res
);
284 PrintAndLog ( "ERROR execute register command. APDU response status: %04x - %s" , sw
, GetAPDUCodeDescription ( sw
>> 8 , sw
& 0xff ));
290 PrintAndLog ( "---------------------------------------------------------------" );
291 PrintAndLog ( "data len: %d" , len
);
293 PrintAndLog ( "--------------data----------------------" );
294 dump_buffer (( const unsigned char *) buf
, len
, NULL
, 0 );
295 PrintAndLog ( "--------------data----------------------" );
298 if ( buf
[ 0 ] != 0x05 ) {
299 PrintAndLog ( "ERROR: First byte must be 0x05, but it %2x" , buf
[ 0 ]);
302 PrintAndLog ( "User public key: %s" , sprint_hex (& buf
[ 1 ], 65 ));
304 uint8_t keyHandleLen
= buf
[ 66 ];
305 PrintAndLog ( "Key handle[%d]: %s" , keyHandleLen
, sprint_hex (& buf
[ 67 ], keyHandleLen
));
307 int derp
= 67 + keyHandleLen
;
308 int derLen
= ( buf
[ derp
+ 2 ] << 8 ) + buf
[ derp
+ 3 ] + 4 ;
310 PrintAndLog ( "DER certificate[%d]: \n ------------------DER-------------------" , derLen
);
311 dump_buffer_simple (( const unsigned char *)& buf
[ derp
], derLen
, NULL
);
312 PrintAndLog ( " \n ----------------DER---------------------" );
315 PrintAndLog ( "------------------DER-------------------" );
316 PrintAndLog ( "DER certificate[%d]: %s..." , derLen
, sprint_hex (& buf
[ derp
], 20 ));
319 // check and print DER certificate
320 uint8_t public_key
[ 65 ] = { 0 };
322 // print DER certificate in TLV view
324 PrintAndLog ( "----------------DER TLV-----------------" );
325 asn1_print (& buf
[ derp
], derLen
, " " );
326 PrintAndLog ( "----------------DER TLV-----------------" );
329 FIDOCheckDERAndGetKey (& buf
[ derp
], derLen
, verbose
, public_key
, sizeof ( public_key
));
332 int hashp
= 1 + 65 + 1 + keyHandleLen
+ derLen
;
333 PrintAndLog ( "Hash[%d]: %s" , len
- hashp
, sprint_hex (& buf
[ hashp
], len
- hashp
));
335 // check ANSI X9.62 format ECDSA signature (on P-256)
336 uint8_t rval
[ 300 ] = { 0 };
337 uint8_t sval
[ 300 ] = { 0 };
338 res
= ecdsa_asn1_get_signature (& buf
[ hashp
], len
- hashp
, rval
, sval
);
341 PrintAndLog ( " r: %s" , sprint_hex ( rval
, 32 ));
342 PrintAndLog ( " s: %s" , sprint_hex ( sval
, 32 ));
345 uint8_t xbuf
[ 4096 ] = { 0 };
347 res
= FillBuffer ( xbuf
, sizeof ( xbuf
), & xbuflen
,
349 & data
[ 32 ], 32 , // application parameter
350 & data
[ 0 ], 32 , // challenge parameter
351 & buf
[ 67 ], keyHandleLen
, // keyHandle
352 & buf
[ 1 ], 65 , // user public key
354 //PrintAndLog("--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen));
355 res
= ecdsa_signature_verify ( public_key
, xbuf
, xbuflen
, & buf
[ hashp
], len
- hashp
);
357 if ( res
== - 0x4e00 ) {
358 PrintAndLog ( "Signature is NOT VALID." );
360 PrintAndLog ( "Other signature check error: %x %s" , ( res
< 0 )?- res
: res
, ecdsa_get_error ( res
));
363 PrintAndLog ( "Signature is OK." );
367 PrintAndLog ( "Invalid signature. res=%d." , res
);
370 PrintAndLog ( " \n auth command: " );
371 printf ( "hf fido auth %s%s" , paramsPlain
? "-p " : "" , sprint_hex_inrow (& buf
[ 67 ], keyHandleLen
));
373 printf ( " %s" , paramsPlain
?( char *) cdata
: sprint_hex_inrow ( cdata
, 32 ));
375 printf ( " %s" , paramsPlain
?( char *) adata
: sprint_hex_inrow ( adata
, 32 ));
379 JsonSaveBufAsHex ( root
, "ChallengeParam" , data
, 32 );
380 JsonSaveBufAsHex ( root
, "ApplicationParam" , & data
[ 32 ], 32 );
381 JsonSaveBufAsHexCompact ( root
, "PublicKey" , & buf
[ 1 ], 65 );
382 JsonSaveInt ( root
, "KeyHandleLen" , keyHandleLen
);
383 JsonSaveBufAsHexCompact ( root
, "KeyHandle" , & buf
[ 67 ], keyHandleLen
);
384 JsonSaveBufAsHexCompact ( root
, "DER" , & buf
[ 67 + keyHandleLen
], derLen
);
386 res
= json_dump_file ( root
, fname
, JSON_INDENT ( 2 ));
388 PrintAndLog ( "ERROR: can't save the file: %s" , fname
);
391 PrintAndLog ( "File `%s` saved." , fname
);
400 int CmdHFFidoAuthenticate ( const char * cmd
) {
401 uint8_t data
[ 512 ] = { 0 };
402 uint8_t hdata
[ 250 ] = { 0 };
403 bool public_key_loaded
= false ;
404 uint8_t public_key
[ 65 ] = { 0 };
406 uint8_t keyHandleLen
= 0 ;
409 CLIParserInit ( "hf fido auth" ,
410 "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)." ,
411 "Usage: \n\t hf fido auth 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with 2 parameters, filled 0x00 and key handle \n "
412 " \t hf fido auth 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f "
413 "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with parameters" );
417 arg_lit0 ( "aA" , "apdu" , "show APDU reqests and responses" ),
418 arg_lit0 ( "vV" , "verbose" , "show technical data" ),
419 arg_lit0 ( "pP" , "plain" , "send plain ASCII to challenge and application parameters instead of HEX" ),
420 arg_rem ( "default mode:" , "dont-enforce-user-presence-and-sign" ),
421 arg_lit0 ( "uU" , "user" , "mode: enforce-user-presence-and-sign" ),
422 arg_lit0 ( "cC" , "check" , "mode: check-only" ),
423 arg_str0 ( "jJ" , "json" , "fido.json" , "JSON input / output file name for parameters." ),
424 arg_str0 ( "kK" , "key" , "public key to verify signature" , NULL
),
425 arg_str0 ( NULL
, NULL
, "<HEX key handle (var 0..255b)>" , NULL
),
426 arg_str0 ( NULL
, NULL
, "<HEX/ASCII challenge parameter (32b HEX/1..16 chars)>" , NULL
),
427 arg_str0 ( NULL
, NULL
, "<HEX/ASCII application parameter (32b HEX/1..16 chars)>" , NULL
),
430 CLIExecWithReturn ( cmd
, argtable
, true );
432 bool APDULogging
= arg_get_lit ( 1 );
433 bool verbose
= arg_get_lit ( 2 );
434 bool paramsPlain
= arg_get_lit ( 3 );
435 uint8_t controlByte
= 0x08 ;
441 char fname
[ 250 ] = { 0 };
443 root
= OpenJson ( 7 , fname
, argtable
, & err
);
448 JsonLoadBufAsHex ( root
, "$.ChallengeParam" , data
, 32 , & jlen
);
449 JsonLoadBufAsHex ( root
, "$.ApplicationParam" , & data
[ 32 ], 32 , & jlen
);
450 JsonLoadBufAsHex ( root
, "$.KeyHandle" , & data
[ 65 ], 512 - 67 , & jlen
);
451 keyHandleLen
= jlen
& 0xff ;
452 data
[ 64 ] = keyHandleLen
;
453 JsonLoadBufAsHex ( root
, "$.PublicKey" , public_key
, 65 , & jlen
);
454 public_key_loaded
= ( jlen
> 0 );
458 CLIGetHexWithReturn ( 8 , hdata
, & hdatalen
);
459 if ( hdatalen
&& hdatalen
!= 65 ) {
460 PrintAndLog ( "ERROR: public key length must be 65 bytes only." );
464 memmove ( public_key
, hdata
, hdatalen
);
465 public_key_loaded
= true ;
468 CLIGetHexWithReturn ( 9 , hdata
, & hdatalen
);
469 if ( hdatalen
> 255 ) {
470 PrintAndLog ( "ERROR: application parameter length must be less than 255." );
474 keyHandleLen
= hdatalen
;
475 data
[ 64 ] = keyHandleLen
;
476 memmove (& data
[ 65 ], hdata
, keyHandleLen
);
480 memset ( hdata
, 0x00 , 32 );
481 CLIGetStrWithReturn ( 9 , hdata
, & hdatalen
);
482 if ( hdatalen
&& hdatalen
> 16 ) {
483 PrintAndLog ( "ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d" , hdatalen
);
487 CLIGetHexWithReturn ( 10 , hdata
, & hdatalen
);
488 if ( hdatalen
&& hdatalen
!= 32 ) {
489 PrintAndLog ( "ERROR: challenge parameter length must be 32 bytes only." );
494 memmove ( data
, hdata
, 32 );
497 memset ( hdata
, 0x00 , 32 );
498 CLIGetStrWithReturn ( 11 , hdata
, & hdatalen
);
499 if ( hdatalen
&& hdatalen
> 16 ) {
500 PrintAndLog ( "ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d" , hdatalen
);
504 CLIGetHexWithReturn ( 10 , hdata
, & hdatalen
);
505 if ( hdatalen
&& hdatalen
!= 32 ) {
506 PrintAndLog ( "ERROR: application parameter length must be 32 bytes only." );
511 memmove (& data
[ 32 ], hdata
, 32 );
515 SetAPDULogging ( APDULogging
);
517 // (in parameter) conrtol byte 0x07 - check only, 0x03 - user presense + cign. 0x08 - sign only
518 // challenge parameter [32 bytes]
519 // application parameter [32 bytes]
520 // key handle length [1b] = N
523 uint8_t datalen
= 32 + 32 + 1 + keyHandleLen
;
525 uint8_t buf
[ 2048 ] = { 0 };
530 int res
= FIDOSelect ( true , true , buf
, sizeof ( buf
), & len
, & sw
);
533 PrintAndLog ( "Can't select authenticator. res=%x. Exit..." , res
);
539 PrintAndLog ( "Can't select FIDO application. APDU response status: %04x - %s" , sw
, GetAPDUCodeDescription ( sw
>> 8 , sw
& 0xff ));
544 res
= FIDOAuthentication ( data
, datalen
, controlByte
, buf
, sizeof ( buf
), & len
, & sw
);
547 PrintAndLog ( "Can't execute authentication command. res=%x. Exit..." , res
);
552 PrintAndLog ( "ERROR execute authentication command. APDU response status: %04x - %s" , sw
, GetAPDUCodeDescription ( sw
>> 8 , sw
& 0xff ));
556 PrintAndLog ( "---------------------------------------------------------------" );
557 PrintAndLog ( "User presence: %s" , ( buf
[ 0 ]? "verified" : "not verified" ));
558 uint32_t cntr
= ( uint32_t ) bytes_to_num (& buf
[ 1 ], 4 );
559 PrintAndLog ( "Counter: %d" , cntr
);
560 PrintAndLog ( "Hash[%d]: %s" , len
- 5 , sprint_hex (& buf
[ 5 ], len
- 5 ));
562 // check ANSI X9.62 format ECDSA signature (on P-256)
563 uint8_t rval
[ 300 ] = { 0 };
564 uint8_t sval
[ 300 ] = { 0 };
565 res
= ecdsa_asn1_get_signature (& buf
[ 5 ], len
- 5 , rval
, sval
);
568 PrintAndLog ( " r: %s" , sprint_hex ( rval
, 32 ));
569 PrintAndLog ( " s: %s" , sprint_hex ( sval
, 32 ));
571 if ( public_key_loaded
) {
572 uint8_t xbuf
[ 4096 ] = { 0 };
574 res
= FillBuffer ( xbuf
, sizeof ( xbuf
), & xbuflen
,
575 & data
[ 32 ], 32 , // application parameter
576 & buf
[ 0 ], 1 , // user presence
577 & buf
[ 1 ], 4 , // counter
578 data
, 32 , // challenge parameter
580 //PrintAndLog("--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen));
581 res
= ecdsa_signature_verify ( public_key
, xbuf
, xbuflen
, & buf
[ 5 ], len
- 5 );
583 if ( res
== - 0x4e00 ) {
584 PrintAndLog ( "Signature is NOT VALID." );
586 PrintAndLog ( "Other signature check error: %x %s" , ( res
< 0 )?- res
: res
, ecdsa_get_error ( res
));
589 PrintAndLog ( "Signature is OK." );
592 PrintAndLog ( "No public key provided. can't check signature." );
595 PrintAndLog ( "Invalid signature. res=%d." , res
);
599 JsonSaveBufAsHex ( root
, "ChallengeParam" , data
, 32 );
600 JsonSaveBufAsHex ( root
, "ApplicationParam" , & data
[ 32 ], 32 );
601 JsonSaveInt ( root
, "KeyHandleLen" , keyHandleLen
);
602 JsonSaveBufAsHexCompact ( root
, "KeyHandle" , & data
[ 65 ], keyHandleLen
);
603 JsonSaveInt ( root
, "Counter" , cntr
);
605 res
= json_dump_file ( root
, fname
, JSON_INDENT ( 2 ));
607 PrintAndLog ( "ERROR: can't save the file: %s" , fname
);
610 PrintAndLog ( "File `%s` saved." , fname
);
618 void CheckSlash ( char * fileName
) {
619 if (( fileName
[ strlen ( fileName
) - 1 ] != '/' ) &&
620 ( fileName
[ strlen ( fileName
) - 1 ] != ' \\ ' ))
621 strcat ( fileName
, "/" );
624 int GetExistsFileNameJson ( char * prefixDir
, char * reqestedFileName
, char * fileName
) {
626 strcpy ( fileName
, get_my_executable_directory ());
627 CheckSlash ( fileName
);
629 strcat ( fileName
, prefixDir
);
630 CheckSlash ( fileName
);
632 strcat ( fileName
, reqestedFileName
);
633 if (! strstr ( fileName
, ".json" ))
634 strcat ( fileName
, ".json" );
636 if ( access ( fileName
, F_OK
) < 0 ) {
637 strcpy ( fileName
, get_my_executable_directory ());
638 CheckSlash ( fileName
);
640 strcat ( fileName
, reqestedFileName
);
641 if (! strstr ( fileName
, ".json" ))
642 strcat ( fileName
, ".json" );
644 if ( access ( fileName
, F_OK
) < 0 ) {
645 return 1 ; // file not found
651 int CmdHFFido2MakeCredential ( const char * cmd
) {
654 char fname
[ 300 ] = { 0 };
656 CLIParserInit ( "hf fido make" ,
657 "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." ,
658 "Usage: \n\t hf fido make -> execute command default parameters file `fido2.json` \n "
659 " \t hf fido make test.json -> execute command with parameters file `text.json`" );
663 arg_lit0 ( "aA" , "apdu" , "show APDU reqests and responses" ),
664 arg_litn ( "vV" , "verbose" , 0 , 2 , "show technical data. vv - show full certificates data" ),
665 arg_lit0 ( "tT" , "tlv" , "Show DER certificate contents in TLV representation" ),
666 arg_lit0 ( "cC" , "cbor" , "show CBOR decoded data" ),
667 arg_str0 ( NULL
, NULL
, "<json file name>" , "JSON input / output file name for parameters. Default `fido2.json`" ),
670 CLIExecWithReturn ( cmd
, argtable
, true );
672 bool APDULogging
= arg_get_lit ( 1 );
673 bool verbose
= arg_get_lit ( 2 );
674 bool verbose2
= arg_get_lit ( 2 ) > 1 ;
675 bool showDERTLV
= arg_get_lit ( 3 );
676 bool showCBOR
= arg_get_lit ( 4 );
678 uint8_t jsonname
[ 250 ] ={ 0 };
679 char * cjsonname
= ( char *) jsonname
;
681 CLIGetStrWithReturn ( 5 , jsonname
, & jsonnamelen
);
684 strcat ( cjsonname
, "fido2" );
685 jsonnamelen
= strlen ( cjsonname
);
690 SetAPDULogging ( APDULogging
);
692 int res
= GetExistsFileNameJson ( "fido" , cjsonname
, fname
);
694 PrintAndLog ( "ERROR: Can't found the json file." );
697 PrintAndLog ( "fname: %s \n " , fname
);
698 root
= json_load_file ( fname
, 0 , & error
);
700 PrintAndLog ( "ERROR: json error on line %d: %s" , error
. line
, error
. text
);
704 uint8_t data
[ 2048 ] = { 0 };
706 uint8_t buf
[ 2048 ] = { 0 };
711 res
= FIDOSelect ( true , true , buf
, sizeof ( buf
), & len
, & sw
);
714 PrintAndLog ( "Can't select authenticator. res=%x. Exit..." , res
);
720 PrintAndLog ( "Can't select FIDO application. APDU response status: %04x - %s" , sw
, GetAPDUCodeDescription ( sw
>> 8 , sw
& 0xff ));
725 res
= FIDO2CreateMakeCredentionalReq ( root
, data
, sizeof ( data
), & datalen
);
730 PrintAndLog ( "CBOR make credentional request:" );
731 PrintAndLog ( "---------------- CBOR ------------------" );
732 TinyCborPrintFIDOPackage ( fido2CmdMakeCredential
, false , data
, datalen
);
733 PrintAndLog ( "---------------- CBOR ------------------" );
736 res
= FIDO2MakeCredential ( data
, datalen
, buf
, sizeof ( buf
), & len
, & sw
);
739 PrintAndLog ( "Can't execute make credential command. res=%x. Exit..." , res
);
744 PrintAndLog ( "ERROR execute make credential command. APDU response status: %04x - %s" , sw
, GetAPDUCodeDescription ( sw
>> 8 , sw
& 0xff ));
749 PrintAndLog ( "FIDO2 make credential error: %d - %s" , buf
[ 0 ], fido2GetCmdErrorDescription ( buf
[ 0 ]));
753 PrintAndLog ( "MakeCredential result (%d b) OK." , len
);
755 PrintAndLog ( "CBOR make credentional response:" );
756 PrintAndLog ( "---------------- CBOR ------------------" );
757 TinyCborPrintFIDOPackage ( fido2CmdMakeCredential
, true , & buf
[ 1 ], len
- 1 );
758 PrintAndLog ( "---------------- CBOR ------------------" );
761 // parse returned cbor
762 FIDO2MakeCredentionalParseRes ( root
, & buf
[ 1 ], len
- 1 , verbose
, verbose2
, showCBOR
, showDERTLV
);
765 res
= json_dump_file ( root
, fname
, JSON_INDENT ( 2 ));
767 PrintAndLog ( "ERROR: can't save the file: %s" , fname
);
770 PrintAndLog ( "File `%s` saved." , fname
);
778 int CmdHFFido2GetAssertion ( const char * cmd
) {
781 char fname
[ 300 ] = { 0 };
783 CLIParserInit ( "hf fido assert" ,
784 "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." ,
785 "Usage: \n\t hf fido assert -> execute command default parameters file `fido2.json` \n "
786 " \t hf fido assert test.json -l -> execute command with parameters file `text.json` and add to request CredentialId" );
790 arg_lit0 ( "aA" , "apdu" , "show APDU reqests and responses" ),
791 arg_litn ( "vV" , "verbose" , 0 , 2 , "show technical data. vv - show full certificates data" ),
792 arg_lit0 ( "cC" , "cbor" , "show CBOR decoded data" ),
793 arg_lit0 ( "lL" , "list" , "add CredentialId from json to allowList. Needs if `rk` option is `false` (authenticator don't store credential to its memory)" ),
794 arg_str0 ( NULL
, NULL
, "<json file name>" , "JSON input / output file name for parameters. Default `fido2.json`" ),
797 CLIExecWithReturn ( cmd
, argtable
, true );
799 bool APDULogging
= arg_get_lit ( 1 );
800 bool verbose
= arg_get_lit ( 2 );
801 bool verbose2
= arg_get_lit ( 2 ) > 1 ;
802 bool showCBOR
= arg_get_lit ( 3 );
803 bool createAllowList
= arg_get_lit ( 4 );
805 uint8_t jsonname
[ 250 ] ={ 0 };
806 char * cjsonname
= ( char *) jsonname
;
808 CLIGetStrWithReturn ( 5 , jsonname
, & jsonnamelen
);
811 strcat ( cjsonname
, "fido2" );
812 jsonnamelen
= strlen ( cjsonname
);
817 SetAPDULogging ( APDULogging
);
819 int res
= GetExistsFileNameJson ( "fido" , "fido2" , fname
);
821 PrintAndLog ( "ERROR: Can't found the json file." );
824 PrintAndLog ( "fname: %s \n " , fname
);
825 root
= json_load_file ( fname
, 0 , & error
);
827 PrintAndLog ( "ERROR: json error on line %d: %s" , error
. line
, error
. text
);
831 uint8_t data
[ 2048 ] = { 0 };
833 uint8_t buf
[ 2048 ] = { 0 };
838 res
= FIDOSelect ( true , true , buf
, sizeof ( buf
), & len
, & sw
);
841 PrintAndLog ( "Can't select authenticator. res=%x. Exit..." , res
);
847 PrintAndLog ( "Can't select FIDO application. APDU response status: %04x - %s" , sw
, GetAPDUCodeDescription ( sw
>> 8 , sw
& 0xff ));
852 res
= FIDO2CreateGetAssertionReq ( root
, data
, sizeof ( data
), & datalen
, createAllowList
);
857 PrintAndLog ( "CBOR get assertion request:" );
858 PrintAndLog ( "---------------- CBOR ------------------" );
859 TinyCborPrintFIDOPackage ( fido2CmdGetAssertion
, false , data
, datalen
);
860 PrintAndLog ( "---------------- CBOR ------------------" );
863 res
= FIDO2GetAssertion ( data
, datalen
, buf
, sizeof ( buf
), & len
, & sw
);
866 PrintAndLog ( "Can't execute get assertion command. res=%x. Exit..." , res
);
871 PrintAndLog ( "ERROR execute get assertion command. APDU response status: %04x - %s" , sw
, GetAPDUCodeDescription ( sw
>> 8 , sw
& 0xff ));
876 PrintAndLog ( "FIDO2 get assertion error: %d - %s" , buf
[ 0 ], fido2GetCmdErrorDescription ( buf
[ 0 ]));
880 PrintAndLog ( "GetAssertion result (%d b) OK." , len
);
882 PrintAndLog ( "CBOR get assertion response:" );
883 PrintAndLog ( "---------------- CBOR ------------------" );
884 TinyCborPrintFIDOPackage ( fido2CmdGetAssertion
, true , & buf
[ 1 ], len
- 1 );
885 PrintAndLog ( "---------------- CBOR ------------------" );
888 // parse returned cbor
889 FIDO2GetAssertionParseRes ( root
, & buf
[ 1 ], len
- 1 , verbose
, verbose2
, showCBOR
);
892 res
= json_dump_file ( root
, fname
, JSON_INDENT ( 2 ));
894 PrintAndLog ( "ERROR: can't save the file: %s" , fname
);
897 PrintAndLog ( "File `%s` saved." , fname
);
905 static command_t CommandTable
[] =
907 { "help" , CmdHelp
, 1 , "This help." },
908 { "info" , CmdHFFidoInfo
, 0 , "Info about FIDO tag." },
909 { "reg" , CmdHFFidoRegister
, 0 , "FIDO U2F Registration Message." },
910 { "auth" , CmdHFFidoAuthenticate
, 0 , "FIDO U2F Authentication Message." },
911 { "make" , CmdHFFido2MakeCredential
, 0 , "FIDO2 MakeCredential command." },
912 { "assert" , CmdHFFido2GetAssertion
, 0 , "FIDO2 GetAssertion command." },
913 { NULL
, NULL
, 0 , NULL
}
916 int CmdHFFido ( const char * Cmd
) {
917 ( void ) WaitForResponseTimeout ( CMD_ACK
, NULL
, 100 );
918 CmdsParse ( CommandTable
, Cmd
);
922 int CmdHelp ( const char * Cmd
) {
923 CmdsHelp ( CommandTable
);