From 2981dd94f7648c4215d0bd56f29a8aad09559e40 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 16 Jan 2024 15:12:16 +0100 Subject: [PATCH] had to keep track if the field is on or off on deviceside for 14b raw.\nAdded picopass ISO14443-B anticollision. It allows us to send raw packages over 14b. --- CHANGELOG.md | 1 + armsrc/iclass.c | 5 -- armsrc/iclass.h | 7 ++ armsrc/iso14443b.c | 150 ++++++++++++++++++++++++++++++++++++++- client/src/cmdhf14b.c | 93 ++++++++++++++++++++---- client/src/cmdhficlass.c | 4 +- 6 files changed, 239 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a53be3e8..6bc91ec89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Added `hf 14b raw --pico` - now supports picopass anticollision over ISO14443-B (@iceman1001) - Changed `hf 14b *` - worked apdu and comms. Improved output. Uses NG packets (@iceman1001) - Fixed `data manrawdecode` - now copy to demodbuf even if em4100 decode fails (@iceman1001) - Changed `nfc decode` - now supports Android Managed Provision NDEF message decoding (@iceman1001) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 283577e3a..ca63c5c93 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -43,11 +43,6 @@ uint8_t get_pagemap(const picopass_hdr_t *hdr) { return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3; } -// The length of a received command will in most cases be no more than 18 bytes. -// we expect max 34 (32+2) bytes as tag answer (response to READ4) -#ifndef ICLASS_BUFFER_SIZE -#define ICLASS_BUFFER_SIZE 34 + 2 -#endif #ifndef ICLASS_16KS_SIZE #define ICLASS_16KS_SIZE 0x100 * 8 diff --git a/armsrc/iclass.h b/armsrc/iclass.h index 30846ff36..4a71780bb 100644 --- a/armsrc/iclass.h +++ b/armsrc/iclass.h @@ -36,6 +36,13 @@ #define ICLASS_READER_TIMEOUT_UPDATE 3390 // 16000us, nominal 4-15ms #define ICLASS_READER_TIMEOUT_OTHERS 80 // 380us, nominal 330us +// The length of a received command will in most cases be no more than 18 bytes. +// we expect max 34 (32+2) bytes as tag answer (response to READ4) +#ifndef ICLASS_BUFFER_SIZE +#define ICLASS_BUFFER_SIZE 34 + 2 +#endif + + #define AddCrc(data, len) compute_crc(CRC_ICLASS, (data), (len), (data)+(len), (data)+(len)+1) void SniffIClass(uint8_t jam_search_len, uint8_t *jam_search_string); diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 950f13ecb..1c9e94983 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -34,6 +34,7 @@ #include "dbprint.h" #include "ticks.h" #include "iso14b.h" // defines for ETU conversions +#include "iclass.h" // picopass buffer defines /* * Current timing issues with ISO14443-b implementation @@ -196,6 +197,8 @@ static uint8_t s_iso14b_pcb_blocknum = 0; static uint8_t s_iso14b_fwt = 9; static uint32_t s_iso14b_timeout = MAX_14B_TIMEOUT; +static bool s_field_on = false; + /* * ISO 14443-B communications * -------------------------- @@ -2115,6 +2118,132 @@ int iso14443b_select_card(iso14b_card_select_t *card) { return PM3_SUCCESS; } +static int iso14443b_select_picopass_card(picopass_hdr_t *hdr) { + + static uint8_t act_all[] = { ICLASS_CMD_ACTALL }; + static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY }; + static uint8_t read_conf[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22 }; + uint8_t select[] = { 0x80 | ICLASS_CMD_SELECT, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t read_aia[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64}; + uint8_t read_check_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; + uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; + + uint32_t start_time = 0; + uint32_t eof_time = 0; + uint16_t retlen = 0; + + // first, wake up the tag 0x0A + CodeAndTransmit14443bAsReader(act_all, sizeof(act_all), &start_time, &eof_time, true); + eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; + + // 0x0C + // start_time = eof_time + ISO14B_TR2; + start_time = eof_time + US_TO_SSP(1000); // 330ms before next cmd + CodeAndTransmit14443bAsReader(identify, sizeof(identify), &start_time, &eof_time, true); + eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; + + // expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC + if (Get14443bAnswerFromTag(resp, sizeof(resp), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { + return PM3_ECARDEXCHANGE; + } + if (retlen != 10) { + return PM3_ELENGTH; + } + + // copy the Anti-collision CSN to our select-packet + memcpy(&select[1], resp, 8); + + // select the card + start_time = eof_time + ISO14B_TR2; + CodeAndTransmit14443bAsReader(select, sizeof(select), &start_time, &eof_time, true); + eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; + + // expect a 10-byte response here, 8 byte CSN and 2 byte CRC + if (Get14443bAnswerFromTag(resp, sizeof(resp), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { + return PM3_ECARDEXCHANGE; + } + if (retlen != 10) { + return PM3_ELENGTH; + } + + // save CSN + memcpy(hdr->csn, resp, sizeof(hdr->csn)); + + // card selected, now read config (block1) (only 8 bytes no CRC) + start_time = eof_time + ISO14B_TR2; + CodeAndTransmit14443bAsReader(read_conf, sizeof(read_conf), &start_time, &eof_time, true); + eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; + + // expect a 10-byte response here, 8 bytes CONFIGURATION and 2 byte CRC) + if (Get14443bAnswerFromTag(resp, sizeof(resp), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { + return PM3_ECARDEXCHANGE; + } + if (retlen != 10) { + return PM3_ELENGTH; + } + + // save CONF + memcpy((uint8_t *)&hdr->conf, resp, sizeof(hdr->conf)); + + uint8_t pagemap = get_pagemap(hdr); + if (pagemap != PICOPASS_NON_SECURE_PAGEMODE) { + + // read App Issuer Area block 5 + start_time = eof_time + ISO14B_TR2; + CodeAndTransmit14443bAsReader(read_aia, sizeof(read_aia), &start_time, &eof_time, true); + eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; + + // expect AIA, a 10-byte response here + if (Get14443bAnswerFromTag(resp, sizeof(resp), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { + return PM3_ECARDEXCHANGE; + } + if (retlen != 10) { + return PM3_ELENGTH; + } + + memcpy(hdr->app_issuer_area, resp, sizeof(hdr->app_issuer_area)); + + // card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC) + start_time = eof_time + ISO14B_TR2; + CodeAndTransmit14443bAsReader(read_check_cc, sizeof(read_check_cc), &start_time, &eof_time, true); + eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; + + // expect EPURSE, a 8 byte response here + if (Get14443bAnswerFromTag(resp, sizeof(resp), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { + return PM3_ECARDEXCHANGE; + } + if (retlen != 8) { + return PM3_ELENGTH; + } + + memcpy(hdr->epurse, resp, sizeof(hdr->epurse)); + + } else { + + // on NON_SECURE_PAGEMODE cards, AIA is on block2.. + + // read App Issuer Area block 2 + read_aia[1] = 0x02; + read_aia[2] = 0x61; + read_aia[3] = 0x10; + + start_time = eof_time + ISO14B_TR2; + CodeAndTransmit14443bAsReader(read_aia, sizeof(read_aia), &start_time, &eof_time, true); + eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; + + // expect AIA, a 10-byte response here + if (Get14443bAnswerFromTag(resp, sizeof(resp), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { + return PM3_ECARDEXCHANGE; + } + if (retlen != 10) { + return PM3_ELENGTH; + } + + memcpy(hdr->epurse, resp, sizeof(hdr->epurse)); + } + return PM3_SUCCESS; +} + // Set up ISO 14443 Type B communication (similar to iso14443a_setup) // field is setup for "Sending as Reader" void iso14443b_setup(void) { @@ -2152,6 +2281,8 @@ void iso14443b_setup(void) { // reset timeout iso14b_set_fwt(8); + s_field_on = true; + LED_D_ON(); } @@ -2471,7 +2602,23 @@ void SendRawCommand14443B(iso14b_raw_cmd_t *p) { sendlen = sizeof(iso14b_cts_card_select_t); status = iso14443b_select_cts_card(cts); reply_ng(CMD_HF_ISO14443B_COMMAND, status, (uint8_t *)cts, sendlen); - if (status > PM3_SUCCESS) goto out; + if (status != PM3_SUCCESS) goto out; + } + + if ((p->flags & ISO14B_SELECT_PICOPASS) == ISO14B_SELECT_PICOPASS) { + picopass_hdr_t *hdr = (picopass_hdr_t *)buf; + memset(hdr, 0, sizeof(picopass_hdr_t)); + sendlen = sizeof(picopass_hdr_t); + status = iso14443b_select_picopass_card(hdr); + reply_ng(CMD_HF_ISO14443B_COMMAND, status, (uint8_t *)hdr, sendlen); + if (status != PM3_SUCCESS) goto out; + } + + // if field is off... + if (s_field_on == false) { + DbpString("Field is off"); + reply_ng(CMD_HF_ISO14443B_COMMAND, PM3_ERFTRANS, NULL, 0); + goto out; } if ((p->flags & ISO14B_APDU) == ISO14B_APDU) { @@ -2533,5 +2680,6 @@ out: switch_off(); // disconnect raw SpinDelay(20); BigBuf_free_keep_EM(); + s_field_on = false; } } diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index 4548f0b64..3dfdcf578 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -20,19 +20,20 @@ #include #include "iso14b.h" #include "fileutils.h" -#include "cmdparser.h" // command_t -#include "commonutil.h" // ARRAYLEN -#include "comms.h" // clearCommandBuffer -#include "emv/emvcore.h" // TLVPrintFromBuffer +#include "cmdparser.h" // command_t +#include "commonutil.h" // ARRAYLEN +#include "comms.h" // clearCommandBuffer +#include "emv/emvcore.h" // TLVPrintFromBuffer #include "cmdtrace.h" #include "cliparser.h" #include "crc16.h" #include "cmdhf14a.h" -#include "protocols.h" // definitions of ISO14B/7816 protocol -#include "iso7816/apduinfo.h" // GetAPDUCodeDescription -#include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint +#include "protocols.h" // definitions of ISO14B/7816 protocol +#include "iso7816/apduinfo.h" // GetAPDUCodeDescription +#include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint #include "aidsearch.h" -#include "fileutils.h" // saveFile +#include "fileutils.h" // saveFile +#include "iclass_cmd.h" // picopass defines #define MAX_14B_TIMEOUT_MS (4949U) @@ -849,7 +850,7 @@ static int CmdHF14BSniff(const char *Cmd) { return PM3_SUCCESS; } -static int CmdHF14BCmdRaw(const char *Cmd) { +static int CmdHF14BRaw(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf 14b raw", "Sends raw bytes to card. Activates field by default", @@ -872,10 +873,9 @@ static int CmdHF14BCmdRaw(const char *Cmd) { arg_lit0(NULL, "sr", "use SRx ST select"), arg_lit0(NULL, "cts", "use ASK C-ticket select"), arg_lit0(NULL, "xrx", "use Fuji/Xerox select"), + arg_lit0(NULL, "pico", "use Picopass select"), arg_lit0("v", "verbose", "verbose output"), - - arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -894,7 +894,8 @@ static int CmdHF14BCmdRaw(const char *Cmd) { bool select_sr = arg_get_lit(ctx, 8); bool select_cts = arg_get_lit(ctx, 9); bool select_xrx = arg_get_lit(ctx, 10); - bool verbose = arg_get_lit(ctx, 11); + bool select_pico = arg_get_lit(ctx, 11); + bool verbose = arg_get_lit(ctx, 12); CLIParserFree(ctx); // FLAGS for device side @@ -928,6 +929,11 @@ static int CmdHF14BCmdRaw(const char *Cmd) { if (verbose) { PrintAndLogEx(INFO, "using Fuji/Xerox select"); } + } else if (select_pico) { + flags |= (ISO14B_CONNECT | ISO14B_SELECT_PICOPASS | ISO14B_CLEARTRACE); + if (verbose) { + PrintAndLogEx(INFO, "using Picopass select"); + } } uint32_t time_wait = 0; @@ -1008,6 +1014,13 @@ static int CmdHF14BCmdRaw(const char *Cmd) { } } + if (select_pico) { + success = wait_cmd_14b(verbose, true, user_timeout); + if (verbose && success) { + PrintAndLogEx(SUCCESS, "Got response for Picopass select"); + } + } + // get back response from the raw bytes you sent. if (success && datalen > 0) { wait_cmd_14b(true, false, user_timeout); @@ -1315,6 +1328,53 @@ static bool HF14B_ask_ct_reader(bool verbose) { return false; } +static bool HF14B_picopass_reader(bool verbose) { + + iso14b_raw_cmd_t packet = { + .flags = (ISO14B_CONNECT | ISO14B_SELECT_PICOPASS | ISO14B_DISCONNECT), + .timeout = 0, + .rawlen = 0, + }; + + // 14b get and print UID only (general info) + clearCommandBuffer(); + PacketResponseNG resp; + SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t)); + if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT) == false) { + if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply"); + return false; + } + + switch (resp.status) { + case PM3_SUCCESS: { + + picopass_hdr_t *card = calloc(1, sizeof(picopass_hdr_t)); + if (card == NULL) { + PrintAndLogEx(FAILED, "failed to allocate memory"); + return false; + } + memcpy(card, resp.data.asBytes, sizeof(picopass_hdr_t)); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "iCLASS / Picopass CSN: " _GREEN_("%s"), sprint_hex(card->csn, sizeof(card->csn))); + free(card); + return true; + } + case PM3_ELENGTH: { + if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 wrong length"); + break; + } + case PM3_ECRC: { + if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 CRC fail"); + break; + } + default: { + if (verbose) PrintAndLogEx(FAILED, "ISO 14443-b Picopass select failed"); + break; + } + } + return false; +} + // test for other 14b type tags (mimic another reader - don't have tags to identify) static bool HF14B_other_reader(bool verbose) { @@ -2422,7 +2482,7 @@ static command_t CommandTable[] = { {"dump", CmdHF14BDump, IfPm3Iso14443b, "Read all memory pages of an ISO-14443-B tag, save to file"}, {"info", CmdHF14Binfo, IfPm3Iso14443b, "Tag information"}, {"ndefread", CmdHF14BNdefRead, IfPm3Iso14443b, "Read NDEF file on tag"}, - {"raw", CmdHF14BCmdRaw, IfPm3Iso14443b, "Send raw hex data to tag"}, + {"raw", CmdHF14BRaw, IfPm3Iso14443b, "Send raw hex data to tag"}, {"rdbl", CmdHF14BSriRdBl, IfPm3Iso14443b, "Read SRI512/SRIX4 block"}, {"reader", CmdHF14BReader, IfPm3Iso14443b, "Act as a ISO-14443-B reader to identify a tag"}, // {"restore", CmdHF14BRestore, IfPm3Iso14443b, "Restore from file to all memory pages of an ISO-14443-B tag"}, @@ -2497,6 +2557,13 @@ int readHF14B(bool loop, bool verbose) { else if (found) return PM3_SUCCESS; + // Picopass + found |= HF14B_picopass_reader(verbose) ; + if (found && loop) + continue; + else if (found) + return PM3_SUCCESS; + } while (loop && kbd_enter_pressed() == false); if (verbose && found == false) { diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 340af551a..cf4b4f314 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -1009,7 +1009,7 @@ int read_iclass_csn(bool loop, bool verbose, bool shallow_mod) { } else { if (r->status == FLAG_ICLASS_NULL || resp.status == PM3_ERFTRANS) { - if (verbose) PrintAndLogEx(WARNING, "iCLASS / Picopass card select failed ( %d )", r->status); + if (verbose) PrintAndLogEx(WARNING, "iCLASS / Picopass card select failed ( %d , %d)", r->status, resp.status); res = PM3_EOPABORTED; break; } @@ -1059,7 +1059,7 @@ static int CmdHFiClassReader(const char *Cmd) { PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); } - return read_iclass_csn(cm, true, shallow_mod); + return read_iclass_csn(cm, false, shallow_mod); } static int CmdHFiClassELoad(const char *Cmd) {