From f9a65505de7da07248d3e4f6eb1c74728c25dfea Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 21 Jan 2023 20:04:27 +0100 Subject: [PATCH] added tesla info command, with some of the data that is available. Needed to fix the apdu chaining and a sneaky bug in get_sw since the apdu response was larger then 256 --- client/CMakeLists.txt | 1 + client/Makefile | 1 + client/src/cmdhf.c | 4 +- client/src/cmdhf14a.c | 35 ++++--- client/src/cmdhf14a.h | 3 + client/src/cmdhftesla.c | 221 ++++++++++++++++++++++++++++++++++++++++ client/src/cmdhftesla.h | 26 +++++ common/commonutil.c | 4 +- common/commonutil.h | 2 +- 9 files changed, 281 insertions(+), 16 deletions(-) create mode 100644 client/src/cmdhftesla.c create mode 100644 client/src/cmdhftesla.h diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 5519b2e77..5bd3ebddd 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -293,6 +293,7 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/cmdhfseos.c ${PM3_ROOT}/client/src/cmdhfst.c ${PM3_ROOT}/client/src/cmdhfst25ta.c + ${PM3_ROOT}/client/src/cmdhftesla.c ${PM3_ROOT}/client/src/cmdhftexkom.c ${PM3_ROOT}/client/src/cmdhfthinfilm.c ${PM3_ROOT}/client/src/cmdhftopaz.c diff --git a/client/Makefile b/client/Makefile index 03f022297..b08eb0acb 100644 --- a/client/Makefile +++ b/client/Makefile @@ -583,6 +583,7 @@ SRCS = mifare/aiddesfire.c \ cmdhfseos.c \ cmdhfst.c \ cmdhfst25ta.c \ + cmdhftesla.c \ cmdhfthinfilm.c \ cmdhftopaz.c \ cmdhftexkom.c \ diff --git a/client/src/cmdhf.c b/client/src/cmdhf.c index 7bba6d41a..97f7df3c7 100644 --- a/client/src/cmdhf.c +++ b/client/src/cmdhf.c @@ -50,6 +50,7 @@ #include "cmdhftexkom.h" // Texkom #include "cmdhfxerox.h" // Xerox #include "cmdhffudan.h" // Fudan cards +#include "cmdhftesla.h" // Tesla #include "cmdtrace.h" // trace list #include "ui.h" #include "proxgui.h" @@ -493,9 +494,10 @@ static command_t CommandTable[] = { {"ntag424", CmdHF_ntag424, AlwaysAvailable, "{ NXP NTAG 4242 DNA RFIDs... }"}, {"seos", CmdHFSeos, AlwaysAvailable, "{ SEOS RFIDs... }"}, {"st25ta", CmdHFST25TA, AlwaysAvailable, "{ ST25TA RFIDs... }"}, + {"tesla", CmdHFTESLA, AlwaysAvailable, "{ TESLA Cards... }"}, + {"texkom", CmdHFTexkom, AlwaysAvailable, "{ Texkom RFIDs... }"}, {"thinfilm", CmdHFThinfilm, AlwaysAvailable, "{ Thinfilm RFIDs... }"}, {"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"}, - {"texkom", CmdHFTexkom, AlwaysAvailable, "{ Texkom RFIDs... }"}, {"xerox", CmdHFXerox, AlwaysAvailable, "{ Fuji/Xerox cartridge RFIDs... }"}, {"waveshare", CmdHFWaveshare, AlwaysAvailable, "{ Waveshare NFC ePaper... }"}, {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("General") " ---------------------"}, diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 0858150d0..d0ba31cd0 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -42,7 +42,13 @@ #include "desfire.h" // desfire enums #include "mifare/desfirecore.h" // desfire context -static bool APDUInFramingEnable = true; +static bool g_apdu_in_framing_enable = true; +bool Get_apdu_in_framing(void) { + return g_apdu_in_framing_enable; +} +void Set_apdu_in_framing(bool v) { + g_apdu_in_framing_enable = v; +} static int CmdHelp(const char *Cmd); static int waitCmd(bool i_select, uint32_t timeout, bool verbose); @@ -1050,7 +1056,7 @@ int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool lea int res; // 3 byte here - 1b framing header, 2b crc16 - if (APDUInFramingEnable && + if (g_apdu_in_framing_enable && ((gs_frame_len && (datainlen > gs_frame_len - 3)) || (datainlen > PM3_CMD_DATA_SIZE - 3))) { int clen = 0; @@ -1454,29 +1460,34 @@ static int CmdHF14AChaining(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf 14a chaining", "Enable/Disable ISO14443a input chaining. Maximum input length goes from ATS.", - "hf 14a chaining disable -> disable chaining\n" + "hf 14a chaining --off -> disable chaining\n" "hf 14a chaining -> show chaining enable/disable state\n"); void *argtable[] = { arg_param_begin, - arg_str0(NULL, NULL, "", NULL), + arg_lit0("1", "on", "enabled chaining"), + arg_lit0("0", "off", "disable chaining"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - struct arg_str *str = arg_get_str(ctx, 1); - int len = arg_get_str_len(ctx, 1); + bool on = arg_get_lit(ctx, 1); + bool off = arg_get_lit(ctx, 2); - if (len && (!strcmp(str->sval[0], "enable") || !strcmp(str->sval[0], "1"))) - APDUInFramingEnable = true; + if ((on + off) > 1) { + PrintAndLogEx(INFO, "Select only one option"); + return PM3_EINVARG; + } - if (len && (!strcmp(str->sval[0], "disable") || !strcmp(str->sval[0], "0"))) - APDUInFramingEnable = false; + if (on) + Set_apdu_in_framing(true); + + if (off) + Set_apdu_in_framing(false); CLIParserFree(ctx); - PrintAndLogEx(INFO, "\nISO 14443-4 input chaining %s.\n", APDUInFramingEnable ? "enabled" : "disabled"); - + PrintAndLogEx(INFO, "\nISO 14443-4 input chaining %s.\n", g_apdu_in_framing_enable ? "enabled" : "disabled"); return PM3_SUCCESS; } diff --git a/client/src/cmdhf14a.h b/client/src/cmdhf14a.h index 2ac2672a1..a811db66b 100644 --- a/client/src/cmdhf14a.h +++ b/client/src/cmdhf14a.h @@ -53,4 +53,7 @@ int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool lea int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool silentMode); int SelectCard14443A_4(bool disconnect, bool verbose, iso14a_card_select_t *card); + +bool Get_apdu_in_framing(void); +void Set_apdu_in_framing(bool v); #endif diff --git a/client/src/cmdhftesla.c b/client/src/cmdhftesla.c new file mode 100644 index 000000000..62e3bab18 --- /dev/null +++ b/client/src/cmdhftesla.c @@ -0,0 +1,221 @@ +//----------------------------------------------------------------------------- +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- +// High frequency ISO14443A / TESLA commands +//----------------------------------------------------------------------------- + +#include "cmdhftesla.h" +#include +#include +#include "cmdparser.h" // command_t +#include "comms.h" // clearCommandBuffer +#include "cmdtrace.h" +#include "cliparser.h" +#include "cmdhf14a.h" +#include "protocols.h" // definitions of ISO14A/7816 protocol +#include "iso7816/apduinfo.h" // GetAPDUCodeDescription +#include "commonutil.h" // get_sw +#include "protocols.h" // ISO7816 APDU return co-des +#include "ui.h" +#include "cmdhf14a.h" // apdu chaining + +#define TIMEOUT 2000 + +static int CmdHelp(const char *Cmd); + +/** + * 0x80 0x00 0x00 0x00 - get interface object + 0x80 0x01 0x00 0x00 - load data from storage + 0x80 0x02 KEY_INDEX 0x00 - initialize key pair + 0x80 0x03 KEY_INDEX 0x00 - generate key pair + 0x80 0x04 KEY_INDEX 0x00 - get public key + 0x80 0x05 CRT_INDEX 0x00 - load certificate + 0x80 0x06 CRT_INDEX 0x00 - get certificate + 0x80 0x07 0x00 0x00 - get version + 0x80 0x08 0x00 0x00 - confirm prepersonalization + 0x80 0x10 KEY_INDEX 0x00 - sign challenge + 0x80 0x11 KEY_INDEX 0x00 - dh key exchange + +*/ + +// TESLA +static int info_hf_tesla(void) { + + bool activate_field = true; + bool keep_field_on = true; + uint8_t response[PM3_CMD_DATA_SIZE]; + int resplen = 0; + + // --------------- Select TESLA application ---------------- + uint8_t aSELECT_AID[80]; + int aSELECT_AID_n = 0; + param_gethex_to_eol("00a404000a7465736c614c6f676963", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n); + int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + + if (resplen < 2) { + DropField(); + return PM3_ESOFT; + } + + uint16_t sw = get_sw(response, resplen); + if (sw != ISO7816_OK) { + PrintAndLogEx(ERR, "Selecting TESLA aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return PM3_ESOFT; + } + + activate_field = false; + keep_field_on = true; + + // --------------- ECDH public key file reading ---------------- + for (uint8_t i = 0; i < 3; i++) { + + uint8_t aSELECT_PK[5] = {0x80, 0x04, i, 0x00, 0x00}; + res = ExchangeAPDU14a(aSELECT_PK, sizeof(aSELECT_PK), activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res != PM3_SUCCESS) { + continue; + } + + sw = get_sw(response, resplen); + if (sw == ISO7816_OK) { + // save PK for later + uint8_t pk[65] = {0}; + memcpy(pk, response, resplen - 2); + + PrintAndLogEx(INFO, "PUBLIC KEY # %i", i); + PrintAndLogEx(INFO, "%s", sprint_hex_inrow(pk, sizeof(pk))); + } + } + + uint8_t aREAD_FORM_FACTOR[30]; + int aREAD_FORM_FACTOR_n = 0; + param_gethex_to_eol("80140000", 0, aREAD_FORM_FACTOR, sizeof(aREAD_FORM_FACTOR), &aREAD_FORM_FACTOR_n); + res = ExchangeAPDU14a(aREAD_FORM_FACTOR, aREAD_FORM_FACTOR_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + + sw = get_sw(response, resplen); + if (sw != ISO7816_OK) { + PrintAndLogEx(ERR, "reading FORM FACTOR file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return PM3_ESOFT; + } + + // store form factor for later + uint8_t form_factor[resplen - 2]; + memcpy(form_factor, response, sizeof(form_factor)); + + uint8_t aREAD_VERSION[30]; + int aREAD_VERSION_n = 0; + param_gethex_to_eol("80170000", 0, aREAD_VERSION, sizeof(aREAD_VERSION), &aREAD_VERSION_n); + res = ExchangeAPDU14a(aREAD_VERSION, aREAD_VERSION_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + + uint8_t version[resplen - 2]; + + sw = get_sw(response, resplen); + if (sw == ISO7816_OK) { + // store version for later + memcpy(version, response, sizeof(version)); + } + + // --------------- CERT reading ---------------- + Set_apdu_in_framing(true); + for (uint8_t i = 0; i < 4; i++) { + + uint8_t aSELECT_CERT[PM3_CMD_DATA_SIZE] = {0x80, 0x06, i, 0x00, 0x00, 0x00, 0xFF}; + int aSELECT_CERT_n = 7; + + res = ExchangeAPDU14a(aSELECT_CERT, aSELECT_CERT_n, activate_field, keep_field_on, response, PM3_CMD_DATA_SIZE, &resplen); + if (res != PM3_SUCCESS) { + continue; + } + + sw = get_sw(response, resplen); + + if (sw == ISO7816_OK) { + // save CETT for later + uint8_t cert[515] = {0}; + memcpy(cert, response, resplen - 2); + + PrintAndLogEx(INFO, "CERT # %i", i); + PrintAndLogEx(INFO, "%s", sprint_hex_inrow(cert, resplen - 2)); + } + } + Set_apdu_in_framing(false); + keep_field_on = false; + DropField(); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------"); + PrintAndLogEx(NORMAL, ""); +// PrintAndLogEx(INFO, "PUBLIC KEY"); +// PrintAndLogEx(INFO, "%zu - %s", sizeof(pk), sprint_hex_inrow(pk, sizeof(pk))); + PrintAndLogEx(INFO, "Form factor"); + PrintAndLogEx(INFO, "%zu - %s", sizeof(form_factor), sprint_hex_inrow(form_factor, sizeof(form_factor))); + PrintAndLogEx(INFO, "VERSION"); + PrintAndLogEx(INFO, "%zu - %s", sizeof(version), sprint_hex_inrow(version, sizeof(version))); + + return PM3_SUCCESS; +} + +// menu command to get and print all info known about any known ST25TA tag +static int CmdHFTeslaInfo(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf telsa info", + "Get info about TESLA Key tag", + "hf tesla info" + ); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); + return info_hf_tesla(); +} + + +static int CmdHFTeslaList(const char *Cmd) { + return CmdTraceListAlias(Cmd, "hf tesla", "7816"); +} + +static command_t CommandTable[] = { + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"info", CmdHFTeslaInfo, IfPm3Iso14443a, "Tag information"}, + {"list", CmdHFTeslaList, AlwaysAvailable, "List ISO 14443A/7816 history"}, + {NULL, NULL, NULL, NULL} +}; + +static int CmdHelp(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdsHelp(CommandTable); + return PM3_SUCCESS; +} + +int CmdHFTESLA(const char *Cmd) { + clearCommandBuffer(); + return CmdsParse(CommandTable, Cmd); +} diff --git a/client/src/cmdhftesla.h b/client/src/cmdhftesla.h new file mode 100644 index 000000000..923ac5fb1 --- /dev/null +++ b/client/src/cmdhftesla.h @@ -0,0 +1,26 @@ +//----------------------------------------------------------------------------- +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- +// High frequency ISO14443A / TESLA commands +//----------------------------------------------------------------------------- + +#ifndef CMDHFTESLA_H__ +#define CMDHFTESLA_H__ + +#include "common.h" + +int CmdHFTESLA(const char *Cmd); + +#endif diff --git a/common/commonutil.c b/common/commonutil.c index 2101414ab..601dc20e4 100644 --- a/common/commonutil.c +++ b/common/commonutil.c @@ -262,10 +262,10 @@ uint32_t rotr(uint32_t a, uint8_t n) { return (a >> n) | (a << (32 - n)); } -uint16_t get_sw(const uint8_t *d, uint8_t n) { +uint16_t get_sw(const uint8_t *d, uint16_t n) { if (n < 2) return 0; n -= 2; - return d[n] * 0x0100 + d[n + 1]; + return (d[n] << 8 | d[n + 1]); } diff --git a/common/commonutil.h b/common/commonutil.h index 0d8932a51..8e800f25f 100644 --- a/common/commonutil.h +++ b/common/commonutil.h @@ -85,5 +85,5 @@ void htole24(uint32_t val, uint8_t data[3]); uint32_t rotl(uint32_t a, uint8_t n); uint32_t rotr(uint32_t a, uint8_t n); -uint16_t get_sw(const uint8_t *d, uint8_t n); +uint16_t get_sw(const uint8_t *d, uint16_t n); #endif