diff --git a/armsrc/Makefile b/armsrc/Makefile index dedccd3e0..536e95b50 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -37,7 +37,7 @@ APP_CFLAGS = $(PLATFORM_DEFS) \ SRC_LF = lfops.c lfsampling.c pcf7931.c lfdemod.c lfadc.c SRC_HF = hfops.c SRC_ISO15693 = iso15693.c iso15693tools.c -SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c mifaresim.c sam_mfc.c sam_seos.c +SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c mifaresim.c sam_mfc.c sam_seos.c emvsim.c #UNUSED: mifaresniff.c SRC_ISO14443b = iso14443b.c SRC_FELICA = felica.c @@ -59,7 +59,7 @@ else endif ifneq (,$(findstring WITH_SMARTCARD,$(APP_CFLAGS))) - SRC_SMARTCARD = i2c.c + SRC_SMARTCARD = i2c.c i2c_direct.c else SRC_SMARTCARD = endif diff --git a/armsrc/appmain.c b/armsrc/appmain.c index b258b4ff5..baa616b26 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -54,6 +54,7 @@ #include "mifarecmd.h" #include "mifaredesfire.h" #include "mifaresim.h" +#include "emvsim.h" #include "pcf7931.h" #include "Standalone/standalone.h" #include "util.h" @@ -1628,6 +1629,19 @@ static void PacketReceived(PacketCommandNG *packet) { ReaderIso14443a(packet); break; } + case CMD_HF_ISO14443A_EMV_SIMULATE: { + struct p { + uint16_t flags; + uint8_t exitAfter; + uint8_t uid[7]; + uint16_t atqa; + uint8_t sak; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + + EMVsim(payload->flags, payload->exitAfter, payload->uid, payload->atqa, payload->sak); + break; + } case CMD_HF_ISO14443A_SIMULATE: { struct p { uint8_t tagtype; diff --git a/armsrc/emvsim.c b/armsrc/emvsim.c new file mode 100644 index 000000000..a18b023c5 --- /dev/null +++ b/armsrc/emvsim.c @@ -0,0 +1,787 @@ +//----------------------------------------------------------------------------- +// Copyright (C) n-hutton - Sept 2024 +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- +// EVM contact to contactless bridge attack +//----------------------------------------------------------------------------- + +// Verbose Mode: +// DBG_NONE 0 +// DBG_ERROR 1 +// DBG_INFO 2 +// DBG_DEBUG 3 +// DBG_EXTENDED 4 + +// /!\ Printing Debug message is disrupting emulation, +// Only use with caution during debugging + +// These are the old flags which have changed in master since this fork was created. +// Just a temp fix and not intended to go into master +#define FLAG_4B_UID_IN_DATA_OLD 0x02 +#define FLAG_7B_UID_IN_DATA_OLD 0x04 +#define FLAG_10B_UID_IN_DATA_OLD 0x08 +#define FLAG_UID_IN_EMUL_OLD 0x10 +#define FLAG_MF_MINI_OLD 0x80 +#define FLAG_MF_1K_OLD 0x100 +#define FLAG_MF_2K_OLD 0x200 +#define FLAG_MF_4K_OLD 0x400 +#define FLAG_FORCED_ATQA 0x800 +#define FLAG_FORCED_SAK 0x1000 +#define FLAG_CVE21_0430_OLD 0x2000 + +#include "emvsim.h" +#include +#include "BigBuf.h" +#include "iso14443a.h" +#include "BigBuf.h" +#include "string.h" +#include "mifareutil.h" +#include "fpgaloader.h" +#include "proxmark3_arm.h" +#include "protocols.h" +#include "util.h" +#include "commonutil.h" +#include "dbprint.h" +#include "ticks.h" +#include "i2c_direct.h" + +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-function" + +static uint8_t filenotfound[] = {0x02, 0x6a, 0x82, 0x93, 0x2f}; + +// query and response that inserts PDOL so as to continue process... +static uint8_t fci_query[] = {0x02, 0x00, 0xa4, 0x04, 0x00, 0x07, 0xa0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10, 0x00, 0x56, 0x3f}; +static uint8_t fci_template[] = {0x02, 0x6f, 0x5e, 0x84, 0x07, 0xa0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10, 0xa5, 0x53, 0x50, 0x0a, 0x56, 0x69, 0x73, 0x61, 0x20, 0x44, 0x65, 0x62, 0x69, 0x74, 0x9f, 0x38, 0x18, 0x9f, 0x66, 0x04, 0x9f, 0x02, 0x06, 0x9f, 0x03, 0x06, 0x9f, 0x1a, 0x02, 0x95, 0x05, 0x5f, 0x2a, 0x02, 0x9a, 0x03, 0x9c, 0x01, 0x9f, 0x37, 0x04, 0x5f, 0x2d, 0x02, 0x65, 0x6e, 0x9f, 0x11, 0x01, 0x01, 0x9f, 0x12, 0x0a, 0x56, 0x69, 0x73, 0x61, 0x20, 0x44, 0x65, 0x62, 0x69, 0x74, 0xbf, 0x0c, 0x13, 0x9f, 0x5a, 0x05, 0x31, 0x08, 0x26, 0x08, 0x26, 0x9f, 0x0a, 0x08, 0x00, 0x01, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0xd8, 0x15}; + +static uint8_t pay1_response[] = { 0x6F, 0x1E, 0x84, 0x0E, 0x31, 0x50, 0x41, 0x59 }; +static uint8_t pay2_response[] = { 0x03, 0x6f, 0x3e, 0x84, 0x0e, 0x32, 0x50, 0x41, 0x59, 0x2e, 0x53, 0x59, 0x53, 0x2e, 0x44, 0x44, 0x46, 0x30, 0x31, 0xa5, 0x2c, 0xbf, 0x0c, 0x29, 0x61, 0x27, 0x4f, 0x07, 0xa0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10, 0x50, 0x0a, 0x56, 0x69, 0x73, 0x61, 0x20, 0x44, 0x65, 0x62, 0x69, 0x74, 0x9f, 0x0a, 0x08, 0x00, 0x01, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x63, 0x04, 0xdf, 0x20, 0x01, 0x80, 0x90, 0x00, 0x07, 0x9d}; + +static bool MifareSimInit(uint16_t flags, uint8_t *datain, uint16_t atqa, uint8_t sak, tag_response_info_t **responses, uint32_t *cuid, uint8_t *uid_len, uint8_t **rats, uint8_t *rats_len) { + + // SPEC: https://www.nxp.com/docs/en/application-note/AN10833.pdf + // ATQA + static uint8_t rATQA_Mini[] = {0x04, 0x00}; // indicate Mifare classic Mini 4Byte UID + static uint8_t rATQA_1k[] = {0x04, 0x00}; // indicate Mifare classic 1k 4Byte UID + static uint8_t rATQA_2k[] = {0x04, 0x00}; // indicate Mifare classic 2k 4Byte UID + static uint8_t rATQA_4k[] = {0x02, 0x00}; // indicate Mifare classic 4k 4Byte UID + + // SAK + static uint8_t rSAK_Mini = 0x09; // mifare Mini + static uint8_t rSAK_1k = 0x08; // mifare 1k + static uint8_t rSAK_2k = 0x08; // mifare 2k with RATS support + static uint8_t rSAK_4k = 0x18; // mifare 4k + + static uint8_t rUIDBCC1[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 1st cascade level + static uint8_t rUIDBCC1b4[] = {0x00, 0x00, 0x00, 0x00}; // UID 1st cascade level, last 4 bytes + static uint8_t rUIDBCC1b3[] = {0x00, 0x00, 0x00}; // UID 1st cascade level, last 3 bytes + static uint8_t rUIDBCC1b2[] = {0x00, 0x00}; // UID 1st cascade level, last 2 bytes + static uint8_t rUIDBCC1b1[] = {0x00}; // UID 1st cascade level, last byte + static uint8_t rUIDBCC2[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 2nd cascade level + static uint8_t rUIDBCC2b4[] = {0x00, 0x00, 0x00, 0x00}; // UID 2st cascade level, last 4 bytes + static uint8_t rUIDBCC2b3[] = {0x00, 0x00, 0x00}; // UID 2st cascade level, last 3 bytes + static uint8_t rUIDBCC2b2[] = {0x00, 0x00}; // UID 2st cascade level, last 2 bytes + static uint8_t rUIDBCC2b1[] = {0x00}; // UID 2st cascade level, last byte + static uint8_t rUIDBCC3[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 3nd cascade level + static uint8_t rUIDBCC3b4[] = {0x00, 0x00, 0x00, 0x00}; // UID 3st cascade level, last 4 bytes + static uint8_t rUIDBCC3b3[] = {0x00, 0x00, 0x00}; // UID 3st cascade level, last 3 bytes + static uint8_t rUIDBCC3b2[] = {0x00, 0x00}; // UID 3st cascade level, last 2 bytes + static uint8_t rUIDBCC3b1[] = {0x00}; // UID 3st cascade level, last byte + + static uint8_t rATQA[] = {0x00, 0x00}; // Current ATQA + static uint8_t rSAK[] = {0x00, 0x00, 0x00}; // Current SAK, CRC + static uint8_t rSAKuid[] = {0x04, 0xda, 0x17}; // UID incomplete cascade bit, CRC + + // RATS answer for 2K NXP mifare classic (with CRC) + static uint8_t rRATS[] = {0x0c, 0x75, 0x77, 0x80, 0x02, 0xc1, 0x05, 0x2f, 0x2f, 0x01, 0xbc, 0xd6, 0x60, 0xd3}; + + *uid_len = 0; + + // By default use 1K tag + memcpy(rATQA, rATQA_1k, sizeof(rATQA)); + rSAK[0] = rSAK_1k; + + //by default RATS not supported + *rats_len = 0; + *rats = NULL; + + // -- Determine the UID + // Can be set from emulator memory or incoming data + // Length: 4,7,or 10 bytes + + // Get UID, SAK, ATQA from EMUL + if ((flags & FLAG_UID_IN_EMUL_OLD) == FLAG_UID_IN_EMUL_OLD) { + uint8_t block0[16]; + emlGet(block0, 0, 16); + + // If uid size defined, copy only uid from EMUL to use, backward compatibility for 'hf_colin.c', 'hf_mattyrun.c' + if ((flags & (FLAG_4B_UID_IN_DATA_OLD | FLAG_7B_UID_IN_DATA_OLD | FLAG_10B_UID_IN_DATA_OLD)) != 0) { + memcpy(datain, block0, 10); // load 10bytes from EMUL to the datain pointer. to be used below. + } else { + // Check for 4 bytes uid: bcc corrected and single size uid bits in ATQA + if ((block0[0] ^ block0[1] ^ block0[2] ^ block0[3]) == block0[4] && (block0[6] & 0xc0) == 0) { + flags |= FLAG_4B_UID_IN_DATA_OLD; + memcpy(datain, block0, 4); + rSAK[0] = block0[5]; + memcpy(rATQA, &block0[6], sizeof(rATQA)); + } + // Check for 7 bytes UID: double size uid bits in ATQA + else if ((block0[8] & 0xc0) == 0x40) { + flags |= FLAG_7B_UID_IN_DATA_OLD; + memcpy(datain, block0, 7); + rSAK[0] = block0[7]; + memcpy(rATQA, &block0[8], sizeof(rATQA)); + } else { + Dbprintf("ERROR: " _RED_("Invalid dump. UID/SAK/ATQA not found")); + return false; + } + } + + } + + // Tune tag type, if defined directly + // Otherwise use defined by default or extracted from EMUL + if ((flags & FLAG_MF_MINI_OLD) == FLAG_MF_MINI_OLD) { + memcpy(rATQA, rATQA_Mini, sizeof(rATQA)); + rSAK[0] = rSAK_Mini; + if (g_dbglevel > DBG_NONE) Dbprintf("Enforcing Mifare Mini ATQA/SAK"); + } else if ((flags & FLAG_MF_1K_OLD) == FLAG_MF_1K_OLD) { + memcpy(rATQA, rATQA_1k, sizeof(rATQA)); + rSAK[0] = rSAK_1k; + if (g_dbglevel > DBG_NONE) Dbprintf("Enforcing Mifare 1K ATQA/SAK (!!!!)"); + } else if ((flags & FLAG_MF_2K_OLD) == FLAG_MF_2K_OLD) { + memcpy(rATQA, rATQA_2k, sizeof(rATQA)); + rSAK[0] = rSAK_2k; + *rats = rRATS; + *rats_len = sizeof(rRATS); + if (g_dbglevel > DBG_NONE) Dbprintf("Enforcing Mifare 2K ATQA/SAK with RATS support"); + } else if ((flags & FLAG_MF_4K_OLD) == FLAG_MF_4K_OLD) { + memcpy(rATQA, rATQA_4k, sizeof(rATQA)); + rSAK[0] = rSAK_4k; + if (g_dbglevel > DBG_NONE) Dbprintf("Enforcing Mifare 4K ATQA/SAK"); + } + + // Prepare UID arrays + if ((flags & FLAG_4B_UID_IN_DATA_OLD) == FLAG_4B_UID_IN_DATA_OLD) { // get UID from datain + memcpy(rUIDBCC1, datain, 4); + *uid_len = 4; + if (g_dbglevel >= DBG_EXTENDED) + Dbprintf("MifareSimInit - FLAG_4B_UID_IN_DATA_OLD => Get UID from datain: %02X - Flag: %02X - UIDBCC1: %02X", FLAG_4B_UID_IN_DATA_OLD, flags, rUIDBCC1); + + // save CUID + *cuid = bytes_to_num(rUIDBCC1, 4); + // BCC + rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; + if (g_dbglevel > DBG_NONE) { + Dbprintf("4B UID: %02x%02x%02x%02x", rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3]); + } + + // Correct uid size bits in ATQA + rATQA[0] = (rATQA[0] & 0x3f) | 0x00; // single size uid + + } else if ((flags & FLAG_7B_UID_IN_DATA_OLD) == FLAG_7B_UID_IN_DATA_OLD) { + memcpy(&rUIDBCC1[1], datain, 3); + memcpy(rUIDBCC2, datain + 3, 4); + *uid_len = 7; + if (g_dbglevel >= DBG_EXTENDED) + Dbprintf("MifareSimInit - FLAG_7B_UID_IN_DATA_OLD => Get UID from datain: %02X - Flag: %02X - UIDBCC1: %02X", FLAG_7B_UID_IN_DATA_OLD, flags, rUIDBCC1); + + // save CUID + *cuid = bytes_to_num(rUIDBCC2, 4); + // CascadeTag, CT + rUIDBCC1[0] = MIFARE_SELECT_CT; + // BCC + rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; + rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3]; + if (g_dbglevel > DBG_NONE) { + Dbprintf("7B UID: %02x %02x %02x %02x %02x %02x %02x", + rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3], rUIDBCC2[0], rUIDBCC2[1], rUIDBCC2[2], rUIDBCC2[3]); + } + + // Correct uid size bits in ATQA + rATQA[0] = (rATQA[0] & 0x3f) | 0x40; // double size uid + + } else if ((flags & FLAG_10B_UID_IN_DATA_OLD) == FLAG_10B_UID_IN_DATA_OLD) { + memcpy(&rUIDBCC1[1], datain, 3); + memcpy(&rUIDBCC2[1], datain + 3, 3); + memcpy(rUIDBCC3, datain + 6, 4); + *uid_len = 10; + if (g_dbglevel >= DBG_EXTENDED) + Dbprintf("MifareSimInit - FLAG_10B_UID_IN_DATA_OLD => Get UID from datain: %02X - Flag: %02X - UIDBCC1: %02X", FLAG_10B_UID_IN_DATA_OLD, flags, rUIDBCC1); + + // save CUID + *cuid = bytes_to_num(rUIDBCC3, 4); + // CascadeTag, CT + rUIDBCC1[0] = MIFARE_SELECT_CT; + rUIDBCC2[0] = MIFARE_SELECT_CT; + // BCC + rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; + rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3]; + rUIDBCC3[4] = rUIDBCC3[0] ^ rUIDBCC3[1] ^ rUIDBCC3[2] ^ rUIDBCC3[3]; + + if (g_dbglevel > DBG_NONE) { + Dbprintf("10B UID: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3], + rUIDBCC2[1], rUIDBCC2[2], rUIDBCC2[3], + rUIDBCC3[0], rUIDBCC3[1], rUIDBCC3[2], rUIDBCC3[3] + ); + } + + // Correct uid size bits in ATQA + rATQA[0] = (rATQA[0] & 0x3f) | 0x80; // triple size uid + } else { + Dbprintf("ERROR: " _RED_("UID size not defined")); + return false; + } + + if (flags & FLAG_FORCED_ATQA) { + rATQA[0] = atqa >> 8; + rATQA[1] = atqa & 0xff; + } + if (flags & FLAG_FORCED_SAK) { + rSAK[0] = sak; + } + + if (g_dbglevel > DBG_NONE) { + Dbprintf("ATQA : %02X %02X", rATQA[1], rATQA[0]); + Dbprintf("SAK : %02X", rSAK[0]); + } + + // clone UIDs for byte-frame anti-collision multiple tag selection procedure + memcpy(rUIDBCC1b4, &rUIDBCC1[1], 4); + memcpy(rUIDBCC1b3, &rUIDBCC1[2], 3); + memcpy(rUIDBCC1b2, &rUIDBCC1[3], 2); + memcpy(rUIDBCC1b1, &rUIDBCC1[4], 1); + if (*uid_len >= 7) { + memcpy(rUIDBCC2b4, &rUIDBCC2[1], 4); + memcpy(rUIDBCC2b3, &rUIDBCC2[2], 3); + memcpy(rUIDBCC2b2, &rUIDBCC2[3], 2); + memcpy(rUIDBCC2b1, &rUIDBCC2[4], 1); + } + if (*uid_len == 10) { + memcpy(rUIDBCC3b4, &rUIDBCC3[1], 4); + memcpy(rUIDBCC3b3, &rUIDBCC3[2], 3); + memcpy(rUIDBCC3b2, &rUIDBCC3[3], 2); + memcpy(rUIDBCC3b1, &rUIDBCC3[4], 1); + } + + // Calculate actual CRC + AddCrc14A(rSAK, sizeof(rSAK) - 2); + +#define TAG_RESPONSE_COUNT 18 + static tag_response_info_t responses_init[TAG_RESPONSE_COUNT] = { + { .response = rATQA, .response_n = sizeof(rATQA) }, // Answer to request - respond with card type + { .response = rSAK, .response_n = sizeof(rSAK) }, // + { .response = rSAKuid, .response_n = sizeof(rSAKuid) }, // + // Do not reorder. Block used via relative index of rUIDBCC1 + { .response = rUIDBCC1, .response_n = sizeof(rUIDBCC1) }, // Anticollision cascade1 - respond with first part of uid + { .response = rUIDBCC1b4, .response_n = sizeof(rUIDBCC1b4)}, + { .response = rUIDBCC1b3, .response_n = sizeof(rUIDBCC1b3)}, + { .response = rUIDBCC1b2, .response_n = sizeof(rUIDBCC1b2)}, + { .response = rUIDBCC1b1, .response_n = sizeof(rUIDBCC1b1)}, + // Do not reorder. Block used via relative index of rUIDBCC2 + { .response = rUIDBCC2, .response_n = sizeof(rUIDBCC2) }, // Anticollision cascade2 - respond with 2nd part of uid + { .response = rUIDBCC2b4, .response_n = sizeof(rUIDBCC2b4)}, + { .response = rUIDBCC2b3, .response_n = sizeof(rUIDBCC2b3)}, + { .response = rUIDBCC2b2, .response_n = sizeof(rUIDBCC2b2)}, + { .response = rUIDBCC2b1, .response_n = sizeof(rUIDBCC2b1)}, + // Do not reorder. Block used via relative index of rUIDBCC3 + { .response = rUIDBCC3, .response_n = sizeof(rUIDBCC3) }, // Anticollision cascade3 - respond with 3th part of uid + { .response = rUIDBCC3b4, .response_n = sizeof(rUIDBCC3b4)}, + { .response = rUIDBCC3b3, .response_n = sizeof(rUIDBCC3b3)}, + { .response = rUIDBCC3b2, .response_n = sizeof(rUIDBCC3b2)}, + { .response = rUIDBCC3b1, .response_n = sizeof(rUIDBCC3b1)} + }; + + // Prepare ("precompile") the responses of the anticollision phase. + // There will be not enough time to do this at the moment the reader sends its REQA or SELECT + // There are 18 predefined responses with a total of 53 bytes data to transmit. + // Coded responses need one byte per bit to transfer (data, parity, start, stop, correction) + // 53 * 8 data bits, 53 * 1 parity bits, 18 start bits, 18 stop bits, 18 correction bits -> need 571 bytes buffer +#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 571 + + uint8_t *free_buffer = BigBuf_malloc(ALLOCATED_TAG_MODULATION_BUFFER_SIZE); + // modulation buffer pointer and current buffer free space size + uint8_t *free_buffer_pointer = free_buffer; + size_t free_buffer_size = ALLOCATED_TAG_MODULATION_BUFFER_SIZE; + + for (size_t i = 0; i < TAG_RESPONSE_COUNT; i++) { + if (prepare_allocated_tag_modulation(&responses_init[i], &free_buffer_pointer, &free_buffer_size) == false) { + Dbprintf("Not enough modulation buffer size, exit after %d elements", i); + return false; + } + } + + *responses = responses_init; + + // indices into responses array: +#define ATQA 0 +#define SAK 1 +#define SAKuid 2 +#define UIDBCC1 3 +#define UIDBCC2 8 +#define UIDBCC3 13 + + return true; +} + +/** +*xxxxxxxxxxxxxxxxxx. +* +*@param flags : +*@param exitAfterNReads, exit simulation after n blocks have been read, 0 is infinite ... +* (unless reader attack mode enabled then it runs util it gets enough nonces to recover all keys attmpted) +*/ +void EMVsim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint16_t atqa, uint8_t sak) { + + tag_response_info_t *responses; + uint8_t cardSTATE = MFEMUL_NOFIELD; + uint8_t uid_len = 0; // 4, 7, 10 + uint32_t cuid = 0, authTimer = 0; + uint32_t nr, ar; + + uint8_t cardWRBL = 0; + uint8_t cardAUTHSC = 0; + uint8_t cardAUTHKEY = AUTHKEYNONE; // no authentication + uint32_t cardRr = 0; + uint32_t ans = 0; + uint32_t cardINTREG = 0; + uint8_t cardINTBLOCK = 0; + + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + + //uint32_t numReads = 0; //Counts numer of times reader reads a block + uint8_t receivedCmd[MAX_FRAME_SIZE] = {0x00}; + uint8_t receivedCmd_copy[MAX_FRAME_SIZE] = {0x00}; + uint8_t receivedCmd_dec[MAX_FRAME_SIZE] = {0x00}; + //uint8_t convenient_buffer[64] = {0x00}; + uint8_t receivedCmd_par[MAX_MIFARE_PARITY_SIZE] = {0x00}; + uint8_t responseToReader[MAX_FRAME_SIZE] = {0x00}; + uint16_t responseToReader_len; + uint16_t receivedCmd_len; + uint16_t receivedCmd_len_copy = 0; + + if (receivedCmd_len_copy) { + Dbprintf("receivedCmd_len_copy: %d", receivedCmd_len_copy); + } + + uint8_t *rats = NULL; + uint8_t rats_len = 0; + + // if fct is called with NULL we need to assign some memory since this pointer is passaed around + uint8_t datain_tmp[10] = {0}; + if (datain == NULL) { + datain = datain_tmp; + } + + //Here, we collect UID,sector,keytype,NT,AR,NR,NT2,AR2,NR2 + // This will be used in the reader-only attack. + + //allow collecting up to 7 sets of nonces to allow recovery of up to 7 keys +#define ATTACK_KEY_COUNT 7 // keep same as define in cmdhfmf.c -> readerAttack() (Cannot be more than 7) + nonces_t ar_nr_resp[ATTACK_KEY_COUNT * 2]; // *2 for 2 separate attack types (nml, moebius) 36 * 7 * 2 bytes = 504 bytes + memset(ar_nr_resp, 0x00, sizeof(ar_nr_resp)); + + uint8_t ar_nr_collected[ATTACK_KEY_COUNT * 2]; // *2 for 2nd attack type (moebius) + memset(ar_nr_collected, 0x00, sizeof(ar_nr_collected)); + bool gettingMoebius = false; + + const tUart14a *uart = GetUart14a(); + + // free eventually allocated BigBuf memory but keep Emulator Memory + BigBuf_free_keep_EM(); + + if (MifareSimInit(flags, datain, atqa, sak, &responses, &cuid, &uid_len, &rats, &rats_len) == false) { + BigBuf_free_keep_EM(); + return; + } + + // We need to listen to the high-frequency, peak-detected path. + iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN); + + // clear trace + clear_trace(); + set_tracing(true); + LED_D_ON(); + ResetSspClk(); + + uint8_t *p_em = BigBuf_get_EM_addr(); + + int counter = 0; + bool finished = false; + bool button_pushed = BUTTON_PRESS(); + + while ((button_pushed == false) && (finished == false)) { + + WDT_HIT(); + + if (counter == 3000) { + if (data_available()) { + Dbprintf("----------- " _GREEN_("BREAKING") " ----------"); + break; + } + counter = 0; + } else { + counter++; + } + + FpgaEnableTracing(); + // Now, get data from the FPGA + int res = EmGetCmd(receivedCmd, sizeof(receivedCmd), &receivedCmd_len, receivedCmd_par); + + if (res == 2) { //Field is off! + if ((flags & FLAG_CVE21_0430_OLD) == FLAG_CVE21_0430_OLD) { + p_em[1] = 0x21; + } + LEDsoff(); + if (cardSTATE != MFEMUL_NOFIELD) { + Dbprintf("cardSTATE = MFEMUL_NOFIELD"); + break; + } + cardSTATE = MFEMUL_NOFIELD; + continue; + } else if (res == 1) { // button pressed + FpgaDisableTracing(); + button_pushed = true; + if (g_dbglevel >= DBG_EXTENDED) + Dbprintf("Button pressed"); + break; + } + + // WUPA in HALTED state or REQA or WUPA in any other state + if (receivedCmd_len == 1 && ((receivedCmd[0] == ISO14443A_CMD_REQA && cardSTATE != MFEMUL_HALTED) || receivedCmd[0] == ISO14443A_CMD_WUPA)) { + EmSendPrecompiledCmd(&responses[ATQA]); + + FpgaDisableTracing(); + + LED_B_OFF(); + LED_C_OFF(); + cardSTATE = MFEMUL_SELECT; + + continue; + } + + switch (cardSTATE) { + case MFEMUL_NOFIELD: { + if (g_dbglevel >= DBG_EXTENDED) + Dbprintf("MFEMUL_NOFIELD"); + + break; + } + case MFEMUL_HALTED: { + if (g_dbglevel >= DBG_EXTENDED) + Dbprintf("MFEMUL_HALTED"); + + break; + } + case MFEMUL_IDLE: { + LogTrace(uart->output, uart->len, uart->startTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true); + if (g_dbglevel >= DBG_EXTENDED) + Dbprintf("MFEMUL_IDLE"); + + break; + } + + // The anti-collision sequence, which is a mandatory part of the card activation sequence. + // It auto with 4-byte UID (= Single Size UID), + // 7 -byte UID (= Double Size UID) or 10-byte UID (= Triple Size UID). + // For details see chapter 2 of AN10927.pdf + // + // This case is used for all Cascade Levels, because: + // 1) Any devices (under Android for example) after full select procedure completed, + // when UID is known, uses "fast-selection" method. In this case reader ignores + // first cascades and tries to select tag by last bytes of UID of last cascade + // 2) Any readers (like ACR122U) uses bit oriented anti-collision frames during selectin, + // same as multiple tags. For details see chapter 6.1.5.3 of ISO/IEC 14443-3 + case MFEMUL_SELECT: { + + int uid_index = -1; + // Extract cascade level + if (receivedCmd_len >= 2) { + switch (receivedCmd[0]) { + case ISO14443A_CMD_ANTICOLL_OR_SELECT: + uid_index = UIDBCC1; + break; + case ISO14443A_CMD_ANTICOLL_OR_SELECT_2: + uid_index = UIDBCC2; + break; + case ISO14443A_CMD_ANTICOLL_OR_SELECT_3: + uid_index = UIDBCC3; + break; + } + } + + if (uid_index < 0) { + LogTrace(uart->output, uart->len, uart->startTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true); + cardSTATE_TO_IDLE(); + break; + } + + // Incoming SELECT ALL for any cascade level + if (receivedCmd_len == 2 && receivedCmd[1] == 0x20) { + EmSendPrecompiledCmd(&responses[uid_index]); + FpgaDisableTracing(); + + break; + } + + // Incoming SELECT CLx for any cascade level + if (receivedCmd_len == 9 && receivedCmd[1] == 0x70) { + if (memcmp(&receivedCmd[2], responses[uid_index].response, 4) == 0) { + bool cl_finished = (uid_len == 4 && uid_index == UIDBCC1) || + (uid_len == 7 && uid_index == UIDBCC2) || + (uid_len == 10 && uid_index == UIDBCC3); + EmSendPrecompiledCmd(&responses[cl_finished ? SAK : SAKuid]); + FpgaDisableTracing(); + + if (cl_finished) { + LED_B_ON(); + cardSTATE = MFEMUL_WORK; + } + } else { + // IDLE, not our UID + LogTrace(uart->output, uart->len, uart->startTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true); + cardSTATE_TO_IDLE(); + if (g_dbglevel >= DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT] cardSTATE = MFEMUL_IDLE"); + } + break; + } + + // Incoming anti-collision frame + // receivedCmd[1] indicates number of byte and bit collision, supports only for bit collision is zero + if (receivedCmd_len >= 3 && receivedCmd_len <= 6 && (receivedCmd[1] & 0x0f) == 0) { + // we can process only full-byte frame anti-collision procedure + if (memcmp(&receivedCmd[2], responses[uid_index].response, receivedCmd_len - 2) == 0) { + // response missing part of UID via relative array index + EmSendPrecompiledCmd(&responses[uid_index + receivedCmd_len - 2]); + FpgaDisableTracing(); + + if (g_dbglevel >= DBG_EXTENDED) Dbprintf("SELECT ANTICOLLISION - EmSendPrecompiledCmd(%02x)", &responses[uid_index]); + Dbprintf("001 SELECT ANTICOLLISION - EmSendPrecompiledCmd(%02x)", &responses[uid_index]); + } else { + // IDLE, not our UID or split-byte frame anti-collision (not supports) + LogTrace(uart->output, uart->len, uart->startTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true); + cardSTATE_TO_IDLE(); + if (g_dbglevel >= DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT] cardSTATE = MFEMUL_IDLE"); + } + + break; + } + + // Unknown selection procedure + LogTrace(uart->output, uart->len, uart->startTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true); + cardSTATE_TO_IDLE(); + + if (g_dbglevel >= DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT] Unknown selection procedure"); + break; + } + + // WORK + case MFEMUL_WORK: { + + if (receivedCmd_len == 0) { + if (g_dbglevel >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] NO CMD received"); + Dbprintf("001 [MFEMUL_WORK] NO CMD received"); + break; + } + + memcpy(receivedCmd_dec, receivedCmd, receivedCmd_len); + + // all commands must have a valid CRC + if (!CheckCrc14A(receivedCmd_dec, receivedCmd_len)) { + if (g_dbglevel >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] All commands must have a valid CRC %02X (%d)", receivedCmd_dec, receivedCmd_len); + break; + } + + // rule 13 of 7.5.3. in ISO 14443-4. chaining shall be continued + // BUT... ACK --> NACK + if (receivedCmd_len == 1 && receivedCmd_dec[0] == CARD_ACK) { + Dbprintf("[MFEMUL_WORK] ACK --> NACK !!"); + EmSend4bit(CARD_NACK_NA); + FpgaDisableTracing(); + break; + } + + // rule 12 of 7.5.3. in ISO 14443-4. R(NAK) --> R(ACK) + if (receivedCmd_len == 1 && receivedCmd_dec[0] == CARD_NACK_NA) { + Dbprintf("[MFEMUL_WORK] NACK --> NACK !!"); + EmSend4bit(CARD_ACK); + FpgaDisableTracing(); + break; + } + + // case MFEMUL_WORK => CMD RATS + if (receivedCmd_len == 4 && receivedCmd_dec[0] == ISO14443A_CMD_RATS && receivedCmd_dec[1] == 0x80) { + if (rats && rats_len) { + EmSendCmd(rats, rats_len); + FpgaDisableTracing(); + } else { + EmSend4bit(CARD_NACK_NA); + FpgaDisableTracing(); + cardSTATE_TO_IDLE(); + if (g_dbglevel >= DBG_EXTENDED) + Dbprintf("[MFEMUL_WORK] RCV RATS => NACK"); + } + break; + } + + // case MFEMUL_WORK => ISO14443A_CMD_NXP_DESELECT + if (receivedCmd_len == 3 && receivedCmd_dec[0] == ISO14443A_CMD_NXP_DESELECT) { + if (rats && rats_len) { + EmSendCmd(receivedCmd_dec, receivedCmd_len); + + FpgaDisableTracing(); + if (g_dbglevel >= DBG_EXTENDED) + Dbprintf("[MFEMUL_WORK] RCV NXP DESELECT => ACK"); + } else { + EmSend4bit(CARD_NACK_NA); + FpgaDisableTracing(); + cardSTATE_TO_IDLE(); + if (g_dbglevel >= DBG_EXTENDED) + Dbprintf("[MFEMUL_WORK] RCV NXP DESELECT => NACK"); + } + break; + } + + // The WTX we want to send out... + //static uint8_t extend_resp[] = {0xf2, 0x01, 0x91, 0x40}; + //static uint8_t extend_resp[] = {0xf2, 0x02, 0x0a, 0x72}; + //static uint8_t extend_resp[] = {0xf2, 0x03, 0x83, 0x63}; + //static uint8_t extend_resp[] = {0xf2, 0x04, 0x3c, 0x17}; + //static uint8_t extend_resp[] = {0xf2, 0x05, 0x50, 0x6b}; + //static uint8_t extend_resp[] = {0xf2, 0x06, 0x2e, 0x34}; + //static uint8_t extend_resp[] = {0xf2, 0x07, 0xa7, 0x25}; + //static uint8_t extend_resp[] = {0xf2, 0x08, 0x50, 0xdd}; // This works + //static uint8_t extend_resp[] = {0xf2, 0x09, 0xd9, 0xcc}; + //static uint8_t extend_resp[] = {0xf2, 0x0a, 0x42, 0xfe}; + //static uint8_t extend_resp[] = {0xf2, 0x0b, 0xcb, 0xef}; + //static uint8_t extend_resp[] = {0xf2, 0x0c, 0x74, 0x9b}; + //static uint8_t extend_resp[] = {0xf2, 0x0d, 0xfd, 0x8a}; + static uint8_t extend_resp[] = {0xf2, 0x0e, 0x66, 0xb8}; + + // special print me + Dbprintf("\nrecvd from reader:"); + Dbhexdump(receivedCmd_len, receivedCmd, false); + Dbprintf(""); + + // lets handle some obvious stuff here! + if (receivedCmd[6] == 'O' && receivedCmd[7] == 'S' && receivedCmd[8] == 'E') { + Dbprintf("We saw OSE... ignore it!"); + //Full: 02 6a 82 93 2f + EmSendCmd(filenotfound, 5); + continue; + } + + // rather than asing for more time, lets just send the response with the PDOL there too + // there are two of this for some reason?? Ach, this one is not at the card read level, that is why. + if (memcmp(&fci_query[0], receivedCmd, sizeof(fci_query)) == 0 && false) { + Dbprintf("***** returning fast FCI response...!"); + //uint8_t modified_response[] = { 0x03, 0x77, 0x0e, 0x82, 0x02, 0x39, 0x80, 0x94, 0x08, 0x18, 0x01, 0x02, 0x01, 0x20, 0x01, 0x04, 0x00, 0x90, 0x00, 0x03, 0xec }; + //uint8_t modified_response[] = { 0x03, 0x77, 0x0e, 0x82, 0x02, 0x39, 0x80, 0x94, 0x08, 0x18, 0x01, 0x02, 0x01, 0x20, 0x01, 0x04, 0x00, 0x90, 0x00, 0x03, 0xec }; + EmSendCmd(&fci_template[0], sizeof(fci_template)); + + continue; + } + + // We want to modify corrupted request + if ((receivedCmd_len > 5 && receivedCmd[0] != 0x03 && receivedCmd[0] != 0x02 && receivedCmd[1] == 0 && receivedCmd[4] == 0) || (receivedCmd[2] == 0xa8)) { + //if (receivedCmd[2] == 0xa8) { + Dbprintf("We saw signing request... modifying it into a generate ac transaction !!!!"); + receivedCmd[0] = 0x03; + receivedCmd[1] = 0x80; + receivedCmd[2] = 0xae; + receivedCmd[3] = 0x80; + receivedCmd[4] = 0x00; + receivedCmd[5] = 0x1d; + + for (int i = 0; i < 29; i++) { + receivedCmd[6 + i] = receivedCmd[12 + i]; + } + + // clear final byte just in case + receivedCmd[35] = 0; + + receivedCmd_len = 35 + 3; // Core command is 35, then there is control code and hte crc + + Dbprintf("\nthe command has now become:"); + Dbhexdump(receivedCmd_len, receivedCmd, false); + } + + // Seems unlikely + if (receivedCmd_len >= 9 && receivedCmd[6] == '1' && receivedCmd[7] == 'P' && receivedCmd[8] == 'A') { + Dbprintf("We saw 1PA... !!!!"); + } + + // Request more time for 2PAY and respond with a modified 1PAY request + if (receivedCmd_len >= 9 && receivedCmd[6] == '2' && receivedCmd[7] == 'P' && receivedCmd[8] == 'A') { + Dbprintf("We saw 2PA... switching it to 1PAY !!!!"); + receivedCmd[6] = '1'; + } + + static uint8_t rnd_resp[] = {0xb2, 0x67, 0xc7}; + if (memcmp(receivedCmd, rnd_resp, sizeof(rnd_resp)) == 0) { + Dbprintf("We saw bad response... !"); + continue; + } + + // We have received the response from a WTX command! Process the cached command at this point. + if (memcmp(receivedCmd, extend_resp, sizeof(extend_resp)) == 0) { + // Special case: if we are about to do a generate AC, we also need to + // make a request for pdol... + if (receivedCmd_copy[1] == 0x80 && receivedCmd_copy[2] == 0xae) { + Dbprintf("We are about to do a generate AC... we need to request PDOL first..."); + uint8_t pdol_request[] = { 0x80, 0xa8, 0x00, 0x00, 0x02, 0x83, 0x00 }; + + CmdSmartRaw(0xff, &(pdol_request[0]), sizeof(pdol_request), (&responseToReader[0]), &responseToReader_len); + } + + // This is minus 3 because we don't include the first byte (prepend), plus we don't want to send the + // last two bytes (CRC) to the card + CmdSmartRaw(receivedCmd_copy[0], &(receivedCmd_copy[1]), receivedCmd_len_copy-3, (&responseToReader[0]), &responseToReader_len); + EmSendCmd(responseToReader, responseToReader_len); + + Dbprintf("Sent delayed command to card..."); + continue; + } + + // Send a request for more time, and cache the command we want to process + EmSendCmd(extend_resp, 4); + + // copy the command and its length (minus 1???) + Dbprintf("Caching command for later processing... its length is %d", receivedCmd_len); + memcpy(receivedCmd_copy, receivedCmd, receivedCmd_len); + receivedCmd_len_copy = receivedCmd_len; + } + + continue; + } // End Switch Loop + + button_pushed = BUTTON_PRESS(); + } // End While Loop + + FpgaDisableTracing(); + + if (g_dbglevel >= DBG_ERROR) { + Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", get_tracing(), BigBuf_get_traceLen()); + } + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + set_tracing(false); + BigBuf_free_keep_EM(); +} diff --git a/armsrc/emvsim.h b/armsrc/emvsim.h new file mode 100644 index 000000000..265b9effa --- /dev/null +++ b/armsrc/emvsim.h @@ -0,0 +1,29 @@ +//----------------------------------------------------------------------------- +// Copyright (C) Gerhard de Koning Gans - May 2008 +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- +// Mifare Classic Card Simulation +//----------------------------------------------------------------------------- + +#ifndef __EMVSIM_H +#define __EMVSIM_H + +#include "common.h" + +#define AUTHKEYNONE 0xff + +void EMVsim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint16_t atqa, uint8_t sak); + +#endif \ No newline at end of file diff --git a/armsrc/i2c_direct.c b/armsrc/i2c_direct.c new file mode 100644 index 000000000..74a7e86b0 --- /dev/null +++ b/armsrc/i2c_direct.c @@ -0,0 +1,371 @@ +// //----------------------------------------------------------------------------- +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- +// The main i2c code, for communications with smart card module +//----------------------------------------------------------------------------- + +#include + +#include "BigBuf.h" +#include "iso14443a.h" +#include "BigBuf.h" +#include "string.h" +#include "mifareutil.h" +#include "fpgaloader.h" +#include "proxmark3_arm.h" +#include "cmd.h" +#include "protocols.h" +#include "appmain.h" +#include "util.h" +#include "commonutil.h" +#include "crc16.h" +#include "dbprint.h" +#include "ticks.h" +#include "i2c.h" +#include "i2c_direct.h" + +static uint8_t fci_template[] = {0x02, 0x6f, 0x5e, 0x84, 0x07, 0xa0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10, 0xa5, 0x53, 0x50, 0x0a, 0x56, 0x69, 0x73, 0x61, 0x20, 0x44, 0x65, 0x62, 0x69, 0x74, 0x9f, 0x38, 0x18, 0x9f, 0x66, 0x04, 0x9f, 0x02, 0x06, 0x9f, 0x03, 0x06, 0x9f, 0x1a, 0x02, 0x95, 0x05, 0x5f, 0x2a, 0x02, 0x9a, 0x03, 0x9c, 0x01, 0x9f, 0x37, 0x04, 0x5f, 0x2d, 0x02, 0x65, 0x6e, 0x9f, 0x11, 0x01, 0x01, 0x9f, 0x12, 0x0a, 0x56, 0x69, 0x73, 0x61, 0x20, 0x44, 0x65, 0x62, 0x69, 0x74, 0xbf, 0x0c, 0x13, 0x9f, 0x5a, 0x05, 0x31, 0x08, 0x26, 0x08, 0x26, 0x9f, 0x0a, 0x08, 0x00, 0x01, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0xd8, 0x15}; + +static uint8_t pay1_response[] = { 0x6F, 0x1E, 0x84, 0x0E, 0x31, 0x50, 0x41, 0x59 }; +static uint8_t pay2_response[] = { 0x03, 0x6f, 0x3e, 0x84, 0x0e, 0x32, 0x50, 0x41, 0x59, 0x2e, 0x53, 0x59, 0x53, 0x2e, 0x44, 0x44, 0x46, 0x30, 0x31, 0xa5, 0x2c, 0xbf, 0x0c, 0x29, 0x61, 0x27, 0x4f, 0x07, 0xa0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10, 0x50, 0x0a, 0x56, 0x69, 0x73, 0x61, 0x20, 0x44, 0x65, 0x62, 0x69, 0x74, 0x9f, 0x0a, 0x08, 0x00, 0x01, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x63, 0x04, 0xdf, 0x20, 0x01, 0x80, 0x90, 0x00, 0x07, 0x9d}; + +void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint8_t *output, uint16_t *olen) { + LED_D_ON(); + + uint16_t len = 0; + uint8_t *resp = BigBuf_malloc(ISO7816_MAX_FRAME); + resp[0] = prepend; + // check if alloacted... + smartcard_command_t flags = p->flags; + + //if ((flags & SC_CLEARLOG) == SC_CLEARLOG) + //clear_trace(); + + if ((flags & SC_LOG) == SC_LOG) + set_tracing(true); + else + set_tracing(false); + + if ((flags & SC_CONNECT) == SC_CONNECT) { + + I2C_Reset_EnterMainProgram(); + + if ((flags & SC_SELECT) == SC_SELECT) { + smart_card_atr_t card; + bool gotATR = GetATR(&card, true); + //reply_old(CMD_ACK, gotATR, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t)); + if (gotATR == false) { + Dbprintf("No ATR received...\n"); + //reply_ng(CMD_SMART_RAW, PM3_ESOFT, NULL, 0); + goto OUT; + } + } + } + + uint32_t wait = SIM_WAIT_DELAY; + + if (((flags & SC_RAW) == SC_RAW) || ((flags & SC_RAW_T0) == SC_RAW_T0)) { + + if ((flags & SC_WAIT) == SC_WAIT) { + wait = (uint32_t)((p->wait_delay * 1000) / 3.07); + } + + LogTrace(p->data, p->len, 0, 0, NULL, true); + + bool res = I2C_BufferWrite( + p->data, + p->len, + (((flags & SC_RAW_T0) == SC_RAW_T0) ? I2C_DEVICE_CMD_SEND_T0 : I2C_DEVICE_CMD_SEND), + I2C_DEVICE_ADDRESS_MAIN + ); + + if (res == false && g_dbglevel > 3) { + //DbpString(I2C_ERROR); + //reply_ng(CMD_SMART_RAW, PM3_ESOFT, NULL, 0); + Dbprintf("SmartCardDirectSend: I2C_BufferWrite failed\n"); + goto OUT; + } + + // read bytes from module + len = ISO7816_MAX_FRAME; + res = sc_rx_bytes(&resp[1], &len, wait); + if (res) { + LogTrace(&resp[1], len, 0, 0, NULL, false); + } else { + len = 0; + } + } + + if (len == 2 && resp[1] == 0x61) { + //Dbprintf("Data to be read: len = %d\n", len); + //Dbprintf("\n"); + + uint8_t cmd_getresp[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, resp[2]}; + //smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + sizeof(cmd_getresp)); + smart_card_raw_t *payload = (smart_card_raw_t *)BigBuf_calloc(sizeof(smart_card_raw_t) + sizeof(cmd_getresp)); + payload->flags = SC_RAW | SC_LOG; + payload->len = sizeof(cmd_getresp); + payload->wait_delay = 0; + memcpy(payload->data, cmd_getresp, sizeof(cmd_getresp)); + + SmartCardDirectSend(prepend, payload, output, olen); + } else if (len == 2) { + Dbprintf("***** BAD response from card (response unsupported)..."); + Dbhexdump(3, &resp[0], false); + resp[0] = prepend; + resp[1] = 0x6a; + resp[2] =0x82; + AddCrc14A(resp, 3); + + //Dbhexdump(5, &resp[0], false); // special print + //EmSendCmd(&resp[0], 5); + memcpy(output, resp, 5); + *olen = 5; + } + + if (resp[1] == 0x6a && resp[2] == 0x82) { + Dbprintf("***** bad response from card (file not found)..."); + resp[0] = prepend; + resp[1] = 0x6a; + resp[2] =0x82; + AddCrc14A(resp, 3); + + //Dbhexdump(5, &resp[0], false); // special print + //EmSendCmd14443aRaw(&resp[0], 5); + //EmSendCmd(&resp[0], 5); + memcpy(output, resp, 5); + *olen = 5; + FpgaDisableTracing(); + } + + if (len > 2) { + Dbprintf("***** sending it over the wire... len: %d =>\n", len); + resp[1] = prepend; + + // if we have a generate AC request, lets extract the data and populate the template + if (resp[1] != 0xff && resp[2] == 0x77) { + Dbprintf("we have detected a generate ac response, lets repackage it!"); + Dbhexdump(len, &resp[1], false); // special print + // 11 and 12 are trans counter. + // 16 to 24 are the cryptogram + // 27 to 34 is issuer application data + Dbprintf("atc: %d %d, cryptogram: %d ", resp[11], resp[12], resp[13]); + + // then, on the template: + // 61 and 62 for counter + // 46 to 54 for cryptogram + // 36 to 43 for issuer application data + + uint8_t template[] = { 0x00, 0x00, 0x77, 0x47, 0x82, 0x02, 0x39, 0x00, 0x57, 0x13, 0x47, 0x62, 0x28, 0x00, 0x05, 0x93, 0x38, 0x64, 0xd2, 0x70, 0x92, 0x01, 0x00, 0x00, 0x01, 0x42, 0x00, 0x00, 0x0f, 0x5f, 0x34, 0x01, 0x00, 0x9f, 0x10, 0x07, 0x06, 0x01, 0x12, 0x03, 0xa0, 0x20, 0x00, 0x9f, 0x26, 0x08, 0x56, 0xcb, 0x4e, 0xe1, 0xa4, 0xef, 0xac, 0x74, 0x9f, 0x27, 0x01, 0x80, 0x9f, 0x36, 0x02, 0x00, 0x07, 0x9f, 0x6c, 0x02, 0x3e, 0x00, 0x9f, 0x6e, 0x04, 0x20, 0x70, 0x00, 0x00, 0x90, 0x00, 0xff, 0xff}; + + // do the replacement + template[1] = resp[1]; // class bit + + template[61] = resp[11]; + template[62] = resp[12]; + + template[46] = resp[16]; + template[47] = resp[17]; + template[48] = resp[18]; + template[49] = resp[19]; + template[50] = resp[20]; + template[51] = resp[21]; + template[52] = resp[22]; + template[53] = resp[23]; + template[54] = resp[24]; + + template[36] = resp[27]; + template[37] = resp[28]; + template[38] = resp[29]; + template[39] = resp[30]; + template[40] = resp[31]; + template[41] = resp[32]; + template[42] = resp[33]; + + Dbprintf("\nrearranged is: "); + len = sizeof(template); + Dbhexdump(len, &template[0], false); // special print + + AddCrc14A(&template[1], len-3); + Dbprintf("\nafter crc rearranged is: "); + Dbhexdump(len, &template[0], false); // special print + Dbprintf("\n"); + + //EmSendCmd(&template[1], len-1); + memcpy(output, &template[1], len-1); + *olen = len-1; + + BigBuf_free(); + return; + } + + //Dbhexdump(len, &resp[1], false); // special print + AddCrc14A(&resp[1], len); + Dbhexdump(len+2, &resp[1], false); // special print + + // Check we don't want to modify the response (application profile response) + //uint8_t modifyme[] = {0x03, 0x77, 0x0e, 0x82, 0x02}; + + BigBuf_free(); + + if (prepend == 0xff) { + Dbprintf("pdol request, we can can the response..."); + return; + } + + if (memcmp(&resp[2], &pay1_response[0], sizeof(pay1_response)) == 0 && true) { + Dbprintf("Switching out the pay1 response for a pay2 response..."); + //EmSendCmd(&pay2_response[0], sizeof(pay2_response)); + memcpy(output, &pay2_response[0], sizeof(pay2_response)); + *olen = sizeof(pay2_response); + } + else if (memcmp(&resp[1], &fci_template[0], 2) == 0 && true) { + Dbprintf("***** modifying response to have full fci template...!"); + //EmSendCmd(&fci_template[0], sizeof(fci_template)); + memcpy(output, &fci_template[0], sizeof(fci_template)); + *olen = sizeof(fci_template); + } else { + //Dbprintf("***** not modifying response..."); + //EmSendCmd(&resp[1], len + 2); + memcpy(output, &resp[1], len + 2); + *olen = len + 2; + } + + BigBuf_free(); + + //memcpy(saved_command, &resp[1], len+2); + //saved_command_len = len+2; + //EmSendCmd14443aRaw(&resp[1], len+2); + //FpgaDisableTracing(); + //EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA); + } + + //reply_ng(CMD_SMART_RAW, PM3_SUCCESS, resp, len); + + OUT: + //BigBuf_free(); + //set_tracing(false); + LEDsoff(); +} + +int CmdSmartRaw(const uint8_t prepend, const uint8_t *data, int dlen, uint8_t *output, uint16_t *olen) { + + Dbprintf("sending command to smart card... %02x %02x %02x... =>", prepend, data[0], data[1]); + Dbhexdump(dlen, data, false); + + if (data[4] + 5 != dlen) { + Dbprintf("invalid length of data. Received: %d, command specifies %d", dlen, data[4] + 5); + dlen = data[4] + 5; + } + + //smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + dlen); + smart_card_raw_t *payload = (smart_card_raw_t *)BigBuf_calloc(sizeof(smart_card_raw_t) + dlen); + if (payload == NULL) { + Dbprintf("failed to allocate memory"); + return PM3_EMALLOC; + } + payload->len = dlen; + memcpy(payload->data, data, dlen); + + payload->flags = SC_LOG; + bool active = true; + bool active_select = false; + int timeout = 600; + bool use_t0 = true; + + if (active || active_select) { + + payload->flags |= (SC_CONNECT | SC_CLEARLOG); + if (active_select) + payload->flags |= SC_SELECT; + } + + payload->wait_delay = 0; + if (timeout > -1) { + payload->flags |= SC_WAIT; + payload->wait_delay = timeout; + } + //Dbprintf("SIM Card timeout... %u ms", payload->wait_delay); + + if (dlen > 0) { + if (use_t0) + payload->flags |= SC_RAW_T0; + else + payload->flags |= SC_RAW; + } + + ////uint8_t *buf = calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t)); + //uint8_t *buf = BigBuf_calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t)); + //if (buf == NULL) { + // Dbprintf("failed to allocate memory"); + // free(payload); + // return PM3_EMALLOC; + //} + + + //clearCommandBuffer(); + //SendCommandNG(CMD_SMART_RAW, (uint8_t *)payload, sizeof(smart_card_raw_t) + dlen); + + //for (int i = 0; i < dlen; i++) { + // Dbprintf("%02x ", data[i]); + //} + + SmartCardDirectSend(prepend, payload, output, olen); + + //if (reply == false) { + // Dbprintf("failed to talk to smart card!!!"); + // goto out; + //} + + //// reading response from smart card + //int len = smart_response(buf, PM3_CMD_DATA_SIZE); + //if (len < 0) { + // free(payload); + // free(buf); + // return PM3_ESOFT; + //} + + //if (buf[0] == 0x6C) { + + // // request more bytes to download + // data[4] = buf[1]; + // memcpy(payload->data, data, dlen); + // clearCommandBuffer(); + // SendCommandNG(CMD_SMART_RAW, (uint8_t *)payload, sizeof(smart_card_raw_t) + dlen); + + // len = smart_response(buf, PM3_CMD_DATA_SIZE); + + // data[4] = 0; + //} + + //if (decode_tlv && len > 4) { + // TLVPrintFromBuffer(buf, len - 2); + //} else { + // if (len > 2) { + // Dbprintf("Response data:"); + // Dbprintf(" # | bytes | ascii"); + // Dbprintf("---+-------------------------------------------------+-----------------"); + // print_hex_break(buf, len, 16); + // } + //} + + //memcpy(buffer, buf, len); + + //out: + //free(payload); + //free(buf); + return PM3_SUCCESS; +} + diff --git a/armsrc/i2c_direct.h b/armsrc/i2c_direct.h new file mode 100644 index 000000000..b269f792a --- /dev/null +++ b/armsrc/i2c_direct.h @@ -0,0 +1,22 @@ +//----------------------------------------------------------------------------- +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- + +#ifndef __I2C_DIRECT_H +#define __I2C_DIRECT_H + +int CmdSmartRaw(const uint8_t prepend, const uint8_t *data, int dlen, uint8_t *output, uint16_t *olen); + +#endif diff --git a/client/src/emv/cmdemv.c b/client/src/emv/cmdemv.c index 4e4aab42b..809d7a4e5 100644 --- a/client/src/emv/cmdemv.c +++ b/client/src/emv/cmdemv.c @@ -39,7 +39,6 @@ #include "crypto/libpcrypto.h" #include "iso4217.h" // currency lookup - static int CmdHelp(const char *Cmd); #define TLV_ADD(tag, value)( tlvdb_change_or_add_node(tlvRoot, tag, sizeof(value) - 1, (const unsigned char *)value) ) @@ -630,6 +629,73 @@ static int CmdEMVSelect(const char *Cmd) { return PM3_SUCCESS; } +static int CmdEMVSmartToNFC(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "emv smart2nfc", + "Executes ISO14443a payment, TX using ISO7816 interface for authentication", + "emv smart2nfc -t -> test that the attached card is working (must be VISA)\n"); + + void *argtable[] = { + arg_param_begin, + arg_lit0("t", "test", "test that the attached card is working (must be VISA)"), + arg_str0("u", "uid", "", "optional 7 hex bytes UID"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int uid_len = 0; + uint8_t uid[7] = {0}; + CLIGetHexWithReturn(ctx, 2, uid, &uid_len); + + if (uid_len == 0) { + PrintAndLogEx(SUCCESS, "No UID provided, using default."); + uint8_t default_uid[7] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + memcpy(uid, default_uid, sizeof(default_uid)); + uid_len = sizeof(default_uid); + } else if (uid_len != 7) { + PrintAndLogEx(FAILED, "UID must be 7 bytes long."); + return PM3_EINVARG; + } + + PrintAndLogEx(SUCCESS, "UID length is %d", uid_len); + + bool testMode = arg_get_lit(ctx, 1); + bool show_apdu = true; + + if (testMode) { + PrintAndLogEx(SUCCESS, "Test mode enabled."); + } else { + PrintAndLogEx(SUCCESS, "Test mode disabled."); + } + + CLIParserFree(ctx); + + // todo: check this is relevant for us. + SetAPDULogging(show_apdu); + + struct { + uint16_t flags; + uint8_t exitAfter; + uint8_t uid[7]; + uint16_t atqa; + uint8_t sak; + } PACKED payload; + + memcpy(payload.uid, uid, uid_len); + payload.flags = 0x1204; + payload.exitAfter = 0x1; + payload.atqa = 0x0; + payload.sak = 0x20; + + clearCommandBuffer(); + SendCommandNG(0x0386, (uint8_t *)&payload, sizeof(payload)); + + PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " to abort simulation"); + + SetAPDULogging(false); + return PM3_SUCCESS; +} + static int CmdEMVSearch(const char *Cmd) { CLIParserContext *ctx; @@ -2913,8 +2979,9 @@ static command_t CommandTable[] = { {"scan", CmdEMVScan, IfPm3Iso14443, "Scan EMV card and save it contents to json file for emulator"}, {"search", CmdEMVSearch, IfPm3Iso14443, "Try to select all applets from applets list and print installed applets"}, {"select", CmdEMVSelect, IfPm3Iso14443, "Select applet"}, - /* {"-----------", CmdHelp, IfPm3Iso14443a, "---------------------- " _CYAN_("simulation") " ---------------------"}, + {"smart2nfc", CmdEMVSmartToNFC, IfPm3Iso14443, "Complete transaction as a nfc smart card, using the ISO-7816 interface for auth"}, + /* {"getrng", CmdEMVGetrng, IfPm3Iso14443, "Get random number from terminal"}, {"eload", CmdEmvELoad, IfPm3Iso14443, "Load EMV tag into device"}, {"dump", CmdEmvDump, IfPm3Iso14443, "Dump EMV tag values"}, diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 0cfc9bfaa..996b04079 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -612,6 +612,7 @@ typedef struct { #define CMD_HF_ISO14443A_SIM_AID 0x1420 #define CMD_HF_ISO14443A_READER 0x0385 +#define CMD_HF_ISO14443A_EMV_SIMULATE 0x0386 #define CMD_HF_LEGIC_SIMULATE 0x0387 #define CMD_HF_LEGIC_READER 0x0388 diff --git a/tools/deprecated-hid-flasher/flasher/usb_cmd.h b/tools/deprecated-hid-flasher/flasher/usb_cmd.h index 90a76a1be..6c614a628 100644 --- a/tools/deprecated-hid-flasher/flasher/usb_cmd.h +++ b/tools/deprecated-hid-flasher/flasher/usb_cmd.h @@ -137,6 +137,7 @@ typedef struct { #define CMD_HF_ISO14443A_SNIFF 0x0383 #define CMD_HF_ISO14443A_SIMULATE 0x0384 #define CMD_HF_ISO14443A_READER 0x0385 +#define CMD_HF_ISO14443A_EMV_SIMULATE 0x0386 #define CMD_HF_LEGIC_SIMULATE 0x0387 #define CMD_HF_LEGIC_READER 0x0388 @@ -180,7 +181,7 @@ typedef struct { #define CMD_HF_MIFARE_READER 0x0611 #define CMD_HF_MIFARE_NESTED 0x0612 -#define CMD_HF_MIFARE_ACQ_ENCRYPTED_NONCES 0x0613 +#define CMD_HF_MIFARE_ACQ_ENCRYPTED_NONCES 0x0613 #define CMD_HF_MIFARE_READBL 0x0620