Merge pull request #465 from merlokk/hf_info_aid_search

Hf info aid search
This commit is contained in:
Oleg Moiseenko 2019-11-05 02:07:02 +03:00 committed by GitHub
commit 7b650e98a0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 2449 additions and 17 deletions

View file

@ -186,6 +186,7 @@ CMDSRCS = crapto1/crapto1.c \
cmdanalyse.c \
cmdhf.c \
cmdhflist.c \
aidsearch.c \
cmdhf14a.c \
cmdhf14b.c \
cmdhf15.c \

180
client/aidsearch.c Normal file
View file

@ -0,0 +1,180 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2019 merlokk
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Proxmark3 RDV40 AID list library
//-----------------------------------------------------------------------------
#include "aidsearch.h"
#include <ctype.h>
#include <string.h>
#include "fileutils.h"
#include "pm3_cmd.h"
int openAIDFile(json_t **root, bool verbose) {
json_error_t error;
char *path;
int res = searchFile(&path, RESOURCES_SUBDIR, "aidlist", ".json", false);
if (res != PM3_SUCCESS) {
return PM3_EFILE;
}
int retval = PM3_SUCCESS;
*root = json_load_file(path, 0, &error);
if (!*root) {
PrintAndLogEx(ERR, "json (%s) error on line %d: %s", path, error.line, error.text);
retval = PM3_ESOFT;
goto out;
}
if (!json_is_array(*root)) {
PrintAndLogEx(ERR, "Invalid json (%s) format. root must be an array.", path);
retval = PM3_ESOFT;
goto out;
}
if (verbose) PrintAndLogEx(SUCCESS, "Loaded file (%s) OK. %d records.", path, json_array_size(*root));
out:
free(path);
return retval;
}
int closeAIDFile(json_t *root) {
json_decref(root);
return PM3_SUCCESS;
}
json_t *AIDSearchInit(bool verbose) {
json_t *root = NULL;
int res = openAIDFile(&root, verbose);
if (res != PM3_SUCCESS)
return NULL;
return root;
}
json_t *AIDSearchGetElm(json_t *root, int elmindx) {
json_t *data = json_array_get(root, elmindx);
if (!json_is_object(data)) {
PrintAndLogEx(ERR, "data [%d] is not an object\n", elmindx);
return NULL;
}
return data;
}
int AIDSearchFree(json_t *root) {
return closeAIDFile(root);
}
const char * jsonStrGet(json_t *data, char *name) {
json_t *jstr;
jstr = json_object_get(data, name);
if (jstr == NULL)
return NULL;
if (!json_is_string(jstr)) {
PrintAndLogEx(ERR, "`%s` is not a string", name);
return NULL;
}
const char *cstr = json_string_value(jstr);
if (strlen(cstr) == 0)
return NULL;
return cstr;
}
bool aidCompare(const char *aidlarge, const char *aidsmall) {
if (strcmp(aidlarge, aidsmall) == 0)
return true;
if (strlen(aidlarge) > strlen(aidsmall))
if (strncmp(aidlarge, aidsmall, strlen(aidsmall)) == 0)
return true;
return false;
}
bool AIDGetFromElm(json_t *data, uint8_t *aid, size_t aidmaxlen, int *aidlen) {
*aidlen = 0;
const char *hexaid = jsonStrGet(data, "AID");
if (hexaid == NULL || strlen(hexaid) == 0)
return false;
int res = param_gethex_to_eol(hexaid, 0, aid, aidmaxlen, aidlen);
if (res)
return false;
return true;
}
int PrintAIDDescription(json_t *xroot, char *aid, bool verbose) {
int retval = PM3_SUCCESS;
json_t *root = xroot;
if (root == NULL)
root = AIDSearchInit(verbose);
if (root == NULL)
goto out;
json_t *elm = NULL;
int maxaidlen = 0;
for (int elmindx = 0; elmindx < json_array_size(root); elmindx++) {
json_t *data = AIDSearchGetElm(root, elmindx);
if (data == NULL)
continue;
const char *dictaid = jsonStrGet(data, "AID");
if (aidCompare(aid, dictaid)) { // dictaid may be less length than requested aid
if (maxaidlen < strlen(dictaid) && strlen(dictaid) <= strlen(aid)) {
maxaidlen = strlen(dictaid);
elm = data;
}
}
}
if (elm == NULL)
goto out;
// print here
const char *vaid = jsonStrGet(elm, "AID");
const char *vendor = jsonStrGet(elm, "Vendor");
const char *name = jsonStrGet(elm, "Name");
const char *country = jsonStrGet(elm, "Country");
const char *description = jsonStrGet(elm, "Description");
const char *type = jsonStrGet(elm, "Type");
if (!verbose) {
PrintAndLogEx(SUCCESS, "AID %s | %s | %s", vaid, vendor, name);
} else {
PrintAndLogEx(SUCCESS, "Input AID: %s", aid);
if (aid)
PrintAndLogEx(SUCCESS, "Found AID: %s", vaid);
if (vendor)
PrintAndLogEx(SUCCESS, "Vendor: %s", vendor);
if (type)
PrintAndLogEx(SUCCESS, "Type: %s", type);
if (name)
PrintAndLogEx(SUCCESS, "Name: %s", name);
if (country)
PrintAndLogEx(SUCCESS, "Country: %s", country);
if (description)
PrintAndLogEx(SUCCESS, "Description: %s", description);
}
out:
if (xroot == NULL)
AIDSearchFree(root);
return retval;
}
int PrintAIDDescriptionBuf(json_t *root, uint8_t *aid, size_t aidlen, bool verbose) {
return PrintAIDDescription(root, sprint_hex_inrow(aid, aidlen), verbose);
}

28
client/aidsearch.h Normal file
View file

@ -0,0 +1,28 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2019 merlokk
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Proxmark3 RDV40 AID list library
//-----------------------------------------------------------------------------
#ifndef AIDSEARCH_H__
#define AIDSEARCH_H__
#include "common.h"
#include <stdint.h>
#include <stdbool.h>
#include <jansson.h>
int PrintAIDDescription(json_t *root, char *aid, bool verbose);
int PrintAIDDescriptionBuf(json_t *root, uint8_t *aid, size_t aidlen, bool verbose);
json_t *AIDSearchInit(bool verbose);
json_t *AIDSearchGetElm(json_t *root, int elmindx);
bool AIDGetFromElm(json_t *data, uint8_t *aid, size_t aidmaxlen, int *aidlen);
int AIDSearchFree();
#endif

View file

@ -91,7 +91,7 @@ int CmdHFSearch(const char *Cmd) {
PROMPT_CLEARLINE;
PrintAndLogEx(INPLACE, "Searching for ISO14443-A tag...");
if (IfPm3Iso14443a()) {
if (infoHF14A(false, false) > 0) {
if (infoHF14A(false, false, false) > 0) {
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO14443-A tag") " found\n");
return PM3_SUCCESS;
}

View file

@ -26,6 +26,7 @@
#include "ui.h"
#include "crc16.h"
#include "util_posix.h" // msclock
#include "aidsearch.h"
bool APDUInFramingEnable = true;
@ -226,13 +227,6 @@ static int usage_hf_14a_reader(void) {
PrintAndLogEx(NORMAL, " 3 ISO14443-3 select only (skip RATS)");
return 0;
}
static int usage_hf_14a_info(void) {
PrintAndLogEx(NORMAL, "This command makes more extensive tests against a ISO14443a tag in order to collect information");
PrintAndLogEx(NORMAL, "Usage: hf 14a info [h|s]");
PrintAndLogEx(NORMAL, " s silent (no messages)");
PrintAndLogEx(NORMAL, " n test for nack bug");
return 0;
}
static int CmdHF14AList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
@ -367,12 +361,30 @@ static int CmdHF14AReader(const char *Cmd) {
}
static int CmdHF14AInfo(const char *Cmd) {
bool verbose = false;
bool do_nack_test = false;
bool do_aid_search = false;
if (Cmd[0] == 'h' || Cmd[0] == 'H') return usage_hf_14a_info();
CLIParserInit("hf 14a info",
"This command makes more extensive tests against a ISO14443a tag in order to collect information",
"Sample:\n\thf 14a info -nsv - shows full information about the card\n");
bool verbose = !(Cmd[0] == 's' || Cmd[0] == 'S');
bool do_nack_test = (Cmd[0] == 'n' || Cmd[0] == 'N');
infoHF14A(verbose, do_nack_test);
void *argtable[] = {
arg_param_begin,
arg_lit0("vV", "verbose", "adds some information to results"),
arg_lit0("nN", "naktest", "test for nack bug"),
arg_lit0("sS", "aidsearch", "checks if AIDs from aidlist.json is present on the card and prints information about found AIDs"),
arg_param_end
};
CLIExecWithReturn(Cmd, argtable, true);
verbose = arg_get_lit(1);
do_nack_test = arg_get_lit(2);
do_aid_search = arg_get_lit(3);
CLIParserFree();
infoHF14A(verbose, do_nack_test, do_aid_search);
return 0;
}
@ -1225,7 +1237,7 @@ int CmdHF14A(const char *Cmd) {
return CmdsParse(CommandTable, Cmd);
}
int infoHF14A(bool verbose, bool do_nack_test) {
int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
clearCommandBuffer();
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0);
PacketResponseNG resp;
@ -1493,6 +1505,72 @@ int infoHF14A(bool verbose, bool do_nack_test) {
}
}
}
if (do_aid_search) {
int elmindx = 0;
json_t *root = AIDSearchInit(verbose);
if (root != NULL) {
bool ActivateField = true;
for (elmindx = 0; elmindx < json_array_size(root); elmindx++) {
json_t *data = AIDSearchGetElm(root, elmindx);
uint8_t vaid[200] = {0};
int vaidlen = 0;
if (!AIDGetFromElm(data, vaid, sizeof(vaid), &vaidlen) || !vaidlen)
continue;
uint16_t sw = 0;
uint8_t result[1024] = {0};
size_t resultlen = 0;
int res = EMVSelect(ECC_CONTACTLESS, ActivateField, true, vaid, vaidlen, result, sizeof(result), &resultlen, &sw, NULL);
ActivateField = false;
if (res)
continue;
uint8_t dfname[200] = {0};
size_t dfnamelen = 0;
if (resultlen > 3) {
struct tlvdb *tlv = tlvdb_parse_multi(result, resultlen);
if (tlv) {
// 0x84 Dedicated File (DF) Name
const struct tlv *dfnametlv = tlvdb_get_tlv(tlvdb_find_full(tlv, 0x84));
if (dfnametlv) {
dfnamelen = dfnametlv->len;
memcpy(dfname, dfnametlv->value, dfnamelen);
}
tlvdb_free(tlv);
}
}
if (sw == 0x9000 || sw == 0x6283 || sw == 0x6285) {
if (sw == 0x9000) {
if (verbose) PrintAndLogEx(NORMAL, "------------- Application OK -----------");
} else {
if (verbose) PrintAndLogEx(NORMAL, "----------- Application blocked --------");
}
PrintAIDDescriptionBuf(root, vaid, vaidlen, verbose);
if (dfnamelen) {
if (dfnamelen == vaidlen) {
if (memcmp(dfname, vaid, vaidlen) == 0) {
if (verbose) PrintAndLogEx(INFO, "(DF) Name found and equal to AID");
} else {
PrintAndLogEx(INFO, "(DF) Name not equal to AID: %s :", sprint_hex(dfname, dfnamelen));
PrintAIDDescriptionBuf(root, dfname, dfnamelen, verbose);
}
} else {
PrintAndLogEx(INFO, "(DF) Name not equal to AID: %s :", sprint_hex(dfname, dfnamelen));
PrintAIDDescriptionBuf(root, dfname, dfnamelen, verbose);
}
} else {
if (verbose) PrintAndLogEx(INFO, "(DF) Name not found");
}
}
}
DropField();
}
}
} else {
PrintAndLogEx(INFO, "proprietary non iso14443-4 card found, RATS not supported");
}

View file

@ -26,7 +26,7 @@ int CmdHF14A(const char *Cmd);
int CmdHF14ASniff(const char *Cmd); // used by hf topaz sniff
int CmdHF14ASim(const char *Cmd); // used by hf mfu sim
int infoHF14A(bool verbose, bool do_nack_test);
int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search);
const char *getTagInfo(uint8_t uid);
int Hf14443_4aGetCardData(iso14a_card_select_t *card);
int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);

View file

@ -47,7 +47,7 @@ static int CmdHFFidoInfo(const char *cmd) {
PrintAndLogEx(WARNING, "WARNING: command doesn't have any parameters.\n");
// info about 14a part
infoHF14A(false, false);
infoHF14A(false, false, false);
// FIDO info
PrintAndLogEx(NORMAL, "--------------------------------------------");

View file

@ -36,7 +36,7 @@ static int CmdHFMFPInfo(const char *cmd) {
PrintAndLogEx(WARNING, "command don't have any parameters.\n");
// info about 14a part
infoHF14A(false, false);
infoHF14A(false, false, false);
// Mifare Plus info
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0);

File diff suppressed because one or more lines are too long