From c4f1b0768dd290026b91dfb4d9a77242fabd48a5 Mon Sep 17 00:00:00 2001 From: kormax Date: Sun, 16 Jul 2023 16:49:31 +0300 Subject: [PATCH 1/4] Pass polling config via pointer instead of by-value, thus saving RAM --- armsrc/iso14443a.c | 100 ++++++++++++++++++++++----------------------- armsrc/iso14443a.h | 8 ++-- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index da1bfbc2f..8cab781e4 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -143,62 +143,62 @@ Default HF 14a config is set to: static hf14a_config hf14aconfig = { 0, 0, 0, 0, 0 } ; -// Polling frames and configurations +// Polling frames and configurations -/*static iso14a_polling_frame REQA_FRAME = { - { 0x26 }, 1, 7, 0 +/*static iso14a_polling_frame REQA_FRAME = { + { 0x26 }, 1, 7, 0 };*/ -static const iso14a_polling_frame WUPA_FRAME = { +static const iso14a_polling_frame WUPA_FRAME = { { 0x52 }, 1, 7, 0, }; -static const iso14a_polling_frame MAGWUPA1_FRAME = { - { 0x7A }, 1, 7, 0 +static const iso14a_polling_frame MAGWUPA1_FRAME = { + { 0x7A }, 1, 7, 0 }; -static const iso14a_polling_frame MAGWUPA2_FRAME = { - { 0x7B }, 1, 7, 0 +static const iso14a_polling_frame MAGWUPA2_FRAME = { + { 0x7B }, 1, 7, 0 }; -static const iso14a_polling_frame MAGWUPA3_FRAME = { - { 0x7C }, 1, 7, 0 +static const iso14a_polling_frame MAGWUPA3_FRAME = { + { 0x7C }, 1, 7, 0 }; -static const iso14a_polling_frame MAGWUPA4_FRAME = { - { 0x7D }, 1, 7, 0 +static const iso14a_polling_frame MAGWUPA4_FRAME = { + { 0x7D }, 1, 7, 0 }; -static const iso14a_polling_frame 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 +static const iso14a_polling_frame 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 }; static iso14a_polling_parameters WUPA_POLLING_PARAMETERS = { - .frames = { WUPA_FRAME }, - .frame_count = 1, - .extra_timeout = 0, + .frames={ WUPA_FRAME }, + .frame_count=1, + .extra_timeout=0, }; static iso14a_polling_parameters MAGSAFE_POLLING_PARAMETERS = { - .frames = { WUPA_FRAME, MAGWUPA1_FRAME, MAGWUPA2_FRAME, MAGWUPA3_FRAME, MAGWUPA4_FRAME }, - .frame_count = 5, - .extra_timeout = 0 + .frames={ WUPA_FRAME, MAGWUPA1_FRAME, MAGWUPA2_FRAME, MAGWUPA3_FRAME, MAGWUPA4_FRAME }, + .frame_count=5, + .extra_timeout=0 }; // Extra 100ms give enough time for Apple devices to proccess field info and make a decision static iso14a_polling_parameters ECP_POLLING_PARAMETERS = { - .frames = { WUPA_FRAME, ECP_FRAME }, - .frame_count = 2, - .extra_timeout = 100 + .frames={ WUPA_FRAME, ECP_FRAME }, + .frame_count=2, + .extra_timeout=100 }; static iso14a_polling_parameters FULL_POLLING_PARAMETERS = { - .frames = { WUPA_FRAME, ECP_FRAME, MAGWUPA1_FRAME, MAGWUPA2_FRAME, MAGWUPA3_FRAME, MAGWUPA4_FRAME }, - .frame_count = 6, - .extra_timeout = 100 + .frames={ WUPA_FRAME, ECP_FRAME, MAGWUPA1_FRAME, MAGWUPA2_FRAME, MAGWUPA3_FRAME, MAGWUPA4_FRAME }, + .frame_count=6, + .extra_timeout=100 }; @@ -2569,33 +2569,32 @@ static void iso14a_set_ATS_times(const uint8_t *ats) { } -static int GetATQA(uint8_t *resp, uint8_t *resp_par, iso14a_polling_parameters parameters) { -#define WUPA_RETRY_TIMEOUT 10 +static int GetATQA(uint8_t *resp, uint8_t *resp_par, iso14a_polling_parameters *polling_parameters) { + #define WUPA_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. bool first_try = true; - uint32_t retry_timeout = WUPA_RETRY_TIMEOUT * parameters.frame_count + parameters.extra_timeout; + uint32_t retry_timeout = WUPA_RETRY_TIMEOUT * polling_parameters->frame_count + polling_parameters->extra_timeout; uint32_t start_time; int len; uint8_t current_frame = 0; do { - iso14a_polling_frame frame_parameters = parameters.frames[current_frame]; - - if (frame_parameters.last_byte_bits == 8) { - ReaderTransmit(frame_parameters.frame, frame_parameters.frame_length, NULL); + iso14a_polling_frame *frame_parameters = &polling_parameters->frames[current_frame]; + if (frame_parameters->last_byte_bits == 8) { + ReaderTransmit(frame_parameters->frame, frame_parameters->frame_length, NULL); } else { - ReaderTransmitBitsPar(frame_parameters.frame, frame_parameters.last_byte_bits, NULL, NULL); + ReaderTransmitBitsPar(frame_parameters->frame, frame_parameters->last_byte_bits, NULL, NULL); } - if (frame_parameters.extra_delay) { - SpinDelay(frame_parameters.extra_delay); + if (frame_parameters->extra_delay) { + SpinDelay(frame_parameters->extra_delay); } - + // Receive the ATQA len = ReaderReceive(resp, resp_par); @@ -2606,8 +2605,8 @@ static int GetATQA(uint8_t *resp, uint8_t *resp_par, iso14a_polling_parameters p first_try = false; - // Go over frame configurations - current_frame = current_frame < (parameters.frame_count - 1) ? current_frame + 1 : 0; + // Go over frame configurations, loop back when we reach the end + 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); @@ -2616,7 +2615,7 @@ static int GetATQA(uint8_t *resp, uint8_t *resp_par, iso14a_polling_parameters 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, false, false); + return iso14443a_select_cardEx(uid_ptr, p_card, cuid_ptr, anticollision, num_cascades, no_rats, &WUPA_POLLING_PARAMETERS); } @@ -2628,7 +2627,7 @@ iso14a_polling_parameters iso14a_get_polling_parameters(bool use_ecp, bool use_m return ECP_POLLING_PARAMETERS; } else if (use_magsafe) { return MAGSAFE_POLLING_PARAMETERS; - } + } return WUPA_POLLING_PARAMETERS; } @@ -2638,7 +2637,7 @@ iso14a_polling_parameters iso14a_get_polling_parameters(bool use_ecp, bool use_m // if anticollision is false, then the UID must be provided in uid_ptr[] // and num_cascades must be set (1: 4 Byte UID, 2: 7 Byte UID, 3: 10 Byte UID) // requests ATS unless no_rats is true -int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats, bool use_ecp, bool use_magsafe) { +int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats, iso14a_polling_parameters *polling_parameters) { uint8_t resp[MAX_FRAME_SIZE] = {0}; // theoretically. A usual RATS will be much smaller uint8_t resp_par[MAX_PARITY_SIZE] = {0}; @@ -2653,7 +2652,7 @@ int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint p_card->ats_len = 0; } - if (GetATQA(resp, resp_par, iso14a_get_polling_parameters(use_ecp, use_magsafe)) == false) { + if (GetATQA(resp, resp_par, polling_parameters) == false) { return 0; } @@ -2678,11 +2677,11 @@ int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint memcpy(p_card->uid, resp, 4); // select again? - if (GetATQA(resp, resp_par, WUPA_POLLING_PARAMETERS) == false) { + if (GetATQA(resp, resp_par, &WUPA_POLLING_PARAMETERS) == false) { return 0; } - if (GetATQA(resp, resp_par, WUPA_POLLING_PARAMETERS) == false) { + if (GetATQA(resp, resp_par, &WUPA_POLLING_PARAMETERS) == false) { return 0; } @@ -2881,7 +2880,7 @@ int iso14443a_fast_select_card(uint8_t *uid_ptr, uint8_t num_cascades) { uint8_t sak = 0x04; // cascade uid int cascade_level = 0; - if (!GetATQA(resp, resp_par, WUPA_POLLING_PARAMETERS)) { + if (!GetATQA(resp, resp_par, &WUPA_POLLING_PARAMETERS)) { return 0; } @@ -3089,7 +3088,8 @@ void ReaderIso14443a(PacketCommandNG *c) { // if failed selecting, turn off antenna and quite. if (!(param & ISO14A_NO_SELECT)) { iso14a_card_select_t *card = (iso14a_card_select_t *)buf; - arg0 = iso14443a_select_cardEx(NULL, card, NULL, true, 0, (param & ISO14A_NO_RATS), (param & ISO14A_USE_ECP), (param & ISO14A_USE_MAGSAFE)); + iso14a_polling_parameters polling_parameters = iso14a_get_polling_parameters(param & ISO14A_USE_ECP, param & ISO14A_USE_MAGSAFE); + arg0 = iso14443a_select_cardEx(NULL, card, NULL, true, 0, (param & ISO14A_NO_RATS), &polling_parameters); FpgaDisableTracing(); reply_mix(CMD_ACK, arg0, card->uidlen, 0, buf, sizeof(iso14a_card_select_t)); diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index 80a223379..98793a02f 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -120,9 +120,9 @@ typedef struct { // Defines polling sequence configuration // 4 magsafe, 1 wupa, 1 reqa, 1 ecp, 1 extra typedef struct { - iso14a_polling_frame frames[8]; - uint8_t frame_count; - uint16_t extra_timeout; + iso14a_polling_frame frames[8]; + uint8_t frame_count; + uint16_t extra_timeout; } iso14a_polling_parameters; @@ -170,7 +170,7 @@ iso14a_polling_parameters iso14a_get_polling_parameters(bool use_ecp, bool use_m void iso14443a_setup(uint8_t fpga_minor_mode); int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, uint8_t *res); 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); -int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats, bool use_ecp, bool use_magsafe); +int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats, iso14a_polling_parameters *polling_parameters); int iso14443a_fast_select_card(uint8_t *uid_ptr, uint8_t num_cascades); void iso14a_set_trigger(bool enable); From 45ca9ab4d6e7f492ea8d0880231e80a8a33fa6e0 Mon Sep 17 00:00:00 2001 From: kormax Date: Sun, 16 Jul 2023 16:56:07 +0300 Subject: [PATCH 2/4] Reduce struct memory footprint by reducing array sizes --- armsrc/iso14443a.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index 98793a02f..abe04ac46 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -109,18 +109,18 @@ typedef enum { } resp_index_t; // Defines a frame that will be used in a polling sequence -// ECP Frames are up to (7 + 16) bytes long, this config should cover future and other cases +// ECP Frames are up to (7 + 16) bytes long, 24 bytes should cover future and other cases typedef struct { - uint8_t frame[32]; + uint8_t frame[24]; uint8_t frame_length; uint8_t last_byte_bits; uint16_t extra_delay; } iso14a_polling_frame; // Defines polling sequence configuration -// 4 magsafe, 1 wupa, 1 reqa, 1 ecp, 1 extra +// 6 would be enough for 4 magsafe, 1 wupa, 1 ecp, typedef struct { - iso14a_polling_frame frames[8]; + iso14a_polling_frame frames[6]; uint8_t frame_count; uint16_t extra_timeout; } iso14a_polling_parameters; From a9cba025144419b8bf7b1ac784888ceca43b0722 Mon Sep 17 00:00:00 2001 From: kormax Date: Sun, 16 Jul 2023 17:39:32 +0300 Subject: [PATCH 3/4] Move custom polling frame generation logic to client --- armsrc/iso14443a.c | 65 ++++----------------------------- armsrc/iso14443a.h | 19 ---------- client/src/cmdhf14a.c | 83 +++++++++++++++++++++++++++++++++++++++---- client/src/cmdhf14a.h | 1 + include/mifare.h | 20 ++++++++++- 5 files changed, 102 insertions(+), 86 deletions(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 8cab781e4..3619155da 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -145,61 +145,16 @@ static hf14a_config hf14aconfig = { 0, 0, 0, 0, 0 } ; // Polling frames and configurations -/*static iso14a_polling_frame REQA_FRAME = { - { 0x26 }, 1, 7, 0 -};*/ - static const iso14a_polling_frame WUPA_FRAME = { { 0x52 }, 1, 7, 0, }; -static const iso14a_polling_frame MAGWUPA1_FRAME = { - { 0x7A }, 1, 7, 0 -}; - -static const iso14a_polling_frame MAGWUPA2_FRAME = { - { 0x7B }, 1, 7, 0 -}; - -static const iso14a_polling_frame MAGWUPA3_FRAME = { - { 0x7C }, 1, 7, 0 -}; - -static const iso14a_polling_frame MAGWUPA4_FRAME = { - { 0x7D }, 1, 7, 0 -}; - -static const iso14a_polling_frame 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 -}; - static iso14a_polling_parameters WUPA_POLLING_PARAMETERS = { .frames={ WUPA_FRAME }, .frame_count=1, .extra_timeout=0, }; -static iso14a_polling_parameters MAGSAFE_POLLING_PARAMETERS = { - .frames={ WUPA_FRAME, MAGWUPA1_FRAME, MAGWUPA2_FRAME, MAGWUPA3_FRAME, MAGWUPA4_FRAME }, - .frame_count=5, - .extra_timeout=0 -}; - -// Extra 100ms give enough time for Apple devices to proccess field info and make a decision -static iso14a_polling_parameters ECP_POLLING_PARAMETERS = { - .frames={ WUPA_FRAME, ECP_FRAME }, - .frame_count=2, - .extra_timeout=100 -}; - -static iso14a_polling_parameters FULL_POLLING_PARAMETERS = { - .frames={ WUPA_FRAME, ECP_FRAME, MAGWUPA1_FRAME, MAGWUPA2_FRAME, MAGWUPA3_FRAME, MAGWUPA4_FRAME }, - .frame_count=6, - .extra_timeout=100 -}; void printHf14aConfig(void) { @@ -2619,18 +2574,6 @@ int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32 } -// This method is temporary. Main intention is to move "special" polling frame configuration to the client -iso14a_polling_parameters iso14a_get_polling_parameters(bool use_ecp, bool use_magsafe) { - if (use_ecp && use_magsafe) { - return FULL_POLLING_PARAMETERS; - } else if (use_ecp) { - return ECP_POLLING_PARAMETERS; - } else if (use_magsafe) { - return MAGSAFE_POLLING_PARAMETERS; - } - return WUPA_POLLING_PARAMETERS; -} - // performs iso14443a anticollision (optional) and card select procedure // fills the uid and cuid pointer unless NULL // fills the card info record unless NULL @@ -3088,8 +3031,12 @@ void ReaderIso14443a(PacketCommandNG *c) { // if failed selecting, turn off antenna and quite. if (!(param & ISO14A_NO_SELECT)) { iso14a_card_select_t *card = (iso14a_card_select_t *)buf; - iso14a_polling_parameters polling_parameters = iso14a_get_polling_parameters(param & ISO14A_USE_ECP, param & ISO14A_USE_MAGSAFE); - arg0 = iso14443a_select_cardEx(NULL, card, NULL, true, 0, (param & ISO14A_NO_RATS), &polling_parameters); + + arg0 = iso14443a_select_cardEx( + NULL, card, NULL, true, 0, (param & ISO14A_NO_RATS), + (param & ISO14A_USE_CUSTOM_POLLING) ? (iso14a_polling_parameters *)cmd : &WUPA_POLLING_PARAMETER + ); + // This can be improved by adding a cmd parser pointer and moving it by struct length to allow combining data with polling params FpgaDisableTracing(); reply_mix(CMD_ACK, arg0, card->uidlen, 0, buf, sizeof(iso14a_card_select_t)); diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index abe04ac46..817ee7df4 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -108,24 +108,6 @@ typedef enum { RESP_INDEX_PACK, } resp_index_t; -// Defines a frame that will be used in a polling sequence -// ECP Frames are up to (7 + 16) bytes long, 24 bytes should cover future and other cases -typedef struct { - uint8_t frame[24]; - uint8_t frame_length; - uint8_t last_byte_bits; - uint16_t extra_delay; -} iso14a_polling_frame; - -// Defines polling sequence configuration -// 6 would be enough for 4 magsafe, 1 wupa, 1 ecp, -typedef struct { - iso14a_polling_frame frames[6]; - uint8_t frame_count; - uint16_t extra_timeout; -} iso14a_polling_parameters; - - #ifndef AddCrc14A # define AddCrc14A(data, len) compute_crc(CRC_14443_A, (data), (len), (data)+(len), (data)+(len)+1) #endif @@ -166,7 +148,6 @@ void ReaderTransmitBitsPar(uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t void ReaderTransmitPar(uint8_t *frame, uint16_t len, uint8_t *par, uint32_t *timing); uint16_t ReaderReceive(uint8_t *receivedAnswer, uint8_t *par); -iso14a_polling_parameters iso14a_get_polling_parameters(bool use_ecp, bool use_magsafe); void iso14443a_setup(uint8_t fpga_minor_mode); int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, uint8_t *res); 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); diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index a8ec8a60d..61423cc48 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -434,6 +434,71 @@ int Hf14443_4aGetCardData(iso14a_card_select_t *card) { return 0; } +iso14a_polling_parameters iso14a_get_polling_parameters(bool use_ecp, bool use_magsafe) { + + iso14a_polling_frame WUPA_FRAME = { + { 0x52 }, 1, 7, 0, + }; + + iso14a_polling_frame MAGWUPA1_FRAME = { + { 0x7A }, 1, 7, 0 + }; + + iso14a_polling_frame MAGWUPA2_FRAME = { + { 0x7B }, 1, 7, 0 + }; + + iso14a_polling_frame MAGWUPA3_FRAME = { + { 0x7C }, 1, 7, 0 + }; + + iso14a_polling_frame MAGWUPA4_FRAME = { + { 0x7D }, 1, 7, 0 + }; + + iso14a_polling_frame 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 + }; + + iso14a_polling_parameters WUPA_POLLING_PARAMETERS = { + .frames={ WUPA_FRAME }, + .frame_count=1, + .extra_timeout=0, + }; + + iso14a_polling_parameters MAGSAFE_POLLING_PARAMETERS = { + .frames={ WUPA_FRAME, MAGWUPA1_FRAME, MAGWUPA2_FRAME, MAGWUPA3_FRAME, MAGWUPA4_FRAME }, + .frame_count=5, + .extra_timeout=0 + }; + + // Extra 100ms give enough time for Apple devices to proccess field info and make a decision + iso14a_polling_parameters ECP_POLLING_PARAMETERS = { + .frames={ WUPA_FRAME, ECP_FRAME }, + .frame_count=2, + .extra_timeout=100 + }; + + iso14a_polling_parameters FULL_POLLING_PARAMETERS = { + .frames={ WUPA_FRAME, ECP_FRAME, MAGWUPA1_FRAME, MAGWUPA2_FRAME, MAGWUPA3_FRAME, MAGWUPA4_FRAME }, + .frame_count=6, + .extra_timeout=100 + }; + + if (use_ecp && use_magsafe) { + return FULL_POLLING_PARAMETERS; + } else if (use_ecp) { + return ECP_POLLING_PARAMETERS; + } else if (use_magsafe) { + return MAGSAFE_POLLING_PARAMETERS; + } + return WUPA_POLLING_PARAMETERS; +} + + static int CmdHF14AReader(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf 14a reader", @@ -473,12 +538,10 @@ static int CmdHF14AReader(const char *Cmd) { cm |= ISO14A_NO_RATS; } - if (arg_get_lit(ctx, 5)) { - cm |= ISO14A_USE_ECP; - } - - if (arg_get_lit(ctx, 6)) { - cm |= ISO14A_USE_MAGSAFE; + iso14a_polling_parameters polling_parameters; + if (arg_get_lit(ctx, 5) || arg_get_lit(ctx, 6)) { + cm |= ISO14A_USE_CUSTOM_POLLING; + polling_parameters = iso14a_get_polling_parameters(arg_get_lit(ctx, 5), arg_get_lit(ctx, 6)); } bool continuous = arg_get_lit(ctx, 7); @@ -494,7 +557,13 @@ static int CmdHF14AReader(const char *Cmd) { } do { clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO14443A_READER, cm, 0, 0, NULL, 0); + + if (cm & ISO14A_USE_CUSTOM_POLLING) { + SendCommandMIX(CMD_HF_ISO14443A_READER, cm, 0, 0, (uint8_t *)&polling_parameters, sizeof(polling_parameters)); + } else { + SendCommandMIX(CMD_HF_ISO14443A_READER, cm, 0, 0, NULL, 0); + } + if (ISO14A_CONNECT & cm) { PacketResponseNG resp; diff --git a/client/src/cmdhf14a.h b/client/src/cmdhf14a.h index a811db66b..ff6d80318 100644 --- a/client/src/cmdhf14a.h +++ b/client/src/cmdhf14a.h @@ -52,6 +52,7 @@ int Hf14443_4aGetCardData(iso14a_card_select_t *card); int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool silentMode); +iso14a_polling_parameters iso14a_get_polling_parameters(bool use_ecp, bool use_magsafe); int SelectCard14443A_4(bool disconnect, bool verbose, iso14a_card_select_t *card); bool Get_apdu_in_framing(void); diff --git a/include/mifare.h b/include/mifare.h index e66df50aa..cf3b51511 100644 --- a/include/mifare.h +++ b/include/mifare.h @@ -75,9 +75,27 @@ typedef enum ISO14A_COMMAND { ISO14A_NO_RATS = (1 << 9), ISO14A_SEND_CHAINING = (1 << 10), ISO14A_USE_ECP = (1 << 11), - ISO14A_USE_MAGSAFE = (1 << 12) + ISO14A_USE_MAGSAFE = (1 << 12), + ISO14A_USE_CUSTOM_POLLING = (1 << 13) } iso14a_command_t; +// Defines a frame that will be used in a polling sequence +// ECP Frames are up to (7 + 16) bytes long, 24 bytes should cover future and other cases +typedef struct { + uint8_t frame[24]; + uint8_t frame_length; + uint8_t last_byte_bits; + uint16_t extra_delay; +} iso14a_polling_frame; + +// Defines polling sequence configuration +// 6 would be enough for 4 magsafe, 1 wupa, 1 ecp, +typedef struct { + iso14a_polling_frame frames[6]; + uint8_t frame_count; + uint16_t extra_timeout; +} iso14a_polling_parameters; + typedef struct { uint8_t *response; uint8_t *modulation; From 7f5e1c9657874b9de7fcad3d1ce87d60adc38cd8 Mon Sep 17 00:00:00 2001 From: kormax Date: Sun, 16 Jul 2023 19:27:38 +0300 Subject: [PATCH 4/4] Move custom polling frame generation logic to client --- armsrc/iso14443a.c | 12 +--- client/src/cmdhf14a.c | 151 ++++++++++++++++++++++-------------------- client/src/cmdhf14a.h | 1 + client/src/cmdhfvas.c | 28 ++++++-- include/mifare.h | 1 - 5 files changed, 105 insertions(+), 88 deletions(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 3619155da..4bb51f69b 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -144,19 +144,13 @@ static hf14a_config hf14aconfig = { 0, 0, 0, 0, 0 } ; // Polling frames and configurations - -static const iso14a_polling_frame WUPA_FRAME = { - { 0x52 }, 1, 7, 0, -}; - static iso14a_polling_parameters WUPA_POLLING_PARAMETERS = { - .frames={ WUPA_FRAME }, + .frames={ {{ 0x52 }, 1, 7, 0} }, .frame_count=1, .extra_timeout=0, }; - void printHf14aConfig(void) { DbpString(_CYAN_("HF 14a config")); Dbprintf(" [a] Anticol override.... %s%s%s", @@ -3034,9 +3028,9 @@ void ReaderIso14443a(PacketCommandNG *c) { arg0 = iso14443a_select_cardEx( NULL, card, NULL, true, 0, (param & ISO14A_NO_RATS), - (param & ISO14A_USE_CUSTOM_POLLING) ? (iso14a_polling_parameters *)cmd : &WUPA_POLLING_PARAMETER + (param & ISO14A_USE_CUSTOM_POLLING) ? (iso14a_polling_parameters *)cmd : &WUPA_POLLING_PARAMETERS ); - // This can be improved by adding a cmd parser pointer and moving it by struct length to allow combining data with polling params + // TODO: Improve by adding a cmd parser pointer and moving it by struct length to allow combining data with polling params FpgaDisableTracing(); reply_mix(CMD_ACK, arg0, card->uidlen, 0, buf, sizeof(iso14a_card_select_t)); diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 61423cc48..bf1ded102 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -54,6 +54,35 @@ void Set_apdu_in_framing(bool v) { static int CmdHelp(const char *Cmd); static int waitCmd(bool i_select, uint32_t timeout, bool verbose); + +static const iso14a_polling_frame WUPA_FRAME = { + { 0x52 }, 1, 7, 0, +}; + +static const iso14a_polling_frame MAGWUPA1_FRAME = { + { 0x7A }, 1, 7, 0 +}; + +static const iso14a_polling_frame MAGWUPA2_FRAME = { + { 0x7B }, 1, 7, 0 +}; + +static const iso14a_polling_frame MAGWUPA3_FRAME = { + { 0x7C }, 1, 7, 0 +}; + +static const iso14a_polling_frame MAGWUPA4_FRAME = { + { 0x7D }, 1, 7, 0 +}; + +static const iso14a_polling_frame 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 +}; + + static const manufactureName_t manufactureMapping[] = { // ID, "Vendor Country" { 0x01, "Motorola UK" }, @@ -435,67 +464,37 @@ int Hf14443_4aGetCardData(iso14a_card_select_t *card) { } iso14a_polling_parameters 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 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 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 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_frame WUPA_FRAME = { - { 0x52 }, 1, 7, 0, - }; - - iso14a_polling_frame MAGWUPA1_FRAME = { - { 0x7A }, 1, 7, 0 - }; - - iso14a_polling_frame MAGWUPA2_FRAME = { - { 0x7B }, 1, 7, 0 - }; - - iso14a_polling_frame MAGWUPA3_FRAME = { - { 0x7C }, 1, 7, 0 - }; - - iso14a_polling_frame MAGWUPA4_FRAME = { - { 0x7D }, 1, 7, 0 - }; - - iso14a_polling_frame 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 - }; - - iso14a_polling_parameters WUPA_POLLING_PARAMETERS = { + iso14a_polling_parameters wupa_polling_parameters = { .frames={ WUPA_FRAME }, .frame_count=1, .extra_timeout=0, }; - - iso14a_polling_parameters MAGSAFE_POLLING_PARAMETERS = { - .frames={ WUPA_FRAME, MAGWUPA1_FRAME, MAGWUPA2_FRAME, MAGWUPA3_FRAME, MAGWUPA4_FRAME }, - .frame_count=5, - .extra_timeout=0 - }; - - // Extra 100ms give enough time for Apple devices to proccess field info and make a decision - iso14a_polling_parameters ECP_POLLING_PARAMETERS = { - .frames={ WUPA_FRAME, ECP_FRAME }, - .frame_count=2, - .extra_timeout=100 - }; - - iso14a_polling_parameters FULL_POLLING_PARAMETERS = { - .frames={ WUPA_FRAME, ECP_FRAME, MAGWUPA1_FRAME, MAGWUPA2_FRAME, MAGWUPA3_FRAME, MAGWUPA4_FRAME }, - .frame_count=6, - .extra_timeout=100 - }; - - if (use_ecp && use_magsafe) { - return FULL_POLLING_PARAMETERS; - } else if (use_ecp) { - return ECP_POLLING_PARAMETERS; - } else if (use_magsafe) { - return MAGSAFE_POLLING_PARAMETERS; - } - return WUPA_POLLING_PARAMETERS; + return wupa_polling_parameters; } @@ -538,10 +537,14 @@ static int CmdHF14AReader(const char *Cmd) { cm |= ISO14A_NO_RATS; } - iso14a_polling_parameters polling_parameters; - if (arg_get_lit(ctx, 5) || arg_get_lit(ctx, 6)) { + bool use_ecp = arg_get_lit(ctx, 5); + bool use_magsafe = arg_get_lit(ctx, 6); + + iso14a_polling_parameters * polling_parameters = NULL; + iso14a_polling_parameters parameters = iso14a_get_polling_parameters(use_ecp, use_magsafe); + if (use_ecp || use_magsafe) { cm |= ISO14A_USE_CUSTOM_POLLING; - polling_parameters = iso14a_get_polling_parameters(arg_get_lit(ctx, 5), arg_get_lit(ctx, 6)); + polling_parameters = ¶meters; } bool continuous = arg_get_lit(ctx, 7); @@ -559,7 +562,7 @@ static int CmdHF14AReader(const char *Cmd) { clearCommandBuffer(); if (cm & ISO14A_USE_CUSTOM_POLLING) { - SendCommandMIX(CMD_HF_ISO14443A_READER, cm, 0, 0, (uint8_t *)&polling_parameters, sizeof(polling_parameters)); + SendCommandMIX(CMD_HF_ISO14443A_READER, cm, 0, 0, (uint8_t *)polling_parameters, sizeof(iso14a_polling_parameters)); } else { SendCommandMIX(CMD_HF_ISO14443A_READER, cm, 0, 0, NULL, 0); } @@ -900,7 +903,6 @@ int CmdHF14ASniff(const char *Cmd) { } int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool silentMode) { - uint16_t cmdc = 0; *dataoutlen = 0; @@ -962,8 +964,7 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav return 0; } -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 *polling_parameters) { // global vars should be prefixed with g_ gs_frame_len = 0; gs_frames_num = 0; @@ -976,7 +977,12 @@ int SelectCard14443A_4(bool disconnect, bool verbose, iso14a_card_select_t *card // Anticollision + SELECT card PacketResponseNG resp; - SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); + if (polling_parameters != NULL) { + SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT | ISO14A_USE_CUSTOM_POLLING, 0, 0, (uint8_t *)polling_parameters, sizeof(iso14a_polling_parameters)); + } else { + SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); + } + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) { PrintAndLogEx(WARNING, "Command execute timeout"); return PM3_ETIMEOUT; @@ -1042,6 +1048,10 @@ int SelectCard14443A_4(bool disconnect, bool verbose, iso14a_card_select_t *card return PM3_SUCCESS; } +int SelectCard14443A_4(bool disconnect, bool verbose, iso14a_card_select_t *card) { + return SelectCard14443A_4_WithParameters(disconnect, verbose, card, NULL); +} + static int CmdExchangeAPDU(bool chainingin, uint8_t *datain, int datainlen, bool activateField, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool *chainingout) { *chainingout = false; @@ -1423,14 +1433,13 @@ static int CmdHF14ACmdRaw(const char *Cmd) { flags |= ISO14A_NO_RATS; } - if (use_ecp) { - flags |= ISO14A_USE_ECP; + // 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; } - - if (use_magsafe) { - flags |= ISO14A_USE_MAGSAFE; - } - + // Max buffer is PM3_CMD_DATA_SIZE datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen; diff --git a/client/src/cmdhf14a.h b/client/src/cmdhf14a.h index ff6d80318..8d0c1d8bc 100644 --- a/client/src/cmdhf14a.h +++ b/client/src/cmdhf14a.h @@ -54,6 +54,7 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav iso14a_polling_parameters 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 *polling_parameters); bool Get_apdu_in_framing(void); void Set_apdu_in_framing(bool v); diff --git a/client/src/cmdhfvas.c b/client/src/cmdhfvas.c index 2bb5c8341..1a0dca54e 100644 --- a/client/src/cmdhfvas.c +++ b/client/src/cmdhfvas.c @@ -41,7 +41,20 @@ #include "mbedtls/ecc_point_compression.h" #include "mbedtls/gcm.h" -uint8_t ecpData[] = { 0x6a, 0x01, 0x00, 0x00, 0x04 }; +static const iso14a_polling_frame WUPA_FRAME = { + .frame={ 0x52 }, + .frame_length=1, + .last_byte_bits=7, + .extra_delay=0, +}; + +static const iso14a_polling_frame ECP_VAS_ONLY_FRAME = { + .frame={0x6a, 0x01, 0x00, 0x00, 0x02, 0xe4, 0xd2}, + .frame_length=7, + .last_byte_bits=8, + .extra_delay=0, +}; + uint8_t aid[] = { 0x4f, 0x53, 0x45, 0x2e, 0x56, 0x41, 0x53, 0x2e, 0x30, 0x31 }; uint8_t getVasUrlOnlyP2 = 0x00; uint8_t getVasFullReqP2 = 0x01; @@ -336,12 +349,13 @@ static int DecryptVASCryptogram(uint8_t *pidHash, uint8_t *cryptogram, size_t cr static int VASReader(uint8_t *pidHash, const char *url, size_t urlLen, uint8_t *cryptogram, size_t *cryptogramLen, bool verbose) { clearCommandBuffer(); - uint16_t flags = ISO14A_RAW | ISO14A_CONNECT | ISO14A_NO_SELECT | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT; - SendCommandMIX(CMD_HF_ISO14443A_READER, flags, sizeof(ecpData), 0, ecpData, sizeof(ecpData)); + iso14a_polling_parameters polling_parameters = { + .frames={ WUPA_FRAME, ECP_VAS_ONLY_FRAME }, + .frame_count=2, + .extra_timeout=250 + }; - msleep(160); - - if (SelectCard14443A_4(false, false, NULL) != PM3_SUCCESS) { + if (SelectCard14443A_4_WithParameters(false, false, NULL, &polling_parameters) != PM3_SUCCESS) { PrintAndLogEx(FAILED, "No card in field"); return PM3_ECARDEXCHANGE; } @@ -349,7 +363,7 @@ static int VASReader(uint8_t *pidHash, const char *url, size_t urlLen, uint8_t * uint16_t status = 0; size_t resLen = 0; uint8_t selectResponse[APDU_RES_LEN] = {0}; - Iso7816Select(CC_CONTACTLESS, true, true, aid, sizeof(aid), selectResponse, APDU_RES_LEN, &resLen, &status); + Iso7816Select(CC_CONTACTLESS, false, true, aid, sizeof(aid), selectResponse, APDU_RES_LEN, &resLen, &status); if (status != 0x9000) { PrintAndLogEx(FAILED, "Card doesn't support VAS"); diff --git a/include/mifare.h b/include/mifare.h index cf3b51511..3bb8c9ba8 100644 --- a/include/mifare.h +++ b/include/mifare.h @@ -155,5 +155,4 @@ typedef struct { } state; } PACKED nonces_t; - #endif // _MIFARE_H_