mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-14 02:27:26 -07:00
refactor fido2 commands to use load and save fcts from fileutils.c. They will now load from /client/resources and save a new file in working dir
This commit is contained in:
parent
25cdc321cd
commit
cbf045dddb
4 changed files with 192 additions and 245 deletions
|
@ -35,6 +35,10 @@
|
||||||
#include "cmdhf14a.h"
|
#include "cmdhf14a.h"
|
||||||
#include "cmdtrace.h"
|
#include "cmdtrace.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "fileutils.h" // laodFileJSONroot
|
||||||
|
|
||||||
|
#define DEF_FIDO_SIZE 2048
|
||||||
|
#define DEF_FIDO_PARAM_FILE "fido2_defparams.json"
|
||||||
|
|
||||||
static int CmdHelp(const char *Cmd);
|
static int CmdHelp(const char *Cmd);
|
||||||
|
|
||||||
|
@ -118,60 +122,13 @@ static int CmdHFFidoInfo(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static json_t *OpenJson(CLIParserContext *ctx, int paramnum, char *fname, void *argtable[], bool *err) {
|
|
||||||
json_t *root = NULL;
|
|
||||||
json_error_t error;
|
|
||||||
*err = false;
|
|
||||||
|
|
||||||
uint8_t jsonname[FILE_PATH_SIZE] = {0};
|
|
||||||
char *cjsonname = (char *)jsonname;
|
|
||||||
int jsonnamelen = 0;
|
|
||||||
|
|
||||||
// CLIGetStrWithReturn(ctx, paramnum, jsonname, &jsonnamelen);
|
|
||||||
if (CLIParamStrToBuf(arg_get_str(ctx, paramnum), jsonname, sizeof(jsonname), &jsonnamelen)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// current path + file name
|
|
||||||
if (!strstr(cjsonname, ".json"))
|
|
||||||
strcat(cjsonname, ".json");
|
|
||||||
|
|
||||||
if (jsonnamelen) {
|
|
||||||
strcpy(fname, get_my_executable_directory());
|
|
||||||
strcat(fname, cjsonname);
|
|
||||||
if (access(fname, F_OK) != -1) {
|
|
||||||
root = json_load_file(fname, 0, &error);
|
|
||||||
if (!root) {
|
|
||||||
PrintAndLogEx(ERR, "ERROR: json error on line %d: %s", error.line, error.text);
|
|
||||||
*err = true;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!json_is_object(root)) {
|
|
||||||
PrintAndLogEx(ERR, "ERROR: Invalid json format. root must be an object.");
|
|
||||||
json_decref(root);
|
|
||||||
*err = true;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
root = json_object();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int CmdHFFidoRegister(const char *cmd) {
|
static int CmdHFFidoRegister(const char *cmd) {
|
||||||
uint8_t data[64] = {0};
|
|
||||||
int chlen = 0;
|
|
||||||
uint8_t cdata[250] = {0};
|
|
||||||
int applen = 0;
|
|
||||||
uint8_t adata[250] = {0};
|
|
||||||
|
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf fido reg",
|
CLIParserInit(&ctx, "hf fido reg",
|
||||||
"Initiate a U2F token registration. Needs two 32-byte hash numbers.\n"
|
"Initiate a U2F token registration. Needs two 32-byte hash numbers.\n"
|
||||||
"challenge parameter (32b) and application parameter (32b).",
|
"challenge parameter (32b) and application parameter (32b).\n"
|
||||||
|
"The output template filename is `hf-fido2-params.json`\n"
|
||||||
|
"\n",
|
||||||
"hf fido reg -> execute command with 2 parameters, filled 0x00\n"
|
"hf fido reg -> execute command with 2 parameters, filled 0x00\n"
|
||||||
"hf fido reg -p s0 s1 -> execute command with plain parameters\n"
|
"hf fido reg -p s0 s1 -> execute command with plain parameters\n"
|
||||||
"hf fido reg --cp 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f --ap 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f\n"
|
"hf fido reg --cp 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f --ap 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f\n"
|
||||||
|
@ -179,11 +136,11 @@ static int CmdHFFidoRegister(const char *cmd) {
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_lit0("a", "apdu", "show APDU requests and responses"),
|
arg_lit0("a", "apdu", "show APDU requests and responses"),
|
||||||
arg_litn("v", "verbose", 0, 2, "show technical data. vv - show full certificates data"),
|
arg_litn("v", "verbose", 0, 2, "show technical data. vv - show full certificates data"),
|
||||||
arg_lit0("p", "plain", "send plain ASCII to challenge and application parameters instead of HEX"),
|
arg_lit0("p", "plain", "send plain ASCII to challenge and application parameters instead of HEX"),
|
||||||
arg_lit0("t", "tlv", "Show DER certificate contents in TLV representation"),
|
arg_lit0("t", "tlv", "Show DER certificate contents in TLV representation"),
|
||||||
arg_str0("j", "json", "fido.json", "JSON input / output file name for parameters."),
|
arg_str0("f", "file", "<fn>", "JSON input file name for parameters"),
|
||||||
arg_str0(NULL, "cp", "<hex/ascii>", "challenge parameter (32 bytes hex / 1..16 chars)"),
|
arg_str0(NULL, "cp", "<hex/ascii>", "challenge parameter (32 bytes hex / 1..16 chars)"),
|
||||||
arg_str0(NULL, "ap", "<hex/ascii>", "application parameter (32 bytes hex / 1..16 chars)"),
|
arg_str0(NULL, "ap", "<hex/ascii>", "application parameter (32 bytes hex / 1..16 chars)"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
|
@ -196,18 +153,38 @@ static int CmdHFFidoRegister(const char *cmd) {
|
||||||
bool paramsPlain = arg_get_lit(ctx, 3);
|
bool paramsPlain = arg_get_lit(ctx, 3);
|
||||||
bool showDERTLV = arg_get_lit(ctx, 4);
|
bool showDERTLV = arg_get_lit(ctx, 4);
|
||||||
|
|
||||||
char fname[FILE_PATH_SIZE] = {0};
|
|
||||||
bool err;
|
uint8_t data[64] = {0};
|
||||||
json_t *root = OpenJson(ctx, 5, fname, argtable, &err);
|
int chlen = 0;
|
||||||
if (err) {
|
uint8_t cdata[250] = {0};
|
||||||
|
int applen = 0;
|
||||||
|
uint8_t adata[250] = {0};
|
||||||
|
|
||||||
|
int fnlen = 0;
|
||||||
|
char filename[FILE_PATH_SIZE] = {0};
|
||||||
|
CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||||
|
|
||||||
|
// deafault name
|
||||||
|
if (fnlen == 0) {
|
||||||
|
strcat(filename, DEF_FIDO_PARAM_FILE);
|
||||||
|
fnlen = strlen(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
json_t *root = calloc(1, sizeof(json_t));
|
||||||
|
if (root == NULL) {
|
||||||
|
PrintAndLogEx(ERR, "error, cannot allocate memory ");
|
||||||
|
return PM3_EMALLOC;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = loadFileJSONroot(filename, root, verbose);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
if (root) {
|
|
||||||
size_t jlen;
|
size_t jlen = 0;
|
||||||
JsonLoadBufAsHex(root, "$.ChallengeParam", data, 32, &jlen);
|
JsonLoadBufAsHex(root, "$.ChallengeParam", data, 32, &jlen);
|
||||||
JsonLoadBufAsHex(root, "$.ApplicationParam", &data[32], 32, &jlen);
|
JsonLoadBufAsHex(root, "$.ApplicationParam", &data[32], 32, &jlen);
|
||||||
}
|
|
||||||
|
|
||||||
if (paramsPlain) {
|
if (paramsPlain) {
|
||||||
memset(cdata, 0x00, 32);
|
memset(cdata, 0x00, 32);
|
||||||
|
@ -264,7 +241,7 @@ static int CmdHFFidoRegister(const char *cmd) {
|
||||||
uint16_t sw = 0;
|
uint16_t sw = 0;
|
||||||
|
|
||||||
DropField();
|
DropField();
|
||||||
int res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw);
|
res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw);
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
PrintAndLogEx(ERR, "Can't select authenticator. res=%x. Exit...", res);
|
PrintAndLogEx(ERR, "Can't select authenticator. res=%x. Exit...", res);
|
||||||
|
@ -364,16 +341,16 @@ static int CmdHFFidoRegister(const char *cmd) {
|
||||||
res = ecdsa_signature_verify(MBEDTLS_ECP_DP_SECP256R1, public_key, xbuf, xbuflen, &buf[hashp], len - hashp, true);
|
res = ecdsa_signature_verify(MBEDTLS_ECP_DP_SECP256R1, public_key, xbuf, xbuflen, &buf[hashp], len - hashp, true);
|
||||||
if (res) {
|
if (res) {
|
||||||
if (res == MBEDTLS_ERR_ECP_VERIFY_FAILED) {
|
if (res == MBEDTLS_ERR_ECP_VERIFY_FAILED) {
|
||||||
PrintAndLogEx(WARNING, "Signature is" _RED_("NOT VALID"));
|
PrintAndLogEx(WARNING, "Signature is ( " _RED_("not valid") " )");
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "Other signature check error: %x %s", (res < 0) ? -res : res, ecdsa_get_error(res));
|
PrintAndLogEx(WARNING, "Other signature check error: %x %s", (res < 0) ? -res : res, ecdsa_get_error(res));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(SUCCESS, "Signature is" _GREEN_("OK"));
|
PrintAndLogEx(SUCCESS, "Signature is ( " _GREEN_("ok") " )");
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "Invalid signature. res = %d.", res);
|
PrintAndLogEx(WARNING, "Invalid signature. res = %d. ( " _RED_("fail") " )" , res);
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "\nauth command: ");
|
PrintAndLogEx(INFO, "\nauth command: ");
|
||||||
|
@ -391,12 +368,8 @@ static int CmdHFFidoRegister(const char *cmd) {
|
||||||
JsonSaveBufAsHexCompact(root, "KeyHandle", &buf[67], keyHandleLen);
|
JsonSaveBufAsHexCompact(root, "KeyHandle", &buf[67], keyHandleLen);
|
||||||
JsonSaveBufAsHexCompact(root, "DER", &buf[67 + keyHandleLen], derLen);
|
JsonSaveBufAsHexCompact(root, "DER", &buf[67 + keyHandleLen], derLen);
|
||||||
|
|
||||||
res = json_dump_file(root, fname, JSON_INDENT(2));
|
sprintf(filename, "hf-fido2-params");
|
||||||
if (res) {
|
res = saveFileJSONroot(filename, root, JSON_INDENT(2), verbose);
|
||||||
PrintAndLogEx(ERR, "ERROR: can't save the file: %s", fname);
|
|
||||||
return PM3_EFILE;
|
|
||||||
}
|
|
||||||
PrintAndLogEx(SUCCESS, "File " _YELLOW_("`%s`") " saved.", fname);
|
|
||||||
|
|
||||||
// free json object
|
// free json object
|
||||||
json_decref(root);
|
json_decref(root);
|
||||||
|
@ -405,17 +378,12 @@ static int CmdHFFidoRegister(const char *cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHFFidoAuthenticate(const char *cmd) {
|
static int CmdHFFidoAuthenticate(const char *cmd) {
|
||||||
uint8_t data[512] = {0};
|
|
||||||
uint8_t hdata[250] = {0};
|
|
||||||
bool public_key_loaded = false;
|
|
||||||
uint8_t public_key[65] = {0};
|
|
||||||
int hdatalen = 0;
|
|
||||||
uint8_t keyHandleLen = 0;
|
|
||||||
|
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf fido auth",
|
CLIParserInit(&ctx, "hf fido auth",
|
||||||
"Initiate a U2F token authentication. Needs key handle and two 32-byte hash numbers.\n"
|
"Initiate a U2F token authentication. Needs key handle and two 32-byte hash numbers.\n"
|
||||||
"key handle(var 0..255), challenge parameter (32b) and application parameter (32b)",
|
"key handle(var 0..255), challenge parameter (32b) and application parameter (32b)\n"
|
||||||
|
"The output template filename is `hf-fido2-params.json`\n"
|
||||||
|
"\n",
|
||||||
"hf fido auth --kh 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with 2 parameters, filled 0x00 and key handle\n"
|
"hf fido auth --kh 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with 2 parameters, filled 0x00 and key handle\n"
|
||||||
"hf fido auth \n"
|
"hf fido auth \n"
|
||||||
"--kh 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f\n"
|
"--kh 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f\n"
|
||||||
|
@ -430,11 +398,11 @@ static int CmdHFFidoAuthenticate(const char *cmd) {
|
||||||
arg_rem("default mode:", "dont-enforce-user-presence-and-sign"),
|
arg_rem("default mode:", "dont-enforce-user-presence-and-sign"),
|
||||||
arg_lit0("u", "user", "mode: enforce-user-presence-and-sign"),
|
arg_lit0("u", "user", "mode: enforce-user-presence-and-sign"),
|
||||||
arg_lit0("c", "check", "mode: check-only"),
|
arg_lit0("c", "check", "mode: check-only"),
|
||||||
arg_str0("j", "json", "fido.json", "JSON input / output file name for parameters."),
|
arg_str0("f", "file", "<fn>", "JSON input file name for parameters"),
|
||||||
arg_str0("k", "key", "<hex>", "public key to verify signature"),
|
arg_str0("k", "key", "<hex>", "public key to verify signature"),
|
||||||
arg_str0(NULL, "kh", "<hex>", "key handle (var 0..255b)"),
|
arg_str0(NULL, "kh", "<hex>", "key handle (var 0..255b)"),
|
||||||
arg_str0(NULL, "cp", "<hex/ascii>", "challenge parameter (32 bytes hex / 1..16 chars)"),
|
arg_str0(NULL, "cp", "<hex/ascii>", "challenge parameter (32 bytes hex / 1..16 chars)"),
|
||||||
arg_str0(NULL, "ap", "<hex/ascii>", "application parameter (32 bytes hex / 1..16 chars)"),
|
arg_str0(NULL, "ap", "<hex/ascii>", "application parameter (32 bytes hex / 1..16 chars)"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, cmd, argtable, true);
|
CLIExecWithReturn(ctx, cmd, argtable, true);
|
||||||
|
@ -442,30 +410,52 @@ static int CmdHFFidoAuthenticate(const char *cmd) {
|
||||||
bool APDULogging = arg_get_lit(ctx, 1);
|
bool APDULogging = arg_get_lit(ctx, 1);
|
||||||
bool verbose = arg_get_lit(ctx, 2);
|
bool verbose = arg_get_lit(ctx, 2);
|
||||||
bool paramsPlain = arg_get_lit(ctx, 3);
|
bool paramsPlain = arg_get_lit(ctx, 3);
|
||||||
|
|
||||||
uint8_t controlByte = 0x08;
|
uint8_t controlByte = 0x08;
|
||||||
if (arg_get_lit(ctx, 5))
|
if (arg_get_lit(ctx, 5))
|
||||||
controlByte = 0x03;
|
controlByte = 0x03;
|
||||||
|
|
||||||
if (arg_get_lit(ctx, 6))
|
if (arg_get_lit(ctx, 6))
|
||||||
controlByte = 0x07;
|
controlByte = 0x07;
|
||||||
|
|
||||||
char fname[250] = {0};
|
uint8_t data[512] = {0};
|
||||||
bool err;
|
uint8_t hdata[250] = {0};
|
||||||
json_t *root = OpenJson(ctx, 7, fname, argtable, &err);
|
bool public_key_loaded = false;
|
||||||
if (err) {
|
uint8_t public_key[65] = {0};
|
||||||
|
int hdatalen = 0;
|
||||||
|
uint8_t keyHandleLen = 0;
|
||||||
|
|
||||||
|
|
||||||
|
int fnlen = 0;
|
||||||
|
char filename[FILE_PATH_SIZE] = {0};
|
||||||
|
CLIParamStrToBuf(arg_get_str(ctx, 7), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||||
|
|
||||||
|
// deafault name
|
||||||
|
if (fnlen == 0) {
|
||||||
|
strcat(filename, DEF_FIDO_PARAM_FILE);
|
||||||
|
fnlen = strlen(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
json_t *root = calloc(1, sizeof(json_t));
|
||||||
|
if (root == NULL) {
|
||||||
|
PrintAndLogEx(ERR, "error, cannot allocate memory ");
|
||||||
|
return PM3_EMALLOC;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = loadFileJSONroot(filename, root, verbose);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root) {
|
size_t jlen = 0;
|
||||||
size_t jlen;
|
JsonLoadBufAsHex(root, "$.ChallengeParam", data, 32, &jlen);
|
||||||
JsonLoadBufAsHex(root, "$.ChallengeParam", data, 32, &jlen);
|
JsonLoadBufAsHex(root, "$.ApplicationParam", &data[32], 32, &jlen);
|
||||||
JsonLoadBufAsHex(root, "$.ApplicationParam", &data[32], 32, &jlen);
|
JsonLoadBufAsHex(root, "$.KeyHandle", &data[65], 512 - 67, &jlen);
|
||||||
JsonLoadBufAsHex(root, "$.KeyHandle", &data[65], 512 - 67, &jlen);
|
keyHandleLen = jlen & 0xff;
|
||||||
keyHandleLen = jlen & 0xff;
|
data[64] = keyHandleLen;
|
||||||
data[64] = keyHandleLen;
|
JsonLoadBufAsHex(root, "$.PublicKey", public_key, 65, &jlen);
|
||||||
JsonLoadBufAsHex(root, "$.PublicKey", public_key, 65, &jlen);
|
public_key_loaded = (jlen > 0);
|
||||||
public_key_loaded = (jlen > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// public key
|
// public key
|
||||||
CLIGetHexWithReturn(ctx, 8, hdata, &hdatalen);
|
CLIGetHexWithReturn(ctx, 8, hdata, &hdatalen);
|
||||||
|
@ -554,8 +544,7 @@ static int CmdHFFidoAuthenticate(const char *cmd) {
|
||||||
uint16_t sw = 0;
|
uint16_t sw = 0;
|
||||||
|
|
||||||
DropField();
|
DropField();
|
||||||
int res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw);
|
res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw);
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
PrintAndLogEx(ERR, "Can't select authenticator. res=%x. Exit...", res);
|
PrintAndLogEx(ERR, "Can't select authenticator. res=%x. Exit...", res);
|
||||||
DropField();
|
DropField();
|
||||||
|
@ -614,13 +603,13 @@ static int CmdHFFidoAuthenticate(const char *cmd) {
|
||||||
PrintAndLogEx(WARNING, "Other signature check error: %x %s", (res < 0) ? -res : res, ecdsa_get_error(res));
|
PrintAndLogEx(WARNING, "Other signature check error: %x %s", (res < 0) ? -res : res, ecdsa_get_error(res));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(SUCCESS, "Signature is" _GREEN_("OK"));
|
PrintAndLogEx(SUCCESS, "Signature is (" _GREEN_("ok") " )");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "No public key provided. can't check signature.");
|
PrintAndLogEx(WARNING, "No public key provided. can't check signature.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(ERR, "Invalid signature. res = %d.", res);
|
PrintAndLogEx(WARNING, "Invalid signature. res = %d. ( " _RED_("fail") " )" , res);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root) {
|
if (root) {
|
||||||
|
@ -630,63 +619,21 @@ static int CmdHFFidoAuthenticate(const char *cmd) {
|
||||||
JsonSaveBufAsHexCompact(root, "KeyHandle", &data[65], keyHandleLen);
|
JsonSaveBufAsHexCompact(root, "KeyHandle", &data[65], keyHandleLen);
|
||||||
JsonSaveInt(root, "Counter", cntr);
|
JsonSaveInt(root, "Counter", cntr);
|
||||||
|
|
||||||
res = json_dump_file(root, fname, JSON_INDENT(2));
|
sprintf(filename, "hf-fido2-params");
|
||||||
if (res) {
|
res = saveFileJSONroot(filename, root, JSON_INDENT(2), verbose);
|
||||||
PrintAndLogEx(ERR, "ERROR: can't save the file: %s", fname);
|
|
||||||
return PM3_EFILE;
|
|
||||||
}
|
|
||||||
PrintAndLogEx(SUCCESS, "File " _YELLOW_("`%s`") " saved.", fname);
|
|
||||||
|
|
||||||
// free json object
|
// free json object
|
||||||
json_decref(root);
|
json_decref(root);
|
||||||
}
|
}
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CheckSlash(char *fileName) {
|
|
||||||
if ((fileName[strlen(fileName) - 1] != '/') &&
|
|
||||||
(fileName[strlen(fileName) - 1] != '\\'))
|
|
||||||
strcat(fileName, "/");
|
|
||||||
}
|
|
||||||
|
|
||||||
//iceman, todo: use searchfile..
|
|
||||||
static int GetExistsFileNameJson(const char *prefixDir, const char *reqestedFileName, char *fileName) {
|
|
||||||
fileName[0] = 0x00;
|
|
||||||
strcpy(fileName, get_my_executable_directory());
|
|
||||||
CheckSlash(fileName);
|
|
||||||
|
|
||||||
strcat(fileName, prefixDir);
|
|
||||||
CheckSlash(fileName);
|
|
||||||
|
|
||||||
strcat(fileName, reqestedFileName);
|
|
||||||
if (!strstr(fileName, ".json"))
|
|
||||||
strcat(fileName, ".json");
|
|
||||||
|
|
||||||
if (access(fileName, F_OK) < 0) {
|
|
||||||
strcpy(fileName, get_my_executable_directory());
|
|
||||||
CheckSlash(fileName);
|
|
||||||
|
|
||||||
strcat(fileName, reqestedFileName);
|
|
||||||
if (!strstr(fileName, ".json"))
|
|
||||||
strcat(fileName, ".json");
|
|
||||||
|
|
||||||
if (access(fileName, F_OK) < 0) {
|
|
||||||
return PM3_EFILE; // file not found
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int CmdHFFido2MakeCredential(const char *cmd) {
|
static int CmdHFFido2MakeCredential(const char *cmd) {
|
||||||
json_error_t error;
|
|
||||||
char fname[FILE_PATH_SIZE] = {0};
|
|
||||||
|
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf fido make",
|
CLIParserInit(&ctx, "hf fido make",
|
||||||
"Execute a FIDO2 Make Credential command. Needs json file with parameters.\n"
|
"Execute a FIDO2 Make Credential command. Needs json file with parameters.\n"
|
||||||
"Sample file `fido2.json` in `client/resources/`.",
|
"Sample file `fido2_defparams.json` in `client/resources/`.",
|
||||||
"hf fido make -> default parameters file `fido2.json`\n"
|
"hf fido make --> use default parameters file `fido2_defparams.json`\n"
|
||||||
"hf fido make -f test.json -> use parameters file `text.json`"
|
"hf fido make -f test.json --> use parameters file `text.json`"
|
||||||
);
|
);
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
|
@ -695,7 +642,7 @@ static int CmdHFFido2MakeCredential(const char *cmd) {
|
||||||
arg_litn("v", "verbose", 0, 2, "show technical data. vv - show full certificates data"),
|
arg_litn("v", "verbose", 0, 2, "show technical data. vv - show full certificates data"),
|
||||||
arg_lit0("t", "tlv", "Show DER certificate contents in TLV representation"),
|
arg_lit0("t", "tlv", "Show DER certificate contents in TLV representation"),
|
||||||
arg_lit0("c", "cbor", "show CBOR decoded data"),
|
arg_lit0("c", "cbor", "show CBOR decoded data"),
|
||||||
arg_str0("f", "file", "<fn>", "parameter JSON file name. (def `fido2.json`)"),
|
arg_str0("f", "file", "<fn>", "parameter JSON file name"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, cmd, argtable, true);
|
CLIExecWithReturn(ctx, cmd, argtable, true);
|
||||||
|
@ -706,41 +653,37 @@ static int CmdHFFido2MakeCredential(const char *cmd) {
|
||||||
bool showDERTLV = arg_get_lit(ctx, 3);
|
bool showDERTLV = arg_get_lit(ctx, 3);
|
||||||
bool showCBOR = arg_get_lit(ctx, 4);
|
bool showCBOR = arg_get_lit(ctx, 4);
|
||||||
|
|
||||||
uint8_t jsonname[FILE_PATH_SIZE] = {0};
|
int fnlen = 0;
|
||||||
char *cjsonname = (char *)jsonname;
|
char filename[FILE_PATH_SIZE] = {0};
|
||||||
int jsonnamelen = 0;
|
CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||||
jsonnamelen = sizeof(jsonname);
|
|
||||||
CLIGetStrWithReturn(ctx, 5, jsonname, &jsonnamelen);
|
|
||||||
|
|
||||||
if (!jsonnamelen) {
|
|
||||||
strcat(cjsonname, "fido2");
|
|
||||||
jsonnamelen = strlen(cjsonname);
|
|
||||||
}
|
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
SetAPDULogging(APDULogging);
|
// deafault name
|
||||||
|
if (fnlen == 0) {
|
||||||
int res = GetExistsFileNameJson("fido", cjsonname, fname);
|
strcat(filename, DEF_FIDO_PARAM_FILE);
|
||||||
if (res != PM3_SUCCESS) {
|
fnlen = strlen(filename);
|
||||||
PrintAndLogEx(ERR, "ERROR: Can't found the json file.");
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
PrintAndLogEx(INFO, "fname: %s\n", fname);
|
|
||||||
json_t *root = json_load_file(fname, 0, &error);
|
json_t *root = calloc(1, sizeof(json_t));
|
||||||
if (!root) {
|
if (root == NULL) {
|
||||||
PrintAndLogEx(ERR, "ERROR: json error on line %d: %s", error.line, error.text);
|
PrintAndLogEx(ERR, "error, cannot allocate memory ");
|
||||||
|
return PM3_EMALLOC;
|
||||||
|
}
|
||||||
|
loadFileJSONroot(filename, root, verbose);
|
||||||
|
if (root == NULL) {
|
||||||
return PM3_EFILE;
|
return PM3_EFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t data[2048] = {0};
|
SetAPDULogging(APDULogging);
|
||||||
|
|
||||||
|
uint8_t data[DEF_FIDO_SIZE] = {0};
|
||||||
size_t datalen = 0;
|
size_t datalen = 0;
|
||||||
uint8_t buf[2048] = {0};
|
uint8_t buf[DEF_FIDO_SIZE] = {0};
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
uint16_t sw = 0;
|
uint16_t sw = 0;
|
||||||
|
|
||||||
DropField();
|
DropField();
|
||||||
res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw);
|
int res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw);
|
||||||
if (res) {
|
if (res) {
|
||||||
PrintAndLogEx(ERR, "Can't select authenticator. res=%x. Exit...", res);
|
PrintAndLogEx(ERR, "Can't select authenticator. res=%x. Exit...", res);
|
||||||
DropField();
|
DropField();
|
||||||
|
@ -767,7 +710,7 @@ static int CmdHFFido2MakeCredential(const char *cmd) {
|
||||||
res = FIDO2MakeCredential(data, datalen, buf, sizeof(buf), &len, &sw);
|
res = FIDO2MakeCredential(data, datalen, buf, sizeof(buf), &len, &sw);
|
||||||
DropField();
|
DropField();
|
||||||
if (res) {
|
if (res) {
|
||||||
PrintAndLogEx(ERR, "Can't execute make credential command. res=%x. Exit...", res);
|
PrintAndLogEx(ERR, "Can't execute make credential command. res=%x. exit...", res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -781,7 +724,7 @@ static int CmdHFFido2MakeCredential(const char *cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "MakeCredential result (%zu b) OK.", len);
|
PrintAndLogEx(SUCCESS, "MakeCredential result %zu b ( ok )", len);
|
||||||
if (showCBOR) {
|
if (showCBOR) {
|
||||||
PrintAndLogEx(SUCCESS, "CBOR make credential response:");
|
PrintAndLogEx(SUCCESS, "CBOR make credential response:");
|
||||||
PrintAndLogEx(INFO, "---------------- " _CYAN_("CBOR") " ------------------");
|
PrintAndLogEx(INFO, "---------------- " _CYAN_("CBOR") " ------------------");
|
||||||
|
@ -792,39 +735,30 @@ static int CmdHFFido2MakeCredential(const char *cmd) {
|
||||||
// parse returned cbor
|
// parse returned cbor
|
||||||
FIDO2MakeCredentionalParseRes(root, &buf[1], len - 1, verbose, verbose2, showCBOR, showDERTLV);
|
FIDO2MakeCredentionalParseRes(root, &buf[1], len - 1, verbose, verbose2, showCBOR, showDERTLV);
|
||||||
|
|
||||||
if (root) {
|
// new file name..
|
||||||
res = json_dump_file(root, fname, JSON_INDENT(2));
|
sprintf(filename, "hf-fido2");
|
||||||
if (res) {
|
res = saveFileJSONroot(filename, root, JSON_INDENT(2), verbose);
|
||||||
PrintAndLogEx(ERR, "ERROR: can't save the file: %s", fname);
|
|
||||||
return PM3_EFILE;
|
|
||||||
}
|
|
||||||
PrintAndLogEx(SUCCESS, "File " _YELLOW_("`%s`") " saved.", fname);
|
|
||||||
}
|
|
||||||
|
|
||||||
json_decref(root);
|
json_decref(root);
|
||||||
return PM3_SUCCESS;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHFFido2GetAssertion(const char *cmd) {
|
static int CmdHFFido2GetAssertion(const char *cmd) {
|
||||||
json_error_t error;
|
|
||||||
char fname[FILE_PATH_SIZE] = {0};
|
|
||||||
|
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf fido assert",
|
CLIParserInit(&ctx, "hf fido assert",
|
||||||
"Execute a FIDO2 Get Assertion command. Needs json file with parameters.\n"
|
"Execute a FIDO2 Get Assertion command. Needs json file with parameters.\n"
|
||||||
"Sample file `fido2.json` in `client/resources/`.\n"
|
"Sample file `fido2_defparams.json` in `client/resources/`.\n"
|
||||||
"- Needs if `rk` option is `false` (authenticator doesn't store credential to its memory)"
|
"- Needs if `rk` option is `false` (authenticator doesn't store credential to its memory)"
|
||||||
,
|
,
|
||||||
"hf fido assert -> default parameters file `fido2.json`\n"
|
"hf fido assert --> default parameters file `fido2_defparams.json`\n"
|
||||||
"hf fido assert -f test.json -l -> use parameters file `text.json` and add to request CredentialId");
|
"hf fido assert -f test.json -l --> use parameters file `text.json` and add to request CredentialId");
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_lit0("a", "apdu", "show APDU reqests and responses"),
|
arg_lit0("a", "apdu", "show APDU reqests and responses"),
|
||||||
arg_litn("v", "verbose", 0, 2, "show technical data. vv - show full certificates data"),
|
arg_litn("v", "verbose", 0, 2, "show technical data. vv - show full certificates data"),
|
||||||
arg_lit0("c", "cbor", "show CBOR decoded data"),
|
arg_lit0("c", "cbor", "show CBOR decoded data"),
|
||||||
arg_lit0("l", "list", "add CredentialId from json to allowList."),
|
arg_lit0("l", "list", "add CredentialId from json to allowList"),
|
||||||
arg_str0("f", "file", "<fn>", "parameter JSON file name. (def `fido2.json`)"),
|
arg_str0("f", "file", "<fn>", "parameter JSON file name"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, cmd, argtable, true);
|
CLIExecWithReturn(ctx, cmd, argtable, true);
|
||||||
|
@ -835,40 +769,33 @@ static int CmdHFFido2GetAssertion(const char *cmd) {
|
||||||
bool showCBOR = arg_get_lit(ctx, 3);
|
bool showCBOR = arg_get_lit(ctx, 3);
|
||||||
bool createAllowList = arg_get_lit(ctx, 4);
|
bool createAllowList = arg_get_lit(ctx, 4);
|
||||||
|
|
||||||
uint8_t jsonname[FILE_PATH_SIZE] = {0};
|
int fnlen = 0;
|
||||||
char *cjsonname = (char *)jsonname;
|
char filename[FILE_PATH_SIZE] = {0};
|
||||||
int jsonnamelen = sizeof(jsonname);
|
CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||||
CLIGetStrWithReturn(ctx, 5, jsonname, &jsonnamelen);
|
|
||||||
|
|
||||||
if (!jsonnamelen) {
|
|
||||||
strcat(cjsonname, "fido2");
|
|
||||||
jsonnamelen = strlen(cjsonname);
|
|
||||||
}
|
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
SetAPDULogging(APDULogging);
|
// deafault name
|
||||||
|
if (fnlen == 0) {
|
||||||
int res = GetExistsFileNameJson("fido", cjsonname, fname);
|
strcat(filename, DEF_FIDO_PARAM_FILE);
|
||||||
if (res != PM3_SUCCESS) {
|
fnlen = strlen(filename);
|
||||||
PrintAndLogEx(ERR, "ERROR: Can't found the json file.");
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
PrintAndLogEx(INFO, "fname: %s\n", fname);
|
|
||||||
json_t *root = json_load_file(fname, 0, &error);
|
json_t *root = NULL;
|
||||||
if (!root) {
|
loadFileJSONroot(filename, root, verbose);
|
||||||
PrintAndLogEx(ERR, "ERROR: json error on line %d: %s", error.line, error.text);
|
if (root == NULL) {
|
||||||
return PM3_EFILE;
|
return PM3_EFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t data[2048] = {0};
|
SetAPDULogging(APDULogging);
|
||||||
|
|
||||||
|
uint8_t data[DEF_FIDO_SIZE] = {0};
|
||||||
size_t datalen = 0;
|
size_t datalen = 0;
|
||||||
uint8_t buf[2048] = {0};
|
uint8_t buf[DEF_FIDO_SIZE] = {0};
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
uint16_t sw = 0;
|
uint16_t sw = 0;
|
||||||
|
|
||||||
DropField();
|
DropField();
|
||||||
res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw);
|
int res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw);
|
||||||
if (res) {
|
if (res) {
|
||||||
PrintAndLogEx(ERR, "Can't select authenticator. res=%x. exiting...", res);
|
PrintAndLogEx(ERR, "Can't select authenticator. res=%x. exiting...", res);
|
||||||
DropField();
|
DropField();
|
||||||
|
@ -920,27 +847,21 @@ static int CmdHFFido2GetAssertion(const char *cmd) {
|
||||||
// parse returned cbor
|
// parse returned cbor
|
||||||
FIDO2GetAssertionParseRes(root, &buf[1], len - 1, verbose, verbose2, showCBOR);
|
FIDO2GetAssertionParseRes(root, &buf[1], len - 1, verbose, verbose2, showCBOR);
|
||||||
|
|
||||||
if (root) {
|
// new file name..
|
||||||
res = json_dump_file(root, fname, JSON_INDENT(2));
|
sprintf(filename, "hf-fido2");
|
||||||
if (res) {
|
res = saveFileJSONroot(filename, root, JSON_INDENT(2), verbose);
|
||||||
PrintAndLogEx(ERR, "ERROR: can't save the file: %s", fname);
|
|
||||||
return PM3_EFILE;
|
|
||||||
}
|
|
||||||
PrintAndLogEx(SUCCESS, "File " _YELLOW_("`%s`") " saved.", fname);
|
|
||||||
}
|
|
||||||
|
|
||||||
json_decref(root);
|
json_decref(root);
|
||||||
return PM3_SUCCESS;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static command_t CommandTable[] = {
|
static command_t CommandTable[] = {
|
||||||
{"help", CmdHelp, AlwaysAvailable, "This help."},
|
{"help", CmdHelp, AlwaysAvailable, "This help."},
|
||||||
{"list", CmdHFFidoList, AlwaysAvailable, "List ISO 14443A history"},
|
{"list", CmdHFFidoList, AlwaysAvailable, "List ISO 14443A history"},
|
||||||
{"info", CmdHFFidoInfo, IfPm3Iso14443a, "Info about FIDO tag."},
|
{"info", CmdHFFidoInfo, IfPm3Iso14443a, "Info about FIDO tag."},
|
||||||
{"reg", CmdHFFidoRegister, IfPm3Iso14443a, "FIDO U2F Registration Message."},
|
{"reg", CmdHFFidoRegister, IfPm3Iso14443a, "FIDO U2F Registration Message."},
|
||||||
{"auth", CmdHFFidoAuthenticate, IfPm3Iso14443a, "FIDO U2F Authentication Message."},
|
{"auth", CmdHFFidoAuthenticate, IfPm3Iso14443a, "FIDO U2F Authentication Message."},
|
||||||
{"make", CmdHFFido2MakeCredential, IfPm3Iso14443a, "FIDO2 MakeCredential command."},
|
{"make", CmdHFFido2MakeCredential, IfPm3Iso14443a, "FIDO2 MakeCredential command."},
|
||||||
{"assert", CmdHFFido2GetAssertion, IfPm3Iso14443a, "FIDO2 GetAssertion command."},
|
{"assert", CmdHFFido2GetAssertion, IfPm3Iso14443a, "FIDO2 GetAssertion command."},
|
||||||
{NULL, NULL, 0, NULL}
|
{NULL, NULL, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -254,7 +254,7 @@ int FIDOCheckDERAndGetKey(uint8_t *der, size_t derLen, bool verbose, uint8_t *pu
|
||||||
if (res) {
|
if (res) {
|
||||||
PrintAndLogEx(ERR, "ERROR: DER verify returned 0x%x - %s\n", (res < 0) ? -res : res, ecdsa_get_error(res));
|
PrintAndLogEx(ERR, "ERROR: DER verify returned 0x%x - %s\n", (res < 0) ? -res : res, ecdsa_get_error(res));
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(SUCCESS, "Certificate OK.\n");
|
PrintAndLogEx(SUCCESS, "Certificate ( " _GREEN_("ok") " )\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
|
@ -388,13 +388,13 @@ static int FIDO2CheckSignature(json_t *root, uint8_t *publickey, uint8_t *sign,
|
||||||
res = ecdsa_signature_verify(MBEDTLS_ECP_DP_SECP256R1, publickey, xbuf, xbuflen, sign, signLen, true);
|
res = ecdsa_signature_verify(MBEDTLS_ECP_DP_SECP256R1, publickey, xbuf, xbuflen, sign, signLen, true);
|
||||||
if (res) {
|
if (res) {
|
||||||
if (res == MBEDTLS_ERR_ECP_VERIFY_FAILED) {
|
if (res == MBEDTLS_ERR_ECP_VERIFY_FAILED) {
|
||||||
PrintAndLogEx(WARNING, "Signature is " _RED_("NOT VALID"));
|
PrintAndLogEx(WARNING, "Signature is ( " _RED_("not valid") " )");
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "Other signature check error: %x %s", (res < 0) ? -res : res, ecdsa_get_error(res));
|
PrintAndLogEx(WARNING, "Other signature check error: %x %s", (res < 0) ? -res : res, ecdsa_get_error(res));
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(SUCCESS, "Signature is OK.");
|
PrintAndLogEx(SUCCESS, "Signature is ( " _GREEN_("ok") " )");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(ERR, "Invalid signature. res = %d.", res);
|
PrintAndLogEx(ERR, "Invalid signature. res = %d.", res);
|
||||||
|
@ -444,9 +444,9 @@ int FIDO2MakeCredentionalParseRes(json_t *root, uint8_t *data, size_t dataLen, b
|
||||||
|
|
||||||
// check RP ID Hash
|
// check RP ID Hash
|
||||||
if (CheckrpIdHash(root, ubuf)) {
|
if (CheckrpIdHash(root, ubuf)) {
|
||||||
PrintAndLogEx(SUCCESS, "rpIdHash OK.");
|
PrintAndLogEx(SUCCESS, "rpIdHash ( " _GREEN_("ok")" )");
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(ERR, "rpIdHash ERROR!");
|
PrintAndLogEx(ERR, "rpIdHash " _RED_("ERROR!!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Flags 0x%02x:", ubuf[32]);
|
PrintAndLogEx(INFO, "Flags 0x%02x:", ubuf[32]);
|
||||||
|
@ -704,9 +704,9 @@ int FIDO2GetAssertionParseRes(json_t *root, uint8_t *data, size_t dataLen, bool
|
||||||
|
|
||||||
// check RP ID Hash
|
// check RP ID Hash
|
||||||
if (CheckrpIdHash(root, ubuf)) {
|
if (CheckrpIdHash(root, ubuf)) {
|
||||||
PrintAndLogEx(SUCCESS, "rpIdHash OK.");
|
PrintAndLogEx(SUCCESS, "rpIdHash ( " _GREEN_("ok")" )");
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(ERR, "rpIdHash ERROR!");
|
PrintAndLogEx(ERR, "rpIdHash " _RED_("ERROR!!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Flags 0x%02x:", ubuf[32]);
|
PrintAndLogEx(INFO, "Flags 0x%02x:", ubuf[32]);
|
||||||
|
@ -760,7 +760,7 @@ int FIDO2GetAssertionParseRes(json_t *root, uint8_t *data, size_t dataLen, bool
|
||||||
JsonLoadBufAsHex(root, "$.UserEntity.id", idbuf, sizeof(idbuf), &idbuflen);
|
JsonLoadBufAsHex(root, "$.UserEntity.id", idbuf, sizeof(idbuf), &idbuflen);
|
||||||
|
|
||||||
if (idbuflen == n && !memcmp(idbuf, cid, idbuflen)) {
|
if (idbuflen == n && !memcmp(idbuf, cid, idbuflen)) {
|
||||||
PrintAndLogEx(SUCCESS, "UserEntity id OK.");
|
PrintAndLogEx(SUCCESS, "UserEntity id ( " _GREEN_("ok") " )");
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(ERR, "ERROR: Wrong UserEntity id (from json: %s)", sprint_hex(idbuf, idbuflen));
|
PrintAndLogEx(ERR, "ERROR: Wrong UserEntity id (from json: %s)", sprint_hex(idbuf, idbuflen));
|
||||||
}
|
}
|
||||||
|
|
|
@ -639,6 +639,9 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case jsfFido: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
case jsfCustom: {
|
case jsfCustom: {
|
||||||
(*callback)(root);
|
(*callback)(root);
|
||||||
break;
|
break;
|
||||||
|
@ -663,6 +666,28 @@ out:
|
||||||
free(fileName);
|
free(fileName);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
int saveFileJSONroot(const char *preferredName, void *root, size_t flags, bool verbose) {
|
||||||
|
if (root == NULL)
|
||||||
|
return PM3_EINVARG;
|
||||||
|
|
||||||
|
char *filename = newfilenamemcopy(preferredName, ".json");
|
||||||
|
if (filename == NULL)
|
||||||
|
return PM3_EMALLOC;
|
||||||
|
|
||||||
|
int res = json_dump_file(root, filename, flags);
|
||||||
|
|
||||||
|
free(filename);
|
||||||
|
|
||||||
|
if ( res == 0 ) {
|
||||||
|
if (verbose) {
|
||||||
|
PrintAndLogEx(SUCCESS, "saved to json file " _YELLOW_("%s"), filename);
|
||||||
|
}
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(FAILED, "error: can't save the file: " _YELLOW_("%s"), filename);
|
||||||
|
}
|
||||||
|
return PM3_EFILE;
|
||||||
|
}
|
||||||
|
|
||||||
int saveFileWAVE(const char *preferredName, int *data, size_t datalen) {
|
int saveFileWAVE(const char *preferredName, int *data, size_t datalen) {
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,7 @@ typedef enum {
|
||||||
jsfEM4x05,
|
jsfEM4x05,
|
||||||
jsfEM4x69,
|
jsfEM4x69,
|
||||||
jsfEM4x50,
|
jsfEM4x50,
|
||||||
|
jsfFido,
|
||||||
} JSONFileType;
|
} JSONFileType;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -121,7 +122,7 @@ int saveFileEML(const char *preferredName, uint8_t *data, size_t datalen, size_t
|
||||||
*/
|
*/
|
||||||
int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, void (*callback)(json_t *));
|
int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, void (*callback)(json_t *));
|
||||||
int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, bool verbose, void (*callback)(json_t *));
|
int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, bool verbose, void (*callback)(json_t *));
|
||||||
|
int saveFileJSONroot(const char *preferredName, void *root, size_t flags, bool verbose);
|
||||||
/** STUB
|
/** STUB
|
||||||
* @brief Utility function to save WAVE data to a file. This method takes a preferred name, but if that
|
* @brief Utility function to save WAVE data to a file. This method takes a preferred name, but if that
|
||||||
* file already exists, it tries with another name until it finds something suitable.
|
* file already exists, it tries with another name until it finds something suitable.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue