diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index ddc3be0f9..b2c9acde2 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -133,6 +133,36 @@ static uint32_t LastProxToAirDuration; #define SEC_Y 0x00 #define SEC_Z 0xc0 + +static const iso14a_polling_frame_t WUPA_CMD = { + { ISO14443A_CMD_WUPA }, 1, 7, 0 +}; + +static const iso14a_polling_frame_t REQA_CMD = { + {ISO14443A_CMD_REQA }, 1, 7, 0 +}; + +static const iso14a_polling_frame_t MAGWUPA_COMMANDS[4] = { + {{ 0x7A }, 1, 7, 0}, + {{ 0x7B }, 1, 7, 0}, + {{ 0x7C }, 1, 7, 0}, + {{ 0x7D }, 1, 7, 0} +}; + + +// Polling frames and configurations +iso14a_polling_parameters_t WUPA_POLLING_PARAMETERS = { + .frames = { WUPA_CMD }, + .frame_count = 1, + .extra_timeout = 0, +}; + +iso14a_polling_parameters_t REQA_POLLING_PARAMETERS = { + .frames = { REQA_CMD }, + .frame_count = 1, + .extra_timeout = 0, +}; + /* Default HF 14a config is set to: forceanticol = 0 (auto) @@ -140,21 +170,17 @@ Default HF 14a config is set to: forcecl2 = 0 (auto) forcecl3 = 0 (auto) forcerats = 0 (auto) + magsafe = 0 (disabled) + polling_loop_annotation = {{0}, 0, 0, 0} (disabled) */ -static hf14a_config hf14aconfig = { 0, 0, 0, 0, 0, {{0}, 0, 0, 0} }; +static hf14a_config hf14aconfig = { 0, 0, 0, 0, 0, 0, {{0}, 0, 0, 0} }; +static iso14a_polling_parameters_t hf14a_polling_parameters = { + .frames = { WUPA_CMD }, + .frame_count = 1, + .extra_timeout = 0 +}; -// Polling frames and configurations -iso14a_polling_parameters_t WUPA_POLLING_PARAMETERS = { - .frames = { {{ ISO14443A_CMD_WUPA }, 1, 7, 0} }, - .frame_count = 1, - .extra_timeout = 0, -}; -iso14a_polling_parameters_t REQA_POLLING_PARAMETERS = { - .frames = { {{ ISO14443A_CMD_REQA }, 1, 7, 0} }, - .frame_count = 1, - .extra_timeout = 0, -}; // parity isn't used much static uint8_t parity_array[MAX_PARITY_SIZE] = {0}; @@ -191,6 +217,9 @@ void printHf14aConfig(void) { (hf14aconfig.forcerats == 1) ? _RED_("force") " ( always do RATS )" : "", (hf14aconfig.forcerats == 2) ? _RED_("skip") " ( always skip RATS )" : "" ); + Dbprintf(" [m] Magsafe polling............... %s", + (hf14aconfig.magsafe == 1) ? _GREEN_("enabled") : _YELLOW_("disabled") + ); Dbprintf(" [p] Polling loop annotation....... %s %*D", (hf14aconfig.polling_loop_annotation.frame_length <= 0) ? _YELLOW_("disabled") : _GREEN_("enabled"), hf14aconfig.polling_loop_annotation.frame_length, @@ -208,7 +237,6 @@ void printHf14aConfig(void) { * @param sc */ void setHf14aConfig(const hf14a_config *hc) { - if ((hc->forceanticol >= 0) && (hc->forceanticol <= 2)) hf14aconfig.forceanticol = hc->forceanticol; if ((hc->forcebcc >= 0) && (hc->forcebcc <= 2)) @@ -219,12 +247,30 @@ void setHf14aConfig(const hf14a_config *hc) { hf14aconfig.forcecl3 = hc->forcecl3; if ((hc->forcerats >= 0) && (hc->forcerats <= 2)) hf14aconfig.forcerats = hc->forcerats; - - if (hc->polling_loop_annotation.frame_length > 0) { + if ((hc->magsafe >= 0) && (hc->magsafe <= 1)) + hf14aconfig.magsafe = hc->magsafe; + if (hc->polling_loop_annotation.frame_length >= 0) { memcpy(&hf14aconfig.polling_loop_annotation, &hc->polling_loop_annotation, sizeof(iso14a_polling_frame_t)); - } else if (hc->polling_loop_annotation.frame_length < 0) { - // Reset if set to empty - hf14aconfig.polling_loop_annotation.frame_length = 0; + } + + // Derive polling loop configuration based on 14a config + hf14a_polling_parameters.frames[0] = WUPA_CMD; + hf14a_polling_parameters.frame_count = 1; + hf14a_polling_parameters.extra_timeout = 0; + if (hf14aconfig.magsafe == 1) { + for (int i = 0; i < ARRAYLEN(MAGWUPA_COMMANDS); i++) { + if (hf14a_polling_parameters.frame_count < ARRAYLEN(hf14a_polling_parameters.frames) - 1) { + hf14a_polling_parameters.frames[hf14a_polling_parameters.frame_count] = MAGWUPA_COMMANDS[i]; + hf14a_polling_parameters.frame_count += 1; + } + } + } + if (hf14aconfig.polling_loop_annotation.frame_length > 0) { + if (hf14a_polling_parameters.frame_count < ARRAYLEN(hf14a_polling_parameters.frames)) { + hf14a_polling_parameters.frames[hf14a_polling_parameters.frame_count] = hf14aconfig.polling_loop_annotation; + hf14a_polling_parameters.frame_count += 1; + } + hf14a_polling_parameters.extra_timeout = 250; } } @@ -2560,8 +2606,7 @@ static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint16_t rec_max return false; } -void ReaderTransmitBitsPar(uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t *timing) { - +void ReaderTransmitBitsPar(const uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t *timing) { CodeIso14443aBitsAsReaderPar(frame, bits, par); // Send command to tag tosend_t *ts = get_tosend(); @@ -2571,17 +2616,17 @@ void ReaderTransmitBitsPar(uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t LogTrace(frame, nbytes(bits), (LastTimeProxToAirStart << 4) + DELAY_ARM2AIR_AS_READER, ((LastTimeProxToAirStart + LastProxToAirDuration) << 4) + DELAY_ARM2AIR_AS_READER, par, true); } -void ReaderTransmitPar(uint8_t *frame, uint16_t len, uint8_t *par, uint32_t *timing) { +void ReaderTransmitPar(const uint8_t *frame, uint16_t len, uint8_t *par, uint32_t *timing) { ReaderTransmitBitsPar(frame, len * 8, par, timing); } -static void ReaderTransmitBits(uint8_t *frame, uint16_t len, uint32_t *timing) { +static void ReaderTransmitBits(const uint8_t *frame, uint16_t len, uint32_t *timing) { // Generate parity and redirect GetParity(frame, len / 8, parity_array); ReaderTransmitBitsPar(frame, len, parity_array, timing); } -void ReaderTransmit(uint8_t *frame, uint16_t len, uint32_t *timing) { +void ReaderTransmit(const uint8_t *frame, uint16_t len, uint32_t *timing) { // Generate parity and redirect GetParity(frame, len, parity_array); ReaderTransmitBitsPar(frame, len * 8, parity_array, timing); @@ -2708,42 +2753,23 @@ static void iso14a_set_ATS_times(const uint8_t *ats) { } -static int GetATQA(uint8_t *resp, uint16_t resp_len, uint8_t *resp_par, iso14a_polling_parameters_t *polling_parameters) { -#define WUPA_RETRY_TIMEOUT 10 +static int GetATQA(uint8_t *resp, uint16_t resp_len, uint8_t *resp_par, const iso14a_polling_parameters_t *polling_parameters) { + #define RETRY_TIMEOUT 10 uint32_t save_iso14a_timeout = iso14a_get_timeout(); iso14a_set_timeout(1236 / 128 + 1); // response to WUPA is expected at exactly 1236/fc. No need to wait longer. - // Create temporary polling parameters structure that might include both standard and custom frames - iso14a_polling_parameters_t temp_params; - memcpy(&temp_params, polling_parameters, sizeof(iso14a_polling_parameters_t)); - - // If we have a custom polling frame annotation, add it to the temporary structure - if (hf14aconfig.polling_loop_annotation.frame_length > 0) { - // Only add if we have space in the frames array - if (temp_params.frame_count < ARRAYLEN(temp_params.frames)) { - // Add the custom frame at the end of the frames array - memcpy(&temp_params.frames[temp_params.frame_count], - &hf14aconfig.polling_loop_annotation, - sizeof(iso14a_polling_frame_t)); - temp_params.frame_count++; - } - - // Increase timeout if polling loop annotation is provided, as target may respond slower - if (temp_params.extra_timeout == 0) { - temp_params.extra_timeout = 250; - } - } + polling_parameters = polling_parameters != NULL ? polling_parameters : &hf14a_polling_parameters; bool first_try = true; int len; - uint32_t retry_timeout = WUPA_RETRY_TIMEOUT * temp_params.frame_count + temp_params.extra_timeout; + uint32_t retry_timeout = RETRY_TIMEOUT * polling_parameters->frame_count + polling_parameters->extra_timeout; uint32_t start_time = 0; uint8_t current_frame = 0; // Use the temporary polling parameters do { - iso14a_polling_frame_t *frame_parameters = &temp_params.frames[current_frame]; + const iso14a_polling_frame_t *frame_parameters = &polling_parameters->frames[current_frame]; if (frame_parameters->last_byte_bits == 8) { ReaderTransmit(frame_parameters->frame, frame_parameters->frame_length, NULL); @@ -2765,7 +2791,7 @@ static int GetATQA(uint8_t *resp, uint16_t resp_len, uint8_t *resp_par, iso14a_p } // Go over frame configurations, loop back when we reach the end - current_frame = current_frame < (temp_params.frame_count - 1) ? current_frame + 1 : 0; + current_frame = current_frame < (polling_parameters->frame_count - 1) ? current_frame + 1 : 0; } while (len == 0 && GetTickCountDelta(start_time) <= retry_timeout); iso14a_set_timeout(save_iso14a_timeout); @@ -2774,7 +2800,7 @@ static int GetATQA(uint8_t *resp, uint16_t resp_len, uint8_t *resp_par, iso14a_p int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats) { - return iso14443a_select_cardEx(uid_ptr, p_card, cuid_ptr, anticollision, num_cascades, no_rats, &WUPA_POLLING_PARAMETERS); + return iso14443a_select_cardEx(uid_ptr, p_card, cuid_ptr, anticollision, num_cascades, no_rats, NULL); } @@ -3047,7 +3073,7 @@ int iso14443a_fast_select_card(uint8_t *uid_ptr, uint8_t num_cascades) { uint8_t sak = 0x04; // cascade uid int cascade_level = 1; - if (GetATQA(resp, sizeof(resp), resp_par, &WUPA_POLLING_PARAMETERS) == 0) { + if (GetATQA(resp, sizeof(resp), resp_par, NULL) == 0) { return 0; } @@ -3280,7 +3306,7 @@ void ReaderIso14443a(PacketCommandNG *c) { true, 0, ((param & ISO14A_NO_RATS) == ISO14A_NO_RATS), - ((param & ISO14A_USE_CUSTOM_POLLING) == ISO14A_USE_CUSTOM_POLLING) ? (iso14a_polling_parameters_t *)cmd : &WUPA_POLLING_PARAMETERS + ((param & ISO14A_USE_CUSTOM_POLLING) == ISO14A_USE_CUSTOM_POLLING) ? (iso14a_polling_parameters_t *)cmd : NULL ); // TODO: Improve by adding a cmd parser pointer and moving it by struct length to allow combining data with polling params FpgaDisableTracing(); diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index d3463b138..2cda8a21e 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -157,9 +157,9 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, bool GetIso14443aCommandFromReader(uint8_t *received, uint16_t received_maxlen, uint8_t *par, int *len); void iso14443a_antifuzz(uint32_t flags); void ReaderIso14443a(PacketCommandNG *c); -void ReaderTransmit(uint8_t *frame, uint16_t len, uint32_t *timing); -void ReaderTransmitBitsPar(uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t *timing); -void ReaderTransmitPar(uint8_t *frame, uint16_t len, uint8_t *par, uint32_t *timing); +void ReaderTransmit(const uint8_t *frame, uint16_t len, uint32_t *timing); +void ReaderTransmitBitsPar(const uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t *timing); +void ReaderTransmitPar(const uint8_t *frame, uint16_t len, uint8_t *par, uint32_t *timing); uint16_t ReaderReceive(uint8_t *receivedAnswer, uint16_t answer_maxlen, uint8_t *par); void iso14443a_setup(uint8_t fpga_minor_mode); diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 32ba0c00b..a47f73eb9 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -58,34 +58,6 @@ static int CmdHelp(const char *Cmd); static int waitCmd(bool i_select, uint32_t timeout, bool verbose); -static const iso14a_polling_frame_t WUPA_FRAME = { - { 0x52 }, 1, 7, 0, -}; - -static const iso14a_polling_frame_t MAGWUPA1_FRAME = { - { 0x7A }, 1, 7, 0 -}; - -static const iso14a_polling_frame_t MAGWUPA2_FRAME = { - { 0x7B }, 1, 7, 0 -}; - -static const iso14a_polling_frame_t MAGWUPA3_FRAME = { - { 0x7C }, 1, 7, 0 -}; - -static const iso14a_polling_frame_t MAGWUPA4_FRAME = { - { 0x7D }, 1, 7, 0 -}; - -static const iso14a_polling_frame_t ECP_FRAME = { - .frame = { 0x6a, 0x02, 0xC8, 0x01, 0x00, 0x03, 0x00, 0x02, 0x79, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xD8}, - .frame_length = 15, - .last_byte_bits = 8, - .extra_delay = 0 -}; - - // based on ISO/IEC JTC1/SC17 STANDING DOCUMENT 5 (Updated 20 September 2024) Register of IC manufacturers static const manufactureName_t manufactureMapping[] = { // ID, "Vendor Country" @@ -370,8 +342,10 @@ static int CmdHf14AConfig(const char *Cmd) { "hf 14a config --rats std -> Follow standard\n" "hf 14a config --rats force -> Execute RATS\n" "hf 14a config --rats skip -> Skip RATS\n" + "hf 14a config --mag on -> Enable Apple magsafe polling\n" + "hf 14a config --mag off -> Disable Apple magsafe polling\n" "hf 14a config --pla -> Set polling loop annotation (max 22 bytes)\n" - "hf 14a config --pla skip -> Disable polling loop annotation\n"); + "hf 14a config --pla off -> Disable polling loop annotation\n"); void *argtable[] = { arg_param_begin, arg_str0(NULL, "atqa", "", "Configure ATQA<>anticollision behavior"), @@ -379,14 +353,15 @@ static int CmdHf14AConfig(const char *Cmd) { arg_str0(NULL, "cl2", "", "Configure SAK<>CL2 behavior"), arg_str0(NULL, "cl3", "", "Configure SAK<>CL3 behavior"), arg_str0(NULL, "rats", "", "Configure RATS behavior"), - arg_str0(NULL, "pla", "", "Configure polling loop annotation"), + arg_str0(NULL, "mag", "", "Configure Apple MagSafe polling"), + arg_str0(NULL, "pla", "", "Configure polling loop annotation"), arg_lit0(NULL, "std", "Reset default configuration: follow all standard"), arg_lit0("v", "verbose", "verbose output"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - bool defaults = arg_get_lit(ctx, 7); - bool verbose = arg_get_lit(ctx, 8); + bool defaults = arg_get_lit(ctx, 8); + bool verbose = arg_get_lit(ctx, 9); int vlen = 0; char value[64]; @@ -450,39 +425,57 @@ static int CmdHf14AConfig(const char *Cmd) { return PM3_EINVARG; } } - + int magsafe = defaults ? 0 : -1; + CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)value, sizeof(value), &vlen); + if (vlen > 0) { + if (strcmp(value, "std") == 0) magsafe = 0; + else if (strcmp(value, "skip") == 0) magsafe = 0; + else if (strcmp(value, "disable") == 0) magsafe = 0; + else if (strcmp(value, "off") == 0) magsafe = 0; + else if (strcmp(value, "enable") == 0) magsafe = 1; + else if (strcmp(value, "on") == 0) magsafe = 1; + else { + PrintAndLogEx(ERR, "magsafe argument must be 'std', 'skip', 'off', 'disable', 'on' or 'enable'"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } // Handle polling loop annotation parameter iso14a_polling_frame_t pla = { - // -1 signals that PLA has to be disabled, 0 signals that no change has to be made - .frame_length = defaults ? -1 : 0, + // 0 signals that PLA has to be disabled, -1 signals that no change has to be made + .frame_length = defaults ? 0 : -1, .last_byte_bits = 8, .extra_delay = 5 }; - CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)value, sizeof(value), &vlen); - if (vlen > 0 && (strncmp((char *)value, "skip", 4) || strncmp((char *)value, "std", 3)) == 0) { - pla.frame_length = -1; - } else if (vlen > 0) { - // Convert hex string to bytes - int length = 0; - if (param_gethex_to_eol((char *)value, 0, pla.frame, sizeof(pla.frame), &length) != 0) { - PrintAndLogEx(ERR, "Error parsing polling loop annotation bytes"); - CLIParserFree(ctx); - return PM3_EINVARG; - } - pla.frame_length = length; + CLIParamStrToBuf(arg_get_str(ctx, 7), (uint8_t *)value, sizeof(value), &vlen); + if (vlen > 0) { + if (strncmp((char *)value, "std", 3) == 0) pla.frame_length = 0; + else if (strncmp((char *)value, "skip", 4) == 0) pla.frame_length = 0; + else if (strncmp((char *)value, "disable", 3) == 0) pla.frame_length = 0; + else if (strncmp((char *)value, "off", 3) == 0) pla.frame_length = 0; + else { + // Convert hex string to bytes + int length = 0; + if (param_gethex_to_eol((char *)value, 0, pla.frame, sizeof(pla.frame), &length) != 0) { + PrintAndLogEx(ERR, "Error parsing polling loop annotation bytes"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + pla.frame_length = length; - // Validate length before adding CRC - if (pla.frame_length < 1 || pla.frame_length > 22) { - PrintAndLogEx(ERR, "Polling loop annotation length invalid: min %d; max %d", 1, 22); - CLIParserFree(ctx); - return PM3_EINVARG; - } + // Validate length before adding CRC + if (pla.frame_length < 1 || pla.frame_length > 22) { + PrintAndLogEx(ERR, "Polling loop annotation length invalid: min %d; max %d", 1, 22); + CLIParserFree(ctx); + return PM3_EINVARG; + } - uint8_t first, second; - compute_crc(CRC_14443_A, pla.frame, pla.frame_length, &first, &second); - pla.frame[pla.frame_length++] = first; - pla.frame[pla.frame_length++] = second; - PrintAndLogEx(INFO, "Added CRC16A to polling loop annotation: %s", sprint_hex(pla.frame, pla.frame_length)); + uint8_t first, second; + compute_crc(CRC_14443_A, pla.frame, pla.frame_length, &first, &second); + pla.frame[pla.frame_length++] = first; + pla.frame[pla.frame_length++] = second; + PrintAndLogEx(INFO, "Added CRC16A to polling loop annotation: %s", sprint_hex(pla.frame, pla.frame_length)); + } } CLIParserFree(ctx); @@ -503,6 +496,7 @@ static int CmdHf14AConfig(const char *Cmd) { .forcecl2 = cl2, .forcecl3 = cl3, .forcerats = rats, + .magsafe = magsafe, .polling_loop_annotation = pla }; @@ -595,48 +589,12 @@ int Hf14443_4aGetCardData(iso14a_card_select_t *card) { return PM3_SUCCESS; } -iso14a_polling_parameters_t iso14a_get_polling_parameters(bool use_ecp, bool use_magsafe) { - // Extra 100ms give enough time for Apple (ECP) devices to proccess field info and make a decision - - if (use_ecp && use_magsafe) { - iso14a_polling_parameters_t full_polling_parameters = { - .frames = { WUPA_FRAME, ECP_FRAME, MAGWUPA1_FRAME, MAGWUPA2_FRAME, MAGWUPA3_FRAME, MAGWUPA4_FRAME }, - .frame_count = 6, - .extra_timeout = 100 - }; - return full_polling_parameters; - } else if (use_ecp) { - iso14a_polling_parameters_t ecp_polling_parameters = { - .frames = { WUPA_FRAME, ECP_FRAME }, - .frame_count = 2, - .extra_timeout = 100 - }; - return ecp_polling_parameters; - } else if (use_magsafe) { - iso14a_polling_parameters_t magsafe_polling_parameters = { - .frames = { WUPA_FRAME, MAGWUPA1_FRAME, MAGWUPA2_FRAME, MAGWUPA3_FRAME, MAGWUPA4_FRAME }, - .frame_count = 5, - .extra_timeout = 0 - }; - return magsafe_polling_parameters; - } - - iso14a_polling_parameters_t wupa_polling_parameters = { - .frames = { WUPA_FRAME }, - .frame_count = 1, - .extra_timeout = 0, - }; - return wupa_polling_parameters; -} - static int CmdHF14AReader(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf 14a reader", "Act as a ISO-14443a reader to identify tag. Look for ISO-14443a tags until Enter or the pm3 button is pressed", "hf 14a reader\n" "hf 14a reader -@ -> Continuous mode\n" - "hf 14a reader --ecp -> trigger apple enhanced contactless polling\n" - "hf 14a reader --mag -> trigger apple magsafe polling\n" ); void *argtable[] = { @@ -645,8 +603,6 @@ static int CmdHF14AReader(const char *Cmd) { arg_lit0("s", "silent", "silent (no messages)"), arg_lit0(NULL, "drop", "just drop the signal field"), arg_lit0(NULL, "skip", "ISO14443-3 select only (skip RATS)"), - arg_lit0(NULL, "ecp", "Use enhanced contactless polling"), - arg_lit0(NULL, "mag", "Use Apple magsafe polling"), arg_lit0("@", NULL, "continuous reader mode"), arg_lit0("w", "wait", "wait for card"), arg_param_end @@ -669,18 +625,8 @@ static int CmdHF14AReader(const char *Cmd) { cm |= ISO14A_NO_RATS; } - bool use_ecp = arg_get_lit(ctx, 5); - bool use_magsafe = arg_get_lit(ctx, 6); - - iso14a_polling_parameters_t *polling_parameters = NULL; - iso14a_polling_parameters_t parameters = iso14a_get_polling_parameters(use_ecp, use_magsafe); - if (use_ecp || use_magsafe) { - cm |= ISO14A_USE_CUSTOM_POLLING; - polling_parameters = ¶meters; - } - - bool continuous = arg_get_lit(ctx, 7); - bool wait = arg_get_lit(ctx, 8); + bool continuous = arg_get_lit(ctx, 5); + bool wait = arg_get_lit(ctx, 6); CLIParserFree(ctx); bool found = false; @@ -695,12 +641,7 @@ static int CmdHF14AReader(const char *Cmd) { int res = PM3_SUCCESS; do { clearCommandBuffer(); - - if ((cm & ISO14A_USE_CUSTOM_POLLING) == ISO14A_USE_CUSTOM_POLLING) { - SendCommandMIX(CMD_HF_ISO14443A_READER, cm, 0, 0, (uint8_t *)polling_parameters, sizeof(iso14a_polling_parameters_t)); - } else { - SendCommandMIX(CMD_HF_ISO14443A_READER, cm, 0, 0, NULL, 0); - } + SendCommandMIX(CMD_HF_ISO14443A_READER, cm, 0, 0, NULL, 0); if ((cm & ISO14A_CONNECT) == ISO14A_CONNECT) { PacketResponseNG resp; @@ -1462,9 +1403,10 @@ static int CmdHF14AAPDU(const char *Cmd) { CLIParserFree(ctx); return PM3_EINVARG; } + bool extendedAPDU = arg_get_lit(ctx, 6); int le = arg_get_int_def(ctx, 7, 0); - + uint8_t data[PM3_CMD_DATA_SIZE]; int datalen = 0; @@ -1546,7 +1488,6 @@ static int CmdHF14ACmdRaw(const char *Cmd) { "Sends raw bytes over ISO14443a. With option to use TOPAZ 14a mode.", "hf 14a raw -sc 3000 -> select, crc, where 3000 == 'read block 00'\n" "hf 14a raw -ak -b 7 40 -> send 7 bit byte 0x40\n" - "hf 14a raw --ecp -s -> send ECP before select\n" "Crypto1 session example, with special auth shortcut 6xxx:\n" "hf 14a raw --crypto1 -skc 6000FFFFFFFFFFFF\n" "hf 14a raw --crypto1 -kc 3000\n" @@ -1565,8 +1506,6 @@ static int CmdHF14ACmdRaw(const char *Cmd) { arg_int0("t", "timeout", "", "Timeout in milliseconds"), arg_int0("b", NULL, "", "Number of bits to send. Useful for send partial byte"), arg_lit0("v", "verbose", "Verbose output"), - arg_lit0(NULL, "ecp", "Use enhanced contactless polling"), - arg_lit0(NULL, "mag", "Use Apple magsafe polling"), arg_lit0(NULL, "topaz", "Use Topaz protocol to send command"), arg_lit0(NULL, "crypto1", "Use crypto1 session"), arg_strx1(NULL, NULL, "", "Raw bytes to send"), @@ -1583,14 +1522,12 @@ static int CmdHF14ACmdRaw(const char *Cmd) { uint32_t timeout = (uint32_t)arg_get_int_def(ctx, 7, 0); uint16_t numbits = (uint16_t)arg_get_int_def(ctx, 8, 0); bool verbose = arg_get_lit(ctx, 9); - bool use_ecp = arg_get_lit(ctx, 10); - bool use_magsafe = arg_get_lit(ctx, 11); - bool topazmode = arg_get_lit(ctx, 12); - bool crypto1mode = arg_get_lit(ctx, 13); + bool topazmode = arg_get_lit(ctx, 10); + bool crypto1mode = arg_get_lit(ctx, 11); int datalen = 0; uint8_t data[PM3_CMD_DATA_SIZE_MIX] = {0}; - CLIGetHexWithReturn(ctx, 14, data, &datalen); + CLIGetHexWithReturn(ctx, 12, data, &datalen); CLIParserFree(ctx); bool bTimeout = (timeout) ? true : false; @@ -1646,7 +1583,7 @@ static int CmdHF14ACmdRaw(const char *Cmd) { if (crypto1mode) { flags |= ISO14A_CRYPTO1MODE; - if (numbits > 0 || topazmode || use_ecp || use_magsafe) { + if (numbits > 0 || topazmode) { PrintAndLogEx(FAILED, "crypto1 mode cannot be used with other modes or partial bytes"); return PM3_EINVARG; } @@ -1656,13 +1593,6 @@ static int CmdHF14ACmdRaw(const char *Cmd) { flags |= ISO14A_NO_RATS; } - // TODO: allow to use reader command with both data and polling configuration - if (use_ecp || use_magsafe) { - PrintAndLogEx(WARNING, "ECP and Magsafe not supported with this command at this moment. Instead use 'hf 14a reader -sk --ecp/--mag'"); - // flags |= ISO14A_USE_MAGSAFE; - // flags |= ISO14A_USE_ECP; - } - // Max buffer is PM3_CMD_DATA_SIZE_MIX datalen = (datalen > PM3_CMD_DATA_SIZE_MIX) ? PM3_CMD_DATA_SIZE_MIX : datalen; diff --git a/client/src/cmdhf14a.h b/client/src/cmdhf14a.h index 21b33fc13..2a3bbd1e1 100644 --- a/client/src/cmdhf14a.h +++ b/client/src/cmdhf14a.h @@ -70,7 +70,6 @@ int Hf14443_4aGetCardData(iso14a_card_select_t *card); int ExchangeAPDU14a(const uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool silentMode); -iso14a_polling_parameters_t iso14a_get_polling_parameters(bool use_ecp, bool use_magsafe); int SelectCard14443A_4(bool disconnect, bool verbose, iso14a_card_select_t *card); int SelectCard14443A_4_WithParameters(bool disconnect, bool verbose, iso14a_card_select_t *card, iso14a_polling_parameters_t *polling_parameters); diff --git a/doc/commands.json b/doc/commands.json index 24da01cee..9fc3e4a6a 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -1324,7 +1324,6 @@ "notes": [ "hf 14a raw -sc 3000 -> select, crc, where 3000 == 'read block 00'", "hf 14a raw -ak -b 7 40 -> send 7 bit byte 0x40", - "hf 14a raw --ecp -s -> send ECP before select", "Crypto1 session example, with special auth shortcut 6xxx:", "hf 14a raw --crypto1 -skc 6000FFFFFFFFFFFF", "hf 14a raw --crypto1 -kc 3000", @@ -1343,13 +1342,12 @@ "-t, --timeout Timeout in milliseconds", "-b Number of bits to send. Useful for send partial byte", "-v, --verbose Verbose output", - "--ecp Use enhanced contactless polling", "--mag Use Apple magsafe polling", "--topaz Use Topaz protocol to send command", "--crypto1 Use crypto1 session", " Raw bytes to send" ], - "usage": "hf 14a raw [-hack3rsv] [-t ] [-b ] [--ecp] [--mag] [--topaz] [--crypto1] []..." + "usage": "hf 14a raw [-hack3rsv] [-t ] [-b ] [--topaz] [--crypto1] []..." }, "hf 14a reader": { "command": "hf 14a reader", @@ -1357,7 +1355,6 @@ "notes": [ "hf 14a reader", "hf 14a reader -@ -> Continuous mode", - "hf 14a reader --ecp -> trigger apple enhanced contactless polling", "hf 14a reader --mag -> trigger apple magsafe polling" ], "offline": false, @@ -1367,12 +1364,11 @@ "-s, --silent silent (no messages)", "--drop just drop the signal field", "--skip ISO14443-3 select only (skip RATS)", - "--ecp Use enhanced contactless polling", "--mag Use Apple magsafe polling", "-@ continuous reader mode", "-w, --wait wait for card" ], - "usage": "hf 14a reader [-hks@w] [--drop] [--skip] [--ecp] [--mag]" + "usage": "hf 14a reader [-hks@w] [--drop] [--skip]" }, "hf 14a sim": { "command": "hf 14a sim", diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 2c7e86898..1256e0792 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -133,7 +133,7 @@ typedef struct { // Defines a frame that will be used in a polling sequence -// Polling loop annotations are up to (7 + 16) bytes long, 24 bytes should cover future and other cases +// Polling loop annotations are up to 20 bytes long, 24 bytes should cover future and other cases typedef struct { uint8_t frame[24]; // negative values can be used to carry special info @@ -144,8 +144,8 @@ typedef struct { // Defines polling sequence configuration -// 6 would be enough for 4 magsafe, 1 wupa, 1 pla, typedef struct { + // 6 would be enough for 4 magsafe, 1 wupa, 1 pla, iso14a_polling_frame_t frames[6]; int8_t frame_count; uint16_t extra_timeout; @@ -159,6 +159,7 @@ typedef struct { int8_t forcecl2; // 0:auto 1:force executing CL2 2:force skipping CL2 int8_t forcecl3; // 0:auto 1:force executing CL3 2:force skipping CL3 int8_t forcerats; // 0:auto 1:force executing RATS 2:force skipping RATS + int8_t magsafe; // 0:disabled 1:enabled iso14a_polling_frame_t polling_loop_annotation; // Polling loop annotation } PACKED hf14a_config;