]> cvs.zerfleddert.de Git - proxmark3-svn/blame - client/cmdhffido.c
Fix format-truncation warning, missing string.h inclusion and strnlen warning (#723)
[proxmark3-svn] / client / cmdhffido.c
CommitLineData
39cc1c87
OM
1//-----------------------------------------------------------------------------
2// Copyright (C) 2018 Merlok
3//
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
6// the license.
7//-----------------------------------------------------------------------------
8// High frequency MIFARE Plus commands
9//-----------------------------------------------------------------------------
10//
11// Documentation here:
12//
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//-----------------------------------------------------------------------------
20
21
22#include "cmdhffido.h"
23
24#include <inttypes.h>
25#include <string.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <ctype.h>
29#include <unistd.h>
30#include <jansson.h>
31#include "comms.h"
32#include "cmdmain.h"
33#include "util.h"
34#include "ui.h"
35#include "proxmark3.h"
36#include "cmdhf14a.h"
37#include "mifare.h"
38#include "emv/emvcore.h"
39#include "emv/emvjson.h"
40#include "emv/dump.h"
41#include "cliparser/cliparser.h"
6b882a39
OM
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"
39cc1c87
OM
48
49static int CmdHelp(const char *Cmd);
50
51int 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};
53
54 return EMVSelect(ActivateField, LeaveFieldON, data, sizeof(data), Result, MaxResultLen, ResultLen, sw, NULL);
55}
56
57int 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
60 res = 0;
61 // software chaining
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
66 res = 0;
67
68 *ResultLen += oldlen;
69 if (*ResultLen > MaxResultLen)
70 return 100;
71 }
72 return res;
73}
74
75int 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);
77}
78
79int 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);
81}
82
83int 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);
86}
87
88int CmdHFFidoInfo(const char *cmd) {
89
90 if (cmd && strlen(cmd) > 0)
91 PrintAndLog("WARNING: command don't have any parameters.\n");
92
93 // info about 14a part
94 CmdHF14AInfo("");
95
96 // FIDO info
97 PrintAndLog("--------------------------------------------");
98 SetAPDULogging(false);
99
100 uint8_t buf[APDU_RES_LEN] = {0};
101 size_t len = 0;
102 uint16_t sw = 0;
103 int res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw);
104
105 if (res) {
106 DropField();
107 return res;
108 }
109
110 if (sw != 0x9000) {
111 if (sw)
112 PrintAndLog("Not a FIDO card! APDU response: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
113 else
114 PrintAndLog("APDU exchange error. Card returns 0x0000.");
115
116 DropField();
117 return 0;
118 }
119
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);
123 } else {
124 PrintAndLog("FIDO authenricator detected (not standard U2F).");
125 PrintAndLog("Non U2F authenticator version:");
126 dump_buffer((const unsigned char *)buf, len, NULL, 0);
127 }
128 } else {
129 PrintAndLog("FIDO U2F authenricator detected. Version: %.*s", len, buf);
130 }
131
132 res = FIDO2GetInfo(buf, sizeof(buf), &len, &sw);
133 DropField();
134 if (res) {
135 return res;
136 }
137 if (sw != 0x9000) {
138 PrintAndLog("FIDO2 version not exists (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
139
140 return 0;
141 }
142
143 PrintAndLog("FIDO2 version: (%d)", len);
144 dump_buffer((const unsigned char *)buf, len, NULL, 0);
145
146 return 0;
147}
148
149json_t *OpenJson(int paramnum, char *fname, void* argtable[], bool *err) {
150 json_t *root = NULL;
151 json_error_t error;
152 *err = false;
153
154 uint8_t jsonname[250] ={0};
155 char *cjsonname = (char *)jsonname;
156 int jsonnamelen = 0;
157
158 // CLIGetStrWithReturn(paramnum, jsonname, &jsonnamelen);
159 if (CLIParamStrToBuf(arg_get_str(paramnum), jsonname, sizeof(jsonname), &jsonnamelen)) {
160 CLIParserFree();
161 return NULL;
162 }
163
164 // current path + file name
165 if (!strstr(cjsonname, ".json"))
166 strcat(cjsonname, ".json");
167
168 if (jsonnamelen) {
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);
173 if (!root) {
174 PrintAndLog("ERROR: json error on line %d: %s", error.line, error.text);
175 *err = true;
176 return NULL;
177 }
178
179 if (!json_is_object(root)) {
180 PrintAndLog("ERROR: Invalid json format. root must be an object.");
181 json_decref(root);
182 *err = true;
183 return NULL;
184 }
185
186 } else {
187 root = json_object();
188 }
189 }
190 return root;
191}
192
193int CmdHFFidoRegister(const char *cmd) {
194 uint8_t data[64] = {0};
195 int chlen = 0;
196 uint8_t cdata[250] = {0};
197 int applen = 0;
198 uint8_t adata[250] = {0};
199 json_t *root = NULL;
200
201 CLIParserInit("hf fido reg",
202 "Initiate a U2F token registration. Needs two 32-byte hash number. \nchallenge parameter (32b) and application parameter (32b).",
203 "Usage:\n\thf fido reg -> execute command with 2 parameters, filled 0x00\n"
204 "\thf fido reg 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with parameters"
205 "\thf fido reg -p s0 s1 -> execute command with plain parameters");
206
207 void* argtable[] = {
208 arg_param_begin,
209 arg_lit0("aA", "apdu", "show APDU reqests and responses"),
6b882a39 210 arg_litn("vV", "verbose", 0, 2, "show technical data. vv - show full certificates data"),
39cc1c87 211 arg_lit0("pP", "plain", "send plain ASCII to challenge and application parameters instead of HEX"),
6b882a39 212 arg_lit0("tT", "tlv", "Show DER certificate contents in TLV representation"),
39cc1c87
OM
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),
216 arg_param_end
217 };
218 CLIExecWithReturn(cmd, argtable, true);
219
220 bool APDULogging = arg_get_lit(1);
221 bool verbose = arg_get_lit(2);
6b882a39 222 bool verbose2 = arg_get_lit(2) > 1;
39cc1c87 223 bool paramsPlain = arg_get_lit(3);
6b882a39 224 bool showDERTLV = arg_get_lit(4);
39cc1c87
OM
225
226 char fname[250] = {0};
227 bool err;
6b882a39 228 root = OpenJson(5, fname, argtable, &err);
39cc1c87
OM
229 if(err)
230 return 1;
231 if (root) {
232 size_t jlen;
233 JsonLoadBufAsHex(root, "$.ChallengeParam", data, 32, &jlen);
234 JsonLoadBufAsHex(root, "$.ApplicationParam", &data[32], 32, &jlen);
235 }
236
237 if (paramsPlain) {
238 memset(cdata, 0x00, 32);
6b882a39 239 CLIGetStrWithReturn(6, cdata, &chlen);
39cc1c87
OM
240 if (chlen && chlen > 16) {
241 PrintAndLog("ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d", chlen);
242 return 1;
243 }
244 } else {
6b882a39 245 CLIGetHexWithReturn(6, cdata, &chlen);
39cc1c87
OM
246 if (chlen && chlen != 32) {
247 PrintAndLog("ERROR: challenge parameter length must be 32 bytes only.");
248 return 1;
249 }
250 }
251 if (chlen)
252 memmove(data, cdata, 32);
253
254
255 if (paramsPlain) {
256 memset(adata, 0x00, 32);
6b882a39 257 CLIGetStrWithReturn(7, adata, &applen);
39cc1c87
OM
258 if (applen && applen > 16) {
259 PrintAndLog("ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", applen);
260 return 1;
261 }
262 } else {
6b882a39 263 CLIGetHexWithReturn(7, adata, &applen);
39cc1c87
OM
264 if (applen && applen != 32) {
265 PrintAndLog("ERROR: application parameter length must be 32 bytes only.");
266 return 1;
267 }
268 }
269 if (applen)
270 memmove(&data[32], adata, 32);
271
272 CLIParserFree();
273
274 SetAPDULogging(APDULogging);
275
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
278
279 uint8_t buf[2048] = {0};
280 size_t len = 0;
281 uint16_t sw = 0;
282
283 DropField();
284 int res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw);
285
286 if (res) {
287 PrintAndLog("Can't select authenticator. res=%x. Exit...", res);
288 DropField();
289 return res;
290 }
291
292 if (sw != 0x9000) {
293 PrintAndLog("Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
294 DropField();
295 return 2;
296 }
297
298 res = FIDORegister(data, buf, sizeof(buf), &len, &sw);
299 DropField();
300 if (res) {
301 PrintAndLog("Can't execute register command. res=%x. Exit...", res);
302 return res;
303 }
304
305 if (sw != 0x9000) {
306 PrintAndLog("ERROR execute register command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
307 return 3;
308 }
309
310 PrintAndLog("");
311 if (APDULogging)
312 PrintAndLog("---------------------------------------------------------------");
313 PrintAndLog("data len: %d", len);
6b882a39 314 if (verbose2) {
39cc1c87
OM
315 PrintAndLog("--------------data----------------------");
316 dump_buffer((const unsigned char *)buf, len, NULL, 0);
317 PrintAndLog("--------------data----------------------");
318 }
319
320 if (buf[0] != 0x05) {
321 PrintAndLog("ERROR: First byte must be 0x05, but it %2x", buf[0]);
322 return 5;
323 }
324 PrintAndLog("User public key: %s", sprint_hex(&buf[1], 65));
325
326 uint8_t keyHandleLen = buf[66];
327 PrintAndLog("Key handle[%d]: %s", keyHandleLen, sprint_hex(&buf[67], keyHandleLen));
328
329 int derp = 67 + keyHandleLen;
330 int derLen = (buf[derp + 2] << 8) + buf[derp + 3] + 4;
6b882a39
OM
331 if (verbose2) {
332 PrintAndLog("DER certificate[%d]:\n------------------DER-------------------", derLen);
333 dump_buffer_simple((const unsigned char *)&buf[derp], derLen, NULL);
39cc1c87
OM
334 PrintAndLog("\n----------------DER---------------------");
335 } else {
6b882a39
OM
336 if (verbose)
337 PrintAndLog("------------------DER-------------------");
39cc1c87
OM
338 PrintAndLog("DER certificate[%d]: %s...", derLen, sprint_hex(&buf[derp], 20));
339 }
340
6b882a39
OM
341 // check and print DER certificate
342 uint8_t public_key[65] = {0};
343
344 // print DER certificate in TLV view
345 if (showDERTLV) {
346 PrintAndLog("----------------DER TLV-----------------");
347 asn1_print(&buf[derp], derLen, " ");
348 PrintAndLog("----------------DER TLV-----------------");
349 }
350
351 // load CA's
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);
355 if (res < 0) {
356 PrintAndLog("ERROR: CA parse certificate returned -0x%x - %s", -res, ecdsa_get_error(res));
357 }
358 if (verbose)
359 PrintAndLog("CA load OK. %d skipped", res);
360
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);
365 if (res) {
366 PrintAndLog("ERROR: DER parse returned 0x%x - %s", (res<0)?-res:res, ecdsa_get_error(res));
367 }
368
369 // get certificate info
370 char linfo[300] = {0};
371 if (verbose) {
372 mbedtls_x509_crt_info(linfo, sizeof(linfo), " ", &cert);
373 PrintAndLog("DER certificate info:\n%s", linfo);
374 }
375
376 // verify certificate
377 uint32_t verifyflags = 0;
378 res = mbedtls_x509_crt_verify(&cert, &cacert, NULL, NULL, &verifyflags, NULL, NULL);
379 if (res) {
380 PrintAndLog("ERROR: DER verify returned 0x%x - %s", (res<0)?-res:res, ecdsa_get_error(res));
381 } else {
382 PrintAndLog("Certificate OK.");
383 }
384
385 if (verbose) {
386 memset(linfo, 0x00, sizeof(linfo));
387 mbedtls_x509_crt_verify_info(linfo, sizeof(linfo), " ", verifyflags);
388 PrintAndLog("Verification info:\n%s", linfo);
389 }
390
391 // get public key
392 res = ecdsa_public_key_from_pk(&cert.pk, public_key, sizeof(public_key));
393 if (res) {
394 PrintAndLog("ERROR: getting public key from certificate 0x%x - %s", (res<0)?-res:res, ecdsa_get_error(res));
395 } else {
396 if (verbose)
397 PrintAndLog("Got a public key from certificate:\n%s", sprint_hex_inrow(public_key, 65));
398 }
399
400 if (verbose)
401 PrintAndLog("------------------DER-------------------");
402
403 mbedtls_x509_crt_free(&cert);
404 mbedtls_x509_crt_free(&cacert);
39cc1c87 405
6b882a39 406 // get hash
39cc1c87
OM
407 int hashp = 1 + 65 + 1 + keyHandleLen + derLen;
408 PrintAndLog("Hash[%d]: %s", len - hashp, sprint_hex(&buf[hashp], len - hashp));
6b882a39 409
39cc1c87 410 // check ANSI X9.62 format ECDSA signature (on P-256)
6b882a39
OM
411 uint8_t rval[300] = {0};
412 uint8_t sval[300] = {0};
413 res = ecdsa_asn1_get_signature(&buf[hashp], len - hashp, rval, sval);
414 if (!res) {
415 if (verbose) {
416 PrintAndLog(" r: %s", sprint_hex(rval, 32));
417 PrintAndLog(" s: %s", sprint_hex(sval, 32));
418 }
419
420 uint8_t xbuf[4096] = {0};
421 size_t xbuflen = 0;
422 res = FillBuffer(xbuf, sizeof(xbuf), &xbuflen,
423 "\x00", 1,
424 &data[32], 32, // application parameter
425 &data[0], 32, // challenge parameter
426 &buf[67], keyHandleLen, // keyHandle
427 &buf[1], 65, // user public key
428 NULL, 0);
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);
431 if (res) {
432 if (res == -0x4e00) {
433 PrintAndLog("Signature is NOT VALID.");
434 } else {
435 PrintAndLog("Other signature check error: %x %s", (res<0)?-res:res, ecdsa_get_error(res));
436 }
437 } else {
438 PrintAndLog("Signature is OK.");
439 }
440
441 } else {
442 PrintAndLog("Invalid signature. res=%d.", res);
443 }
39cc1c87
OM
444
445 PrintAndLog("\nauth command: ");
446 printf("hf fido auth %s%s", paramsPlain?"-p ":"", sprint_hex_inrow(&buf[67], keyHandleLen));
447 if(chlen || applen)
448 printf(" %s", paramsPlain?(char *)cdata:sprint_hex_inrow(cdata, 32));
449 if(applen)
450 printf(" %s", paramsPlain?(char *)adata:sprint_hex_inrow(adata, 32));
451 printf("\n");
452
453 if (root) {
454 JsonSaveBufAsHex(root, "ChallengeParam", data, 32);
455 JsonSaveBufAsHex(root, "ApplicationParam", &data[32], 32);
6b882a39 456 JsonSaveBufAsHexCompact(root, "PublicKey", &buf[1], 65);
39cc1c87
OM
457 JsonSaveInt(root, "KeyHandleLen", keyHandleLen);
458 JsonSaveBufAsHexCompact(root, "KeyHandle", &buf[67], keyHandleLen);
459 JsonSaveBufAsHexCompact(root, "DER", &buf[67 + keyHandleLen], derLen);
460
461 res = json_dump_file(root, fname, JSON_INDENT(2));
462 if (res) {
463 PrintAndLog("ERROR: can't save the file: %s", fname);
464 return 200;
465 }
466 PrintAndLog("File `%s` saved.", fname);
467
468 // free json object
469 json_decref(root);
470 }
471
472 return 0;
473};
474
475int CmdHFFidoAuthenticate(const char *cmd) {
476 uint8_t data[512] = {0};
477 uint8_t hdata[250] = {0};
6b882a39
OM
478 bool public_key_loaded = false;
479 uint8_t public_key[65] = {0};
39cc1c87
OM
480 int hdatalen = 0;
481 uint8_t keyHandleLen = 0;
482 json_t *root = NULL;
483
484 CLIParserInit("hf fido auth",
485 "Initiate a U2F token authentication. Needs key handle and two 32-byte hash number. \nkey handle(var 0..255), challenge parameter (32b) and application parameter (32b).",
486 "Usage:\n\thf fido auth 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with 2 parameters, filled 0x00 and key handle\n"
487 "\thf fido auth 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f "
488 "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with parameters");
489
490 void* argtable[] = {
491 arg_param_begin,
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."),
6b882a39 499 arg_str0("kK", "key", "public key to verify signature", NULL),
39cc1c87
OM
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),
503 arg_param_end
504 };
505 CLIExecWithReturn(cmd, argtable, true);
506
507 bool APDULogging = arg_get_lit(1);
6b882a39 508 bool verbose = arg_get_lit(2);
39cc1c87
OM
509 bool paramsPlain = arg_get_lit(3);
510 uint8_t controlByte = 0x08;
511 if (arg_get_lit(5))
512 controlByte = 0x03;
513 if (arg_get_lit(6))
514 controlByte = 0x07;
515
516 char fname[250] = {0};
517 bool err;
518 root = OpenJson(7, fname, argtable, &err);
519 if(err)
520 return 1;
521 if (root) {
522 size_t jlen;
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;
6b882a39
OM
528 JsonLoadBufAsHex(root, "$.PublicKey", public_key, 65, &jlen);
529 public_key_loaded = (jlen > 0);
39cc1c87
OM
530 }
531
6b882a39 532 // public key
39cc1c87 533 CLIGetHexWithReturn(8, hdata, &hdatalen);
6b882a39
OM
534 if (hdatalen && hdatalen != 130) {
535 PrintAndLog("ERROR: public key length must be 65 bytes only.");
536 return 1;
537 }
538 if (hdatalen) {
539 memmove(public_key, hdata, hdatalen);
540 public_key_loaded = true;
541 }
542
543 CLIGetHexWithReturn(9, hdata, &hdatalen);
39cc1c87
OM
544 if (hdatalen > 255) {
545 PrintAndLog("ERROR: application parameter length must be less than 255.");
546 return 1;
547 }
548 if (hdatalen) {
549 keyHandleLen = hdatalen;
550 data[64] = keyHandleLen;
551 memmove(&data[65], hdata, keyHandleLen);
552 }
553
554 if (paramsPlain) {
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);
559 return 1;
560 }
561 } else {
6b882a39 562 CLIGetHexWithReturn(10, hdata, &hdatalen);
39cc1c87
OM
563 if (hdatalen && hdatalen != 32) {
564 PrintAndLog("ERROR: challenge parameter length must be 32 bytes only.");
565 return 1;
566 }
567 }
568 if (hdatalen)
569 memmove(data, hdata, 32);
570
571 if (paramsPlain) {
572 memset(hdata, 0x00, 32);
6b882a39 573 CLIGetStrWithReturn(11, hdata, &hdatalen);
39cc1c87
OM
574 if (hdatalen && hdatalen > 16) {
575 PrintAndLog("ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", hdatalen);
576 return 1;
577 }
578 } else {
579 CLIGetHexWithReturn(10, hdata, &hdatalen);
580 if (hdatalen && hdatalen != 32) {
581 PrintAndLog("ERROR: application parameter length must be 32 bytes only.");
582 return 1;
583 }
584 }
585 if (hdatalen)
586 memmove(&data[32], hdata, 32);
587
588 CLIParserFree();
589
590 SetAPDULogging(APDULogging);
591
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
596 // key handle [N]
597
598 uint8_t datalen = 32 + 32 + 1 + keyHandleLen;
599
600 uint8_t buf[2048] = {0};
601 size_t len = 0;
602 uint16_t sw = 0;
603
604 DropField();
605 int res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw);
606
607 if (res) {
608 PrintAndLog("Can't select authenticator. res=%x. Exit...", res);
609 DropField();
610 return res;
611 }
612
613 if (sw != 0x9000) {
614 PrintAndLog("Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
615 DropField();
616 return 2;
617 }
618
619 res = FIDOAuthentication(data, datalen, controlByte, buf, sizeof(buf), &len, &sw);
620 DropField();
621 if (res) {
622 PrintAndLog("Can't execute authentication command. res=%x. Exit...", res);
623 return res;
624 }
625
626 if (sw != 0x9000) {
627 PrintAndLog("ERROR execute authentication command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
628 return 3;
629 }
630
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));
636
6b882a39
OM
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);
641 if (!res) {
642 if (verbose) {
643 PrintAndLog(" r: %s", sprint_hex(rval, 32));
644 PrintAndLog(" s: %s", sprint_hex(sval, 32));
645 }
646 if (public_key_loaded) {
647 uint8_t xbuf[4096] = {0};
648 size_t xbuflen = 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
654 NULL, 0);
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);
657 if (res) {
658 if (res == -0x4e00) {
659 PrintAndLog("Signature is NOT VALID.");
660 } else {
661 PrintAndLog("Other signature check error: %x %s", (res<0)?-res:res, ecdsa_get_error(res));
662 }
663 } else {
664 PrintAndLog("Signature is OK.");
665 }
666 } else {
667 PrintAndLog("No public key provided. can't check signature.");
668 }
669 } else {
670 PrintAndLog("Invalid signature. res=%d.", res);
671 }
672
39cc1c87
OM
673 if (root) {
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);
679
680 res = json_dump_file(root, fname, JSON_INDENT(2));
681 if (res) {
682 PrintAndLog("ERROR: can't save the file: %s", fname);
683 return 200;
684 }
685 PrintAndLog("File `%s` saved.", fname);
686
687 // free json object
688 json_decref(root);
689 }
690 return 0;
691};
692
693static command_t CommandTable[] =
694{
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}
700};
701
702int CmdHFFido(const char *Cmd) {
703 (void)WaitForResponseTimeout(CMD_ACK,NULL,100);
704 CmdsParse(CommandTable, Cmd);
705 return 0;
706}
707
708int CmdHelp(const char *Cmd) {
709 CmdsHelp(CommandTable);
710 return 0;
711}
Impressum, Datenschutz