From 4b00db8e48b6ec955028629a8ba9ec4daa699d3b Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sun, 30 May 2021 14:55:58 +0200 Subject: [PATCH] st -> st25ta --- client/CMakeLists.txt | 1 + client/Makefile | 1 + client/android/CMakeLists.txt | 1 + client/experimental_lib/CMakeLists.txt | 1 + client/src/cmdhf.c | 4 +- client/src/cmdhfst.c | 744 +----------------------- client/src/cmdhfst.h | 3 +- client/src/cmdhfst25ta.c | 753 +++++++++++++++++++++++++ client/src/cmdhfst25ta.h | 19 + client/src/cmdnfc.c | 4 +- doc/commands.md | 18 +- 11 files changed, 794 insertions(+), 755 deletions(-) create mode 100644 client/src/cmdhfst25ta.c create mode 100644 client/src/cmdhfst25ta.h diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 46628163e..8ff5f414c 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -253,6 +253,7 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/cmdhfmfu.c ${PM3_ROOT}/client/src/cmdhfseos.c ${PM3_ROOT}/client/src/cmdhfst.c + ${PM3_ROOT}/client/src/cmdhfst25ta.c ${PM3_ROOT}/client/src/cmdhfthinfilm.c ${PM3_ROOT}/client/src/cmdhftopaz.c ${PM3_ROOT}/client/src/cmdhfwaveshare.c diff --git a/client/Makefile b/client/Makefile index 726351cdc..be523d48a 100644 --- a/client/Makefile +++ b/client/Makefile @@ -485,6 +485,7 @@ SRCS = aiddesfire.c \ cmdhfmfp.c \ cmdhfseos.c \ cmdhfst.c \ + cmdhfst25ta.c \ cmdhfthinfilm.c \ cmdhftopaz.c \ cmdhfwaveshare.c \ diff --git a/client/android/CMakeLists.txt b/client/android/CMakeLists.txt index 2197052b1..f41d11fb5 100644 --- a/client/android/CMakeLists.txt +++ b/client/android/CMakeLists.txt @@ -120,6 +120,7 @@ add_library(pm3rrg_rdv4 SHARED ${PM3_ROOT}/client/src/cmdhfmfp.c ${PM3_ROOT}/client/src/cmdhfmfu.c ${PM3_ROOT}/client/src/cmdhfst.c + ${PM3_ROOT}/client/src/cmdhfst25ta.c ${PM3_ROOT}/client/src/cmdhfthinfilm.c ${PM3_ROOT}/client/src/cmdhftopaz.c ${PM3_ROOT}/client/src/cmdhfwaveshare.c diff --git a/client/experimental_lib/CMakeLists.txt b/client/experimental_lib/CMakeLists.txt index 4b0f0f174..67e424e89 100644 --- a/client/experimental_lib/CMakeLists.txt +++ b/client/experimental_lib/CMakeLists.txt @@ -252,6 +252,7 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/cmdhfmfp.c ${PM3_ROOT}/client/src/cmdhfmfu.c ${PM3_ROOT}/client/src/cmdhfst.c + ${PM3_ROOT}/client/src/cmdhfst25ta.c ${PM3_ROOT}/client/src/cmdhfthinfilm.c ${PM3_ROOT}/client/src/cmdhftopaz.c ${PM3_ROOT}/client/src/cmdhfwaveshare.c diff --git a/client/src/cmdhf.c b/client/src/cmdhf.c index 75069610f..369234b9d 100644 --- a/client/src/cmdhf.c +++ b/client/src/cmdhf.c @@ -37,7 +37,7 @@ #include "cmdhflto.h" // LTO-CM #include "cmdhfcryptorf.h" // CryptoRF #include "cmdhfseos.h" // SEOS -#include "cmdhfst.h" // ST rothult +#include "cmdhfst25ta.h" // ST25TA #include "cmdhfwaveshare.h" // Waveshare #include "cmdtrace.h" // trace list #include "ui.h" @@ -412,7 +412,7 @@ static command_t CommandTable[] = { {"mfu", CmdHFMFUltra, AlwaysAvailable, "{ MIFARE Ultralight RFIDs... }"}, {"mfdes", CmdHFMFDes, AlwaysAvailable, "{ MIFARE Desfire RFIDs... }"}, {"seos", CmdHFSeos, AlwaysAvailable, "{ SEOS RFIDs... }"}, - {"st", CmdHFST, AlwaysAvailable, "{ ST Rothult RFIDs... }"}, + {"st25ta", CmdHFST25TA, AlwaysAvailable, "{ ST25TA RFIDs... }"}, {"thinfilm", CmdHFThinfilm, AlwaysAvailable, "{ Thinfilm RFIDs... }"}, {"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"}, {"waveshare", CmdHFWaveshare, AlwaysAvailable, "{ Waveshare NFC ePaper... }"}, diff --git a/client/src/cmdhfst.c b/client/src/cmdhfst.c index 8e4cb40a6..28af644c4 100644 --- a/client/src/cmdhfst.c +++ b/client/src/cmdhfst.c @@ -9,24 +9,13 @@ //----------------------------------------------------------------------------- #include "cmdhfst.h" -#include -#include "fileutils.h" -#include "cmdparser.h" // command_t -#include "comms.h" // clearCommandBuffer -#include "cmdtrace.h" -#include "cliparser.h" -#include "crc16.h" -#include "cmdhf14a.h" -#include "protocols.h" // definitions of ISO14A/7816 protocol -#include "emv/apduinfo.h" // GetAPDUCodeDescription -#include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint +#include +#include #define TIMEOUT 2000 -static int CmdHelp(const char *Cmd); - // get ST Microelectronics chip model (from UID) -static char *get_st_chip_model(uint8_t pc) { +char *get_st_chip_model(uint8_t pc) { static char model[40]; char *s = model; memset(model, 0, sizeof(model)); @@ -78,7 +67,7 @@ static char *get_st_chip_model(uint8_t pc) { } /* // print UID info from SRx chips (ST Microelectronics) -static void print_st_general_info(uint8_t *data, uint8_t len) { +void print_st_general_info(uint8_t *data, uint8_t len) { //uid = first 8 bytes in data PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(SwapEndian64(data, 8, 8), len)); @@ -87,728 +76,3 @@ static void print_st_general_info(uint8_t *data, uint8_t len) { } */ -static void print_st_cc_info(uint8_t *d, uint8_t n) { - if (n < 0x0F) { - PrintAndLogEx(WARNING, "Not enought bytes read from system file"); - return; - } - - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "------------ " _CYAN_("Capability Container file") " ------------"); - PrintAndLogEx(SUCCESS, " len %u bytes (" _GREEN_("0x%02X") ")", d[1], d[1]); - PrintAndLogEx(SUCCESS, " version %s (" _GREEN_("0x%02X") ")", (d[2] == 0x20) ? "v2.0" : "v1.0", d[2]); - - uint16_t maxr = (d[3] << 8 | d[4]); - PrintAndLogEx(SUCCESS, " max bytes read %u bytes ( 0x%04X )", maxr, maxr); - uint16_t maxw = (d[5] << 8 | d[6]); - PrintAndLogEx(SUCCESS, " max bytes write %u bytes ( 0x%04X )", maxw, maxw); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, " NDEF file control TLV {"); - PrintAndLogEx(SUCCESS, " (t) type of file ( %02X )", d[7]); - PrintAndLogEx(SUCCESS, " (v) ( %02X )", d[8]); - PrintAndLogEx(SUCCESS, " file id ( %02X%02X )", d[9], d[10]); - - uint16_t maxndef = (d[11] << 8 | d[12]); - PrintAndLogEx(SUCCESS, " max NDEF filesize %u bytes ( 0x%04X )", maxndef, maxndef); - PrintAndLogEx(SUCCESS, " ----- " _CYAN_("access rights") " -------"); - PrintAndLogEx(SUCCESS, " read ( %02X ) protection: %s", d[13], ((d[13] & 0x80) == 0x80) ? _RED_("enabled") : _GREEN_("disabled")); - PrintAndLogEx(SUCCESS, " write ( %02X ) protection: %s", d[14], ((d[14] & 0x80) == 0x80) ? _RED_("enabled") : _GREEN_("disabled")); - PrintAndLogEx(SUCCESS, " }"); - PrintAndLogEx(SUCCESS, "----------------- " _CYAN_("raw") " -----------------"); - PrintAndLogEx(SUCCESS, "%s", sprint_hex_inrow(d, n)); - PrintAndLogEx(NORMAL, ""); -} -static void print_st_system_info(uint8_t *d, uint8_t n) { - if (n < 0x12) { - PrintAndLogEx(WARNING, "Not enought bytes read from system file"); - return; - } - - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "------------ " _CYAN_("ST System file") " ------------"); - - uint16_t len = (d[0] << 8 | d[1]); - PrintAndLogEx(SUCCESS, " len %u bytes (" _GREEN_("0x%04X") ")", len, len); - - if (d[2] == 0x80) { - PrintAndLogEx(SUCCESS, " ST reserved ( 0x%02X )", d[2]); - } else { - PrintAndLogEx(SUCCESS, " GPO Config ( 0x%02X )", d[2]); - PrintAndLogEx(SUCCESS, " config lock bit ( %s )", ((d[2] & 0x80) == 0x80) ? _RED_("locked") : _GREEN_("unlocked")); - uint8_t conf = (d[2] & 0x70) >> 4; - switch (conf) { - case 0: - PrintAndLogEx(SUCCESS, ""); - break; - case 1: - PrintAndLogEx(SUCCESS, "Session opened"); - break; - case 2: - PrintAndLogEx(SUCCESS, "WIP"); - break; - case 3: - PrintAndLogEx(SUCCESS, "MIP"); - break; - case 4: - PrintAndLogEx(SUCCESS, "Interrupt"); - break; - case 5: - PrintAndLogEx(SUCCESS, "State Control"); - break; - case 6: - PrintAndLogEx(SUCCESS, "RF Busy"); - break; - case 7: - PrintAndLogEx(SUCCESS, "Field Detect"); - break; - } - } - - PrintAndLogEx(SUCCESS, " Event counter config ( 0x%02X )", d[3]); - PrintAndLogEx(SUCCESS, " config lock bit ( %s )", ((d[3] & 0x80) == 0x80) ? _RED_("locked") : _GREEN_("unlocked")); - PrintAndLogEx(SUCCESS, " counter ( %s )", ((d[3] & 0x02) == 0x02) ? _RED_("enabled") : _GREEN_("disable")); - PrintAndLogEx(SUCCESS, " counter increment on ( %s )", ((d[3] & 0x01) == 0x01) ? _YELLOW_("write") : _YELLOW_("read")); - - uint32_t counter = (d[4] << 16 | d[5] << 8 | d[6]); - PrintAndLogEx(SUCCESS, " 20bit counter ( 0x%05X )", counter & 0xFFFFF); - - PrintAndLogEx(SUCCESS, " Product version ( 0x%02X )", d[7]); - - PrintAndLogEx(SUCCESS, " UID " _GREEN_("%s"), sprint_hex_inrow(d + 8, 7)); - PrintAndLogEx(SUCCESS, " MFG 0x%02X, " _YELLOW_("%s"), d[8], getTagInfo(d[8])); - PrintAndLogEx(SUCCESS, " Product Code 0x%02X, " _YELLOW_("%s"), d[9], get_st_chip_model(d[9])); - PrintAndLogEx(SUCCESS, " Device# " _YELLOW_("%s"), sprint_hex_inrow(d + 10, 5)); - - uint16_t mem = (d[0xF] << 8 | d[0x10]); - PrintAndLogEx(SUCCESS, " Memory Size - 1 %u bytes (" _GREEN_("0x%04X") ")", mem, mem); - - PrintAndLogEx(SUCCESS, " IC Reference code %u ( 0x%02X )", d[0x12], d[0x12]); - - PrintAndLogEx(SUCCESS, "----------------- " _CYAN_("raw") " -----------------"); - PrintAndLogEx(SUCCESS, "%s", sprint_hex_inrow(d, n)); - PrintAndLogEx(NORMAL, ""); - - /* - 0012 - 80000000001302E2007D0E8DCC - */ -} - -static uint16_t get_sw(uint8_t *d, uint8_t n) { - if (n < 2) - return 0; - - n -= 2; - return d[n] * 0x0100 + d[n + 1]; -} - -// ST rothult -static int infoHFST(void) { - - bool activate_field = true; - bool keep_field_on = true; - uint8_t response[PM3_CMD_DATA_SIZE]; - int resplen = 0; - - // --------------- Select NDEF Tag application ---------------- - uint8_t aSELECT_AID[80]; - int aSELECT_AID_n = 0; - param_gethex_to_eol("00a4040007d276000085010100", 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 != 0x9000) { - PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - DropField(); - return PM3_ESOFT; - } - - activate_field = false; - keep_field_on = true; - // --------------- CC file reading ---------------- - - uint8_t aSELECT_FILE_CC[30]; - int aSELECT_FILE_CC_n = 0; - param_gethex_to_eol("00a4000c02e103", 0, aSELECT_FILE_CC, sizeof(aSELECT_FILE_CC), &aSELECT_FILE_CC_n); - res = ExchangeAPDU14a(aSELECT_FILE_CC, aSELECT_FILE_CC_n, activate_field, keep_field_on, response, sizeof(response), &resplen); - if (res != PM3_SUCCESS) { - DropField(); - return res; - } - - sw = get_sw(response, resplen); - if (sw != 0x9000) { - PrintAndLogEx(ERR, "Selecting CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - DropField(); - return PM3_ESOFT; - } - - uint8_t aREAD_CC[30]; - int aREAD_CC_n = 0; - param_gethex_to_eol("00b000000f", 0, aREAD_CC, sizeof(aREAD_CC), &aREAD_CC_n); - res = ExchangeAPDU14a(aREAD_CC, aREAD_CC_n, activate_field, keep_field_on, response, sizeof(response), &resplen); - if (res != PM3_SUCCESS) { - DropField(); - return res; - } - - sw = get_sw(response, resplen); - if (sw != 0x9000) { - PrintAndLogEx(ERR, "reading CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - DropField(); - return PM3_ESOFT; - } - // store st cc data for later - uint8_t st_cc_data[resplen - 2]; - memcpy(st_cc_data, response, sizeof(st_cc_data)); - - // --------------- System file reading ---------------- - uint8_t aSELECT_FILE_SYS[30]; - int aSELECT_FILE_SYS_n = 0; - param_gethex_to_eol("00a4000c02e101", 0, aSELECT_FILE_SYS, sizeof(aSELECT_FILE_SYS), &aSELECT_FILE_SYS_n); - res = ExchangeAPDU14a(aSELECT_FILE_SYS, aSELECT_FILE_SYS_n, activate_field, keep_field_on, response, sizeof(response), &resplen); - if (res != PM3_SUCCESS) { - DropField(); - return res; - } - - sw = get_sw(response, resplen); - if (sw != 0x9000) { - PrintAndLogEx(ERR, "Selecting system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - DropField(); - return PM3_ESOFT; - } - - keep_field_on = false; - - uint8_t aREAD_SYS[30]; - int aREAD_SYS_n = 0; - param_gethex_to_eol("00b0000012", 0, aREAD_SYS, sizeof(aREAD_SYS), &aREAD_SYS_n); - res = ExchangeAPDU14a(aREAD_SYS, aREAD_SYS_n, activate_field, keep_field_on, response, sizeof(response), &resplen); - if (res != PM3_SUCCESS) { - DropField(); - return res; - } - - sw = get_sw(response, resplen); - if (sw != 0x9000) { - PrintAndLogEx(ERR, "reading system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - DropField(); - return PM3_ESOFT; - } - - - - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------"); - PrintAndLogEx(NORMAL, ""); - print_st_cc_info(st_cc_data, sizeof(st_cc_data)); - print_st_system_info(response, resplen - 2); - return PM3_SUCCESS; -} - -// menu command to get and print all info known about any known ST25TA tag -static int CmdHFSTInfo(const char *Cmd) { - CLIParserContext *ctx; - CLIParserInit(&ctx, "hf st info", - "Get info about ST25TA tag", - "hf st info" - ); - - void *argtable[] = { - arg_param_begin, - arg_param_end - }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParserFree(ctx); - return infoHFST(); -} - -static int CmdHFSTSim(const char *Cmd) { - int uidlen = 0; - uint8_t uid[7] = {0}; - - CLIParserContext *ctx; - CLIParserInit(&ctx, "hf st sim", - "Emulating ST25TA512B tag with 7 byte UID", - "hf st sim -u 02E2007D0FCA4C\n"); - - void *argtable[] = { - arg_param_begin, - arg_str1("u", "uid", "", "7 byte UID"), - arg_param_end - }; - CLIExecWithReturn(ctx, Cmd, argtable, false); - CLIGetHexWithReturn(ctx, 1, uid, &uidlen); - CLIParserFree(ctx); - - if (uidlen != 7) { - PrintAndLogEx(ERR, "UID must be 7 hex bytes"); - return PM3_EINVARG; - } - - char param[40]; - snprintf(param, sizeof(param), "-t 10 -u %s", sprint_hex_inrow(uid, uidlen)); - return CmdHF14ASim(param); -} - -int CmdHFSTNdefRead(const char *Cmd) { - int pwdlen = 0; - uint8_t pwd[16] = {0}; - bool with_pwd = false; - - CLIParserContext *ctx; - CLIParserInit(&ctx, "hf st ndefread", - "Read NFC Data Exchange Format (NDEF) file on ST25TA", - "hf st ndefread -p 82E80053D4CA5C0B656D852CC696C8A1\n"); - - void *argtable[] = { - arg_param_begin, - arg_str0("p", "pwd", "", "16 byte read password"), - arg_param_end - }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIGetHexWithReturn(ctx, 1, pwd, &pwdlen); - CLIParserFree(ctx); - - if (pwdlen == 0) { - with_pwd = false; - } else { - if (pwdlen != 16) { - PrintAndLogEx(ERR, "Password must be 16 hex bytes"); - return PM3_EINVARG; - } - with_pwd = true; - } - - bool activate_field = true; - bool keep_field_on = true; - uint8_t response[PM3_CMD_DATA_SIZE]; - int resplen = 0; - - // --------------- Select NDEF Tag application ---------------- - uint8_t aSELECT_AID[80]; - int aSELECT_AID_n = 0; - param_gethex_to_eol("00a4040007d276000085010100", 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 != 0x9000) { - PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - DropField(); - return PM3_ESOFT; - } - - activate_field = false; - keep_field_on = true; - - // --------------- NDEF file reading ---------------- - uint8_t aSELECT_FILE_NDEF[30]; - int aSELECT_FILE_NDEF_n = 0; - param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n); - res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen); - if (res != PM3_SUCCESS) { - DropField(); - return res; - } - - sw = get_sw(response, resplen); - if (sw != 0x9000) { - PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - DropField(); - return PM3_ESOFT; - } - - if (with_pwd) { - // --------------- VERIFY ---------------- - uint8_t aVERIFY[30]; - int aVERIFY_n = 0; - param_gethex_to_eol("0020000100", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n); - res = ExchangeAPDU14a(aVERIFY, aVERIFY_n, activate_field, keep_field_on, response, sizeof(response), &resplen); - if (res != PM3_SUCCESS) { - DropField(); - return res; - } - - sw = get_sw(response, resplen); - if (sw == 0x6300) { - // need to provide 16byte password - param_gethex_to_eol("0020000110", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n); - memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen); - res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen); - if (res != PM3_SUCCESS) { - DropField(); - return res; - } - - sw = get_sw(response, resplen); - if (sw != 0x9000) { - PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - DropField(); - return PM3_ESOFT; - } - } - } - - keep_field_on = false; - uint8_t aREAD_NDEF[30]; - int aREAD_NDEF_n = 0; - param_gethex_to_eol("00b000001d", 0, aREAD_NDEF, sizeof(aREAD_NDEF), &aREAD_NDEF_n); - res = ExchangeAPDU14a(aREAD_NDEF, aREAD_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen); - if (res != PM3_SUCCESS) { - DropField(); - return res; - } - - sw = get_sw(response, resplen); - if (sw != 0x9000) { - PrintAndLogEx(ERR, "reading NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - DropField(); - return PM3_ESOFT; - } - - NDEFRecordsDecodeAndPrint(response + 2, resplen - 4); - return PM3_SUCCESS; -} - -static int CmdHFSTProtect(const char *Cmd) { - - int pwdlen = 0; - uint8_t pwd[16] = {0}; - int statelen = 3; - uint8_t state[3] = {0x26, 0, 0x02}; - - bool disable_protection = false; - bool enable_protection = false; - bool read_protection = false; - bool write_protection = false; - - CLIParserContext *ctx; - CLIParserInit(&ctx, "hf st protect", - "Change read or write protection for NFC Data Exchange Format (NDEF) file on ST25TA", - "hf st protect -p 82E80053D4CA5C0B656D852CC696C8A1 -r -e -> enable read protection\n" - "hf st protect -p 82E80053D4CA5C0B656D852CC696C8A1 -w -d -> disable write protection\n"); - - void *argtable[] = { - arg_param_begin, - arg_lit0("e", "enable", "enable protection"), - arg_lit0("d", "disable", "disable protection (default)"), - arg_lit0("r", "read", "change read protection"), - arg_lit0("w", "write", "change write protection (default)"), - arg_str1("p", "password", "", "16 byte write password"), - arg_param_end - }; - CLIExecWithReturn(ctx, Cmd, argtable, false); - - enable_protection = arg_get_lit(ctx, 1); - disable_protection = arg_get_lit(ctx, 2); - read_protection = arg_get_lit(ctx, 3); - write_protection = arg_get_lit(ctx, 4); - CLIGetHexWithReturn(ctx, 5, pwd, &pwdlen); - CLIParserFree(ctx); - - //Validations - if (enable_protection && disable_protection) { - PrintAndLogEx(ERR, "Must specify either enable or disable protection, not both"); - return PM3_EINVARG; - } - if (enable_protection) { - state[0] = 0x28; - } - if (disable_protection) { - state[0] = 0x26; - } - - if (read_protection && write_protection) { - PrintAndLogEx(ERR, "Must specify either read or write protection, not both"); - return PM3_EINVARG; - } - if (read_protection) { - state[2] = 0x01; - } - if (write_protection) { - state[2] = 0x02; - } - - if (pwdlen != 16) { - PrintAndLogEx(ERR, "Missing 16 byte password"); - return PM3_EINVARG; - } - - bool activate_field = true; - bool keep_field_on = true; - uint8_t response[PM3_CMD_DATA_SIZE]; - int resplen = 0; - - // --------------- Select NDEF Tag application ---------------- - uint8_t aSELECT_AID[80]; - int aSELECT_AID_n = 0; - param_gethex_to_eol("00a4040007d276000085010100", 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 != 0x9000) { - PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - DropField(); - return PM3_ESOFT; - } - - activate_field = false; - keep_field_on = true; - - // --------------- Select NDEF file ---------------- - uint8_t aSELECT_FILE_NDEF[30]; - int aSELECT_FILE_NDEF_n = 0; - param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n); - res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen); - if (res != PM3_SUCCESS) { - DropField(); - return res; - } - - sw = get_sw(response, resplen); - if (sw != 0x9000) { - PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - DropField(); - return PM3_ESOFT; - } - - // --------------- VERIFY ---------------- - uint8_t aVERIFY[30]; - int aVERIFY_n = 0; - // need to provide 16byte password - param_gethex_to_eol("0020000210", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n); - memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen); - res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen); - if (res != PM3_SUCCESS) { - DropField(); - return res; - } - - sw = get_sw(response, resplen); - if (sw != 0x9000) { - PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - DropField(); - return PM3_ESOFT; - } - - // --------------- Change protection ---------------- - keep_field_on = false; - uint8_t aPROTECT[30]; - int aPROTECT_n = 0; - param_gethex_to_eol("00", 0, aPROTECT, sizeof(aPROTECT), &aPROTECT_n); - memcpy(aPROTECT + aPROTECT_n, state, statelen); - res = ExchangeAPDU14a(aPROTECT, aPROTECT_n + statelen, activate_field, keep_field_on, response, sizeof(response), &resplen); - if (res != PM3_SUCCESS) { - DropField(); - return res; - } - - sw = get_sw(response, resplen); - if (sw != 0x9000) { - PrintAndLogEx(ERR, "changing protection failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - DropField(); - return PM3_ESOFT; - } - - PrintAndLogEx(SUCCESS, " %s protection ( %s )", ((state[2] & 0x01) == 0x01) ? _YELLOW_("read") : _YELLOW_("write"), - ((state[0] & 0x28) == 0x28) ? _RED_("enabled") : _GREEN_("disabled")); - - return PM3_SUCCESS; -} - -static int CmdHFSTPwd(const char *Cmd) { - - int pwdlen = 0; - uint8_t pwd[16] = {0}; - int newpwdlen = 0; - uint8_t newpwd[16] = {0}; - int changePwdlen = 4; - uint8_t changePwd[4] = {0x24, 0x00, 0x01, 0x10}; - bool change_read_password = false; - bool change_write_password = false; - - CLIParserContext *ctx; - CLIParserInit(&ctx, "hf st pwd", - "Change read or write password for NFC Data Exchange Format (NDEF) file on ST25TA", - "hf st pwd -p 82E80053D4CA5C0B656D852CC696C8A1 -r -n 00000000000000000000000000000000 -> change read password\n" - "hf st pwd -p 82E80053D4CA5C0B656D852CC696C8A1 -w -n 00000000000000000000000000000000 -> change write password\n"); - - void *argtable[] = { - arg_param_begin, - arg_lit0("r", "read", "change the read password (default)"), - arg_lit0("w", "write", "change the write password"), - arg_str1("p", "password", "", "current 16 byte write password"), - arg_str1("n", "new", "", "new 16 byte password"), - arg_param_end - }; - CLIExecWithReturn(ctx, Cmd, argtable, false); - - change_read_password = arg_get_lit(ctx, 1); - change_write_password = arg_get_lit(ctx, 2); - CLIGetHexWithReturn(ctx, 3, pwd, &pwdlen); - CLIGetHexWithReturn(ctx, 4, newpwd, &newpwdlen); - CLIParserFree(ctx); - - if (change_read_password && change_write_password) { - PrintAndLogEx(ERR, "Must specify either read or write, not both"); - return PM3_EINVARG; - } - if (change_read_password) { - changePwd[2] = 0x01; - } - if (change_write_password) { - changePwd[2] = 0x02; - } - - if (pwdlen != 16) { - PrintAndLogEx(ERR, "Original write password must be 16 hex bytes"); - return PM3_EINVARG; - } - if (newpwdlen != 16) { - PrintAndLogEx(ERR, "New password must be 16 hex bytes"); - return PM3_EINVARG; - } - - bool activate_field = true; - bool keep_field_on = true; - uint8_t response[PM3_CMD_DATA_SIZE]; - int resplen = 0; - - // --------------- Select NDEF Tag application ---------------- - uint8_t aSELECT_AID[80]; - int aSELECT_AID_n = 0; - param_gethex_to_eol("00a4040007d276000085010100", 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 != 0x9000) { - PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - DropField(); - return PM3_ESOFT; - } - - activate_field = false; - keep_field_on = true; - - // --------------- Select NDEF file ---------------- - uint8_t aSELECT_FILE_NDEF[30]; - int aSELECT_FILE_NDEF_n = 0; - param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n); - res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen); - if (res != PM3_SUCCESS) { - DropField(); - return res; - } - - sw = get_sw(response, resplen); - if (sw != 0x9000) { - PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - DropField(); - return PM3_ESOFT; - } - - // --------------- VERIFY ---------------- - uint8_t aVERIFY[30]; - int aVERIFY_n = 0; - // need to provide 16byte password - param_gethex_to_eol("0020000210", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n); - memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen); - res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen); - if (res != PM3_SUCCESS) { - DropField(); - return res; - } - - sw = get_sw(response, resplen); - if (sw != 0x9000) { - PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - DropField(); - return PM3_ESOFT; - } - - // --------------- Change password ---------------- - - keep_field_on = false; - uint8_t aCHG_PWD[30]; - int aCHG_PWD_n = 0; - param_gethex_to_eol("00", 0, aCHG_PWD, sizeof(aCHG_PWD), &aCHG_PWD_n); - memcpy(aCHG_PWD + aCHG_PWD_n, changePwd, changePwdlen); - memcpy(aCHG_PWD + aCHG_PWD_n + changePwdlen, newpwd, newpwdlen); - res = ExchangeAPDU14a(aCHG_PWD, aCHG_PWD_n + changePwdlen + newpwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen); - if (res != PM3_SUCCESS) { - DropField(); - return res; - } - - sw = get_sw(response, resplen); - if (sw != 0x9000) { - PrintAndLogEx(ERR, "password change failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - DropField(); - return PM3_ESOFT; - } - PrintAndLogEx(SUCCESS, " %s password changed", ((changePwd[2] & 0x01) == 0x01) ? _YELLOW_("read") : _YELLOW_("write")); - return PM3_SUCCESS; -} - -static int CmdHFSTList(const char *Cmd) { - return CmdTraceListAlias(Cmd, "hf st", "7816"); -} - -static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"info", CmdHFSTInfo, IfPm3Iso14443a, "Tag information"}, - {"list", CmdHFSTList, AlwaysAvailable, "List ISO 14443A/7816 history"}, - {"ndefread", CmdHFSTNdefRead, AlwaysAvailable, "read NDEF file on tag"}, - {"protect", CmdHFSTProtect, IfPm3Iso14443a, "change protection on tag"}, - {"pwd", CmdHFSTPwd, IfPm3Iso14443a, "change password on tag"}, - {"sim", CmdHFSTSim, IfPm3Iso14443a, "Fake ISO 14443A/ST tag"}, - {NULL, NULL, NULL, NULL} -}; - -static int CmdHelp(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - CmdsHelp(CommandTable); - return PM3_SUCCESS; -} - -int CmdHFST(const char *Cmd) { - clearCommandBuffer(); - return CmdsParse(CommandTable, Cmd); -} diff --git a/client/src/cmdhfst.h b/client/src/cmdhfst.h index 2bc1277dc..828a4a286 100644 --- a/client/src/cmdhfst.h +++ b/client/src/cmdhfst.h @@ -13,7 +13,6 @@ #include "common.h" -int CmdHFST(const char *Cmd); -int CmdHFSTNdefRead(const char *Cmd); +char *get_st_chip_model(uint8_t pc); #endif diff --git a/client/src/cmdhfst25ta.c b/client/src/cmdhfst25ta.c new file mode 100644 index 000000000..eb3e8e184 --- /dev/null +++ b/client/src/cmdhfst25ta.c @@ -0,0 +1,753 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2020 iceman1001 +// +// 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. +//----------------------------------------------------------------------------- +// High frequency ISO14443A / ST25TA commands +//----------------------------------------------------------------------------- + +#include "cmdhfst25ta.h" +#include "cmdhfst.h" +#include +#include "fileutils.h" +#include "cmdparser.h" // command_t +#include "comms.h" // clearCommandBuffer +#include "cmdtrace.h" +#include "cliparser.h" +#include "crc16.h" +#include "cmdhf14a.h" +#include "protocols.h" // definitions of ISO14A/7816 protocol +#include "emv/apduinfo.h" // GetAPDUCodeDescription +#include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint + +#define TIMEOUT 2000 + +static int CmdHelp(const char *Cmd); + +static void print_st25ta_cc_info(uint8_t *d, uint8_t n) { + if (n < 0x0F) { + PrintAndLogEx(WARNING, "Not enough bytes read from system file"); + return; + } + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "------------ " _CYAN_("Capability Container file") " ------------"); + PrintAndLogEx(SUCCESS, " len %u bytes (" _GREEN_("0x%02X") ")", d[1], d[1]); + PrintAndLogEx(SUCCESS, " version %s (" _GREEN_("0x%02X") ")", (d[2] == 0x20) ? "v2.0" : "v1.0", d[2]); + + uint16_t maxr = (d[3] << 8 | d[4]); + PrintAndLogEx(SUCCESS, " max bytes read %u bytes ( 0x%04X )", maxr, maxr); + uint16_t maxw = (d[5] << 8 | d[6]); + PrintAndLogEx(SUCCESS, " max bytes write %u bytes ( 0x%04X )", maxw, maxw); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, " NDEF file control TLV {"); + PrintAndLogEx(SUCCESS, " (t) type of file ( %02X )", d[7]); + PrintAndLogEx(SUCCESS, " (v) ( %02X )", d[8]); + PrintAndLogEx(SUCCESS, " file id ( %02X%02X )", d[9], d[10]); + + uint16_t maxndef = (d[11] << 8 | d[12]); + PrintAndLogEx(SUCCESS, " max NDEF filesize %u bytes ( 0x%04X )", maxndef, maxndef); + PrintAndLogEx(SUCCESS, " ----- " _CYAN_("access rights") " -------"); + PrintAndLogEx(SUCCESS, " read ( %02X ) protection: %s", d[13], ((d[13] & 0x80) == 0x80) ? _RED_("enabled") : _GREEN_("disabled")); + PrintAndLogEx(SUCCESS, " write ( %02X ) protection: %s", d[14], ((d[14] & 0x80) == 0x80) ? _RED_("enabled") : _GREEN_("disabled")); + PrintAndLogEx(SUCCESS, " }"); + PrintAndLogEx(SUCCESS, "----------------- " _CYAN_("raw") " -----------------"); + PrintAndLogEx(SUCCESS, "%s", sprint_hex_inrow(d, n)); + PrintAndLogEx(NORMAL, ""); +} +static void print_st25ta_system_info(uint8_t *d, uint8_t n) { + if (n < 0x12) { + PrintAndLogEx(WARNING, "Not enough bytes read from system file"); + return; + } + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "------------ " _CYAN_("ST System file") " ------------"); + + uint16_t len = (d[0] << 8 | d[1]); + PrintAndLogEx(SUCCESS, " len %u bytes (" _GREEN_("0x%04X") ")", len, len); + + if (d[2] == 0x80) { + PrintAndLogEx(SUCCESS, " ST reserved ( 0x%02X )", d[2]); + } else { + PrintAndLogEx(SUCCESS, " GPO Config ( 0x%02X )", d[2]); + PrintAndLogEx(SUCCESS, " config lock bit ( %s )", ((d[2] & 0x80) == 0x80) ? _RED_("locked") : _GREEN_("unlocked")); + uint8_t conf = (d[2] & 0x70) >> 4; + switch (conf) { + case 0: + PrintAndLogEx(SUCCESS, ""); + break; + case 1: + PrintAndLogEx(SUCCESS, "Session opened"); + break; + case 2: + PrintAndLogEx(SUCCESS, "WIP"); + break; + case 3: + PrintAndLogEx(SUCCESS, "MIP"); + break; + case 4: + PrintAndLogEx(SUCCESS, "Interrupt"); + break; + case 5: + PrintAndLogEx(SUCCESS, "State Control"); + break; + case 6: + PrintAndLogEx(SUCCESS, "RF Busy"); + break; + case 7: + PrintAndLogEx(SUCCESS, "Field Detect"); + break; + } + } + + PrintAndLogEx(SUCCESS, " Event counter config ( 0x%02X )", d[3]); + PrintAndLogEx(SUCCESS, " config lock bit ( %s )", ((d[3] & 0x80) == 0x80) ? _RED_("locked") : _GREEN_("unlocked")); + PrintAndLogEx(SUCCESS, " counter ( %s )", ((d[3] & 0x02) == 0x02) ? _RED_("enabled") : _GREEN_("disable")); + PrintAndLogEx(SUCCESS, " counter increment on ( %s )", ((d[3] & 0x01) == 0x01) ? _YELLOW_("write") : _YELLOW_("read")); + + uint32_t counter = (d[4] << 16 | d[5] << 8 | d[6]); + PrintAndLogEx(SUCCESS, " 20bit counter ( 0x%05X )", counter & 0xFFFFF); + + PrintAndLogEx(SUCCESS, " Product version ( 0x%02X )", d[7]); + + PrintAndLogEx(SUCCESS, " UID " _GREEN_("%s"), sprint_hex_inrow(d + 8, 7)); + PrintAndLogEx(SUCCESS, " MFG 0x%02X, " _YELLOW_("%s"), d[8], getTagInfo(d[8])); + PrintAndLogEx(SUCCESS, " Product Code 0x%02X, " _YELLOW_("%s"), d[9], get_st_chip_model(d[9])); + PrintAndLogEx(SUCCESS, " Device# " _YELLOW_("%s"), sprint_hex_inrow(d + 10, 5)); + + uint16_t mem = (d[0xF] << 8 | d[0x10]); + PrintAndLogEx(SUCCESS, " Memory Size - 1 %u bytes (" _GREEN_("0x%04X") ")", mem, mem); + + PrintAndLogEx(SUCCESS, " IC Reference code %u ( 0x%02X )", d[0x12], d[0x12]); + + PrintAndLogEx(SUCCESS, "----------------- " _CYAN_("raw") " -----------------"); + PrintAndLogEx(SUCCESS, "%s", sprint_hex_inrow(d, n)); + PrintAndLogEx(NORMAL, ""); + + /* + 0012 + 80000000001302E2007D0E8DCC + */ +} + +static uint16_t get_sw(uint8_t *d, uint8_t n) { + if (n < 2) + return 0; + + n -= 2; + return d[n] * 0x0100 + d[n + 1]; +} + +// ST25TA +static int infoHFST25TA(void) { + + bool activate_field = true; + bool keep_field_on = true; + uint8_t response[PM3_CMD_DATA_SIZE]; + int resplen = 0; + + // --------------- Select NDEF Tag application ---------------- + uint8_t aSELECT_AID[80]; + int aSELECT_AID_n = 0; + param_gethex_to_eol("00a4040007d276000085010100", 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 != 0x9000) { + PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return PM3_ESOFT; + } + + activate_field = false; + keep_field_on = true; + // --------------- CC file reading ---------------- + + uint8_t aSELECT_FILE_CC[30]; + int aSELECT_FILE_CC_n = 0; + param_gethex_to_eol("00a4000c02e103", 0, aSELECT_FILE_CC, sizeof(aSELECT_FILE_CC), &aSELECT_FILE_CC_n); + res = ExchangeAPDU14a(aSELECT_FILE_CC, aSELECT_FILE_CC_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + + sw = get_sw(response, resplen); + if (sw != 0x9000) { + PrintAndLogEx(ERR, "Selecting CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return PM3_ESOFT; + } + + uint8_t aREAD_CC[30]; + int aREAD_CC_n = 0; + param_gethex_to_eol("00b000000f", 0, aREAD_CC, sizeof(aREAD_CC), &aREAD_CC_n); + res = ExchangeAPDU14a(aREAD_CC, aREAD_CC_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + + sw = get_sw(response, resplen); + if (sw != 0x9000) { + PrintAndLogEx(ERR, "reading CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return PM3_ESOFT; + } + // store st cc data for later + uint8_t st_cc_data[resplen - 2]; + memcpy(st_cc_data, response, sizeof(st_cc_data)); + + // --------------- System file reading ---------------- + uint8_t aSELECT_FILE_SYS[30]; + int aSELECT_FILE_SYS_n = 0; + param_gethex_to_eol("00a4000c02e101", 0, aSELECT_FILE_SYS, sizeof(aSELECT_FILE_SYS), &aSELECT_FILE_SYS_n); + res = ExchangeAPDU14a(aSELECT_FILE_SYS, aSELECT_FILE_SYS_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + + sw = get_sw(response, resplen); + if (sw != 0x9000) { + PrintAndLogEx(ERR, "Selecting system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return PM3_ESOFT; + } + + keep_field_on = false; + + uint8_t aREAD_SYS[30]; + int aREAD_SYS_n = 0; + param_gethex_to_eol("00b0000012", 0, aREAD_SYS, sizeof(aREAD_SYS), &aREAD_SYS_n); + res = ExchangeAPDU14a(aREAD_SYS, aREAD_SYS_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + + sw = get_sw(response, resplen); + if (sw != 0x9000) { + PrintAndLogEx(ERR, "reading system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return PM3_ESOFT; + } + + + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------"); + PrintAndLogEx(NORMAL, ""); + print_st25ta_cc_info(st_cc_data, sizeof(st_cc_data)); + print_st25ta_system_info(response, resplen - 2); + return PM3_SUCCESS; +} + +// menu command to get and print all info known about any known ST25TA tag +static int CmdHFST25TAInfo(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf st25ta info", + "Get info about ST25TA tag", + "hf st25ta info" + ); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); + return infoHFST25TA(); +} + +static int CmdHFST25TASim(const char *Cmd) { + int uidlen = 0; + uint8_t uid[7] = {0}; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf st25ta sim", + "Emulating ST25TA512B tag with 7 byte UID", + "hf st25ta sim -u 02E2007D0FCA4C\n"); + + void *argtable[] = { + arg_param_begin, + arg_str1("u", "uid", "", "7 byte UID"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + CLIGetHexWithReturn(ctx, 1, uid, &uidlen); + CLIParserFree(ctx); + + if (uidlen != 7) { + PrintAndLogEx(ERR, "UID must be 7 hex bytes"); + return PM3_EINVARG; + } + + char param[40]; + snprintf(param, sizeof(param), "-t 10 -u %s", sprint_hex_inrow(uid, uidlen)); + return CmdHF14ASim(param); +} + +int CmdHFST25TANdefRead(const char *Cmd) { + int pwdlen = 0; + uint8_t pwd[16] = {0}; + bool with_pwd = false; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf st25ta ndefread", + "Read NFC Data Exchange Format (NDEF) file on ST25TA", + "hf st25ta ndefread -p 82E80053D4CA5C0B656D852CC696C8A1\n"); + + void *argtable[] = { + arg_param_begin, + arg_str0("p", "pwd", "", "16 byte read password"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIGetHexWithReturn(ctx, 1, pwd, &pwdlen); + CLIParserFree(ctx); + + if (pwdlen == 0) { + with_pwd = false; + } else { + if (pwdlen != 16) { + PrintAndLogEx(ERR, "Password must be 16 hex bytes"); + return PM3_EINVARG; + } + with_pwd = true; + } + + bool activate_field = true; + bool keep_field_on = true; + uint8_t response[PM3_CMD_DATA_SIZE]; + int resplen = 0; + + // --------------- Select NDEF Tag application ---------------- + uint8_t aSELECT_AID[80]; + int aSELECT_AID_n = 0; + param_gethex_to_eol("00a4040007d276000085010100", 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 != 0x9000) { + PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return PM3_ESOFT; + } + + activate_field = false; + keep_field_on = true; + + // --------------- NDEF file reading ---------------- + uint8_t aSELECT_FILE_NDEF[30]; + int aSELECT_FILE_NDEF_n = 0; + param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n); + res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + + sw = get_sw(response, resplen); + if (sw != 0x9000) { + PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return PM3_ESOFT; + } + + if (with_pwd) { + // --------------- VERIFY ---------------- + uint8_t aVERIFY[30]; + int aVERIFY_n = 0; + param_gethex_to_eol("0020000100", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n); + res = ExchangeAPDU14a(aVERIFY, aVERIFY_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + + sw = get_sw(response, resplen); + if (sw == 0x6300) { + // need to provide 16byte password + param_gethex_to_eol("0020000110", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n); + memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen); + res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + + sw = get_sw(response, resplen); + if (sw != 0x9000) { + PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return PM3_ESOFT; + } + } + } + + keep_field_on = false; + uint8_t aREAD_NDEF[30]; + int aREAD_NDEF_n = 0; + param_gethex_to_eol("00b000001d", 0, aREAD_NDEF, sizeof(aREAD_NDEF), &aREAD_NDEF_n); + res = ExchangeAPDU14a(aREAD_NDEF, aREAD_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + + sw = get_sw(response, resplen); + if (sw != 0x9000) { + PrintAndLogEx(ERR, "reading NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return PM3_ESOFT; + } + + NDEFRecordsDecodeAndPrint(response + 2, resplen - 4); + return PM3_SUCCESS; +} + +static int CmdHFST25TAProtect(const char *Cmd) { + + int pwdlen = 0; + uint8_t pwd[16] = {0}; + int statelen = 3; + uint8_t state[3] = {0x26, 0, 0x02}; + + bool disable_protection = false; + bool enable_protection = false; + bool read_protection = false; + bool write_protection = false; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf st25ta protect", + "Change read or write protection for NFC Data Exchange Format (NDEF) file on ST25TA", + "hf st25ta protect -p 82E80053D4CA5C0B656D852CC696C8A1 -r -e -> enable read protection\n" + "hf st25ta protect -p 82E80053D4CA5C0B656D852CC696C8A1 -w -d -> disable write protection\n"); + + void *argtable[] = { + arg_param_begin, + arg_lit0("e", "enable", "enable protection"), + arg_lit0("d", "disable", "disable protection (default)"), + arg_lit0("r", "read", "change read protection"), + arg_lit0("w", "write", "change write protection (default)"), + arg_str1("p", "password", "", "16 byte write password"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + enable_protection = arg_get_lit(ctx, 1); + disable_protection = arg_get_lit(ctx, 2); + read_protection = arg_get_lit(ctx, 3); + write_protection = arg_get_lit(ctx, 4); + CLIGetHexWithReturn(ctx, 5, pwd, &pwdlen); + CLIParserFree(ctx); + + //Validations + if (enable_protection && disable_protection) { + PrintAndLogEx(ERR, "Must specify either enable or disable protection, not both"); + return PM3_EINVARG; + } + if (enable_protection) { + state[0] = 0x28; + } + if (disable_protection) { + state[0] = 0x26; + } + + if (read_protection && write_protection) { + PrintAndLogEx(ERR, "Must specify either read or write protection, not both"); + return PM3_EINVARG; + } + if (read_protection) { + state[2] = 0x01; + } + if (write_protection) { + state[2] = 0x02; + } + + if (pwdlen != 16) { + PrintAndLogEx(ERR, "Missing 16 byte password"); + return PM3_EINVARG; + } + + bool activate_field = true; + bool keep_field_on = true; + uint8_t response[PM3_CMD_DATA_SIZE]; + int resplen = 0; + + // --------------- Select NDEF Tag application ---------------- + uint8_t aSELECT_AID[80]; + int aSELECT_AID_n = 0; + param_gethex_to_eol("00a4040007d276000085010100", 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 != 0x9000) { + PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return PM3_ESOFT; + } + + activate_field = false; + keep_field_on = true; + + // --------------- Select NDEF file ---------------- + uint8_t aSELECT_FILE_NDEF[30]; + int aSELECT_FILE_NDEF_n = 0; + param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n); + res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + + sw = get_sw(response, resplen); + if (sw != 0x9000) { + PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return PM3_ESOFT; + } + + // --------------- VERIFY ---------------- + uint8_t aVERIFY[30]; + int aVERIFY_n = 0; + // need to provide 16byte password + param_gethex_to_eol("0020000210", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n); + memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen); + res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + + sw = get_sw(response, resplen); + if (sw != 0x9000) { + PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return PM3_ESOFT; + } + + // --------------- Change protection ---------------- + keep_field_on = false; + uint8_t aPROTECT[30]; + int aPROTECT_n = 0; + param_gethex_to_eol("00", 0, aPROTECT, sizeof(aPROTECT), &aPROTECT_n); + memcpy(aPROTECT + aPROTECT_n, state, statelen); + res = ExchangeAPDU14a(aPROTECT, aPROTECT_n + statelen, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + + sw = get_sw(response, resplen); + if (sw != 0x9000) { + PrintAndLogEx(ERR, "changing protection failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return PM3_ESOFT; + } + + PrintAndLogEx(SUCCESS, " %s protection ( %s )", ((state[2] & 0x01) == 0x01) ? _YELLOW_("read") : _YELLOW_("write"), + ((state[0] & 0x28) == 0x28) ? _RED_("enabled") : _GREEN_("disabled")); + + return PM3_SUCCESS; +} + +static int CmdHFST25TAPwd(const char *Cmd) { + + int pwdlen = 0; + uint8_t pwd[16] = {0}; + int newpwdlen = 0; + uint8_t newpwd[16] = {0}; + int changePwdlen = 4; + uint8_t changePwd[4] = {0x24, 0x00, 0x01, 0x10}; + bool change_read_password = false; + bool change_write_password = false; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf st25ta pwd", + "Change read or write password for NFC Data Exchange Format (NDEF) file on ST25TA", + "hf st25ta pwd -p 82E80053D4CA5C0B656D852CC696C8A1 -r -n 00000000000000000000000000000000 -> change read password\n" + "hf st25ta pwd -p 82E80053D4CA5C0B656D852CC696C8A1 -w -n 00000000000000000000000000000000 -> change write password\n"); + + void *argtable[] = { + arg_param_begin, + arg_lit0("r", "read", "change the read password (default)"), + arg_lit0("w", "write", "change the write password"), + arg_str1("p", "password", "", "current 16 byte write password"), + arg_str1("n", "new", "", "new 16 byte password"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + change_read_password = arg_get_lit(ctx, 1); + change_write_password = arg_get_lit(ctx, 2); + CLIGetHexWithReturn(ctx, 3, pwd, &pwdlen); + CLIGetHexWithReturn(ctx, 4, newpwd, &newpwdlen); + CLIParserFree(ctx); + + if (change_read_password && change_write_password) { + PrintAndLogEx(ERR, "Must specify either read or write, not both"); + return PM3_EINVARG; + } + if (change_read_password) { + changePwd[2] = 0x01; + } + if (change_write_password) { + changePwd[2] = 0x02; + } + + if (pwdlen != 16) { + PrintAndLogEx(ERR, "Original write password must be 16 hex bytes"); + return PM3_EINVARG; + } + if (newpwdlen != 16) { + PrintAndLogEx(ERR, "New password must be 16 hex bytes"); + return PM3_EINVARG; + } + + bool activate_field = true; + bool keep_field_on = true; + uint8_t response[PM3_CMD_DATA_SIZE]; + int resplen = 0; + + // --------------- Select NDEF Tag application ---------------- + uint8_t aSELECT_AID[80]; + int aSELECT_AID_n = 0; + param_gethex_to_eol("00a4040007d276000085010100", 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 != 0x9000) { + PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return PM3_ESOFT; + } + + activate_field = false; + keep_field_on = true; + + // --------------- Select NDEF file ---------------- + uint8_t aSELECT_FILE_NDEF[30]; + int aSELECT_FILE_NDEF_n = 0; + param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n); + res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + + sw = get_sw(response, resplen); + if (sw != 0x9000) { + PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return PM3_ESOFT; + } + + // --------------- VERIFY ---------------- + uint8_t aVERIFY[30]; + int aVERIFY_n = 0; + // need to provide 16byte password + param_gethex_to_eol("0020000210", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n); + memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen); + res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + + sw = get_sw(response, resplen); + if (sw != 0x9000) { + PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return PM3_ESOFT; + } + + // --------------- Change password ---------------- + + keep_field_on = false; + uint8_t aCHG_PWD[30]; + int aCHG_PWD_n = 0; + param_gethex_to_eol("00", 0, aCHG_PWD, sizeof(aCHG_PWD), &aCHG_PWD_n); + memcpy(aCHG_PWD + aCHG_PWD_n, changePwd, changePwdlen); + memcpy(aCHG_PWD + aCHG_PWD_n + changePwdlen, newpwd, newpwdlen); + res = ExchangeAPDU14a(aCHG_PWD, aCHG_PWD_n + changePwdlen + newpwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + + sw = get_sw(response, resplen); + if (sw != 0x9000) { + PrintAndLogEx(ERR, "password change failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return PM3_ESOFT; + } + PrintAndLogEx(SUCCESS, " %s password changed", ((changePwd[2] & 0x01) == 0x01) ? _YELLOW_("read") : _YELLOW_("write")); + return PM3_SUCCESS; +} + +static int CmdHFST25TAList(const char *Cmd) { + return CmdTraceListAlias(Cmd, "hf st25ta", "7816"); +} + +static command_t CommandTable[] = { + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"info", CmdHFST25TAInfo, IfPm3Iso14443a, "Tag information"}, + {"list", CmdHFST25TAList, AlwaysAvailable, "List ISO 14443A/7816 history"}, + {"ndefread", CmdHFST25TANdefRead, AlwaysAvailable, "read NDEF file on tag"}, + {"protect", CmdHFST25TAProtect, IfPm3Iso14443a, "change protection on tag"}, + {"pwd", CmdHFST25TAPwd, IfPm3Iso14443a, "change password on tag"}, + {"sim", CmdHFST25TASim, IfPm3Iso14443a, "Fake ISO 14443A/ST tag"}, + {NULL, NULL, NULL, NULL} +}; + +static int CmdHelp(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdsHelp(CommandTable); + return PM3_SUCCESS; +} + +int CmdHFST25TA(const char *Cmd) { + clearCommandBuffer(); + return CmdsParse(CommandTable, Cmd); +} diff --git a/client/src/cmdhfst25ta.h b/client/src/cmdhfst25ta.h new file mode 100644 index 000000000..3c0ed9a2f --- /dev/null +++ b/client/src/cmdhfst25ta.h @@ -0,0 +1,19 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2020 iceman1001 +// +// 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. +//----------------------------------------------------------------------------- +// High frequency ISO14443A / ST25TA commands +//----------------------------------------------------------------------------- + +#ifndef CMDHFST25TA_H__ +#define CMDHFST25TA_H__ + +#include "common.h" + +int CmdHFST25TA(const char *Cmd); +int CmdHFST25TANdefRead(const char *Cmd); + +#endif diff --git a/client/src/cmdnfc.c b/client/src/cmdnfc.c index ba854cf4e..45a0a32e3 100644 --- a/client/src/cmdnfc.c +++ b/client/src/cmdnfc.c @@ -15,7 +15,7 @@ #include "cmdhfmf.h" #include "cmdhfmfp.h" #include "cmdhfmfu.h" -#include "cmdhfst.h" +#include "cmdhfst25ta.h" #include "cmdhfthinfilm.h" #include "cmdhftopaz.h" @@ -145,7 +145,7 @@ static int CmdNFCType4ARead(const char *Cmd) { } static int CmdNFCST25TARead(const char *Cmd) { - return CmdHFSTNdefRead(Cmd); + return CmdHFST25TANdefRead(Cmd); } static int CmdNFCType4AHelp(const char *Cmd); diff --git a/doc/commands.md b/doc/commands.md index 75737d811..c9340634c 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -518,19 +518,19 @@ Check column "offline" for their availability. |`hf seos list `|Y |`List SEOS history` -### hf st +### hf st25ta - { ST Rothult RFIDs... } + { ST25TA RFIDs... } |command |offline |description |------- |------- |----------- -|`hf st help `|Y |`This help` -|`hf st info `|N |`Tag information` -|`hf st list `|Y |`List ISO 14443A/7816 history` -|`hf st ndefread `|Y |`read NDEF file on tag` -|`hf st protect `|N |`change protection on tag` -|`hf st pwd `|N |`change password on tag` -|`hf st sim `|N |`Fake ISO 14443A/ST tag` +|`hf st25ta help `|Y |`This help` +|`hf st25ta info `|N |`Tag information` +|`hf st25ta list `|Y |`List ISO 14443A/7816 history` +|`hf st25ta ndefread `|Y |`read NDEF file on tag` +|`hf st25ta protect `|N |`change protection on tag` +|`hf st25ta pwd `|N |`change password on tag` +|`hf st25ta sim `|N |`Fake ISO 14443A/ST tag` ### hf thinfilm