From 807d4ac37e83fa24c4678f2828ea688e5eaa7303 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Thu, 30 Jun 2022 22:24:07 -0400 Subject: [PATCH] Stashing DESFire updates before tinkering with saving space with PSTR wrappers around the terminal command names --- Doc/DESFireSupportReadme.md | 201 +++--------------- .../DESFire/DESFireChameleonTerminal.c | 11 +- .../DESFire/DESFireISO14443Support.c | 169 ++++++--------- .../DESFire/DESFireISO14443Support.h | 21 +- .../DESFire/DESFireISO7816Support.h | 4 +- .../Application/DESFire/DESFireInstructions.c | 5 - .../Application/DESFire/DESFireLogging.c | 80 ++++--- .../Application/DESFire/DESFireLogging.h | 76 ++----- .../Application/DESFire/DESFirePICCControl.c | 60 ++++-- .../Application/DESFire/DESFirePICCControl.h | 16 +- .../DESFire/DESFirePICCHeaderLayout.h | 87 ++++---- .../Application/DESFire/DESFireUtils.h | 6 +- .../Chameleon-Mini/Application/ISO14443-3A.c | 7 +- .../Application/MifareDESFire.c | 87 ++++---- .../Application/MifareDESFire.h | 40 ++-- .../BuildScripts/custom_build_targets.mk | 5 +- Firmware/Chameleon-Mini/Configuration.c | 16 ++ Firmware/Chameleon-Mini/Configuration.h | 1 + Firmware/Chameleon-Mini/Makefile | 10 +- 19 files changed, 386 insertions(+), 516 deletions(-) diff --git a/Doc/DESFireSupportReadme.md b/Doc/DESFireSupportReadme.md index f5f3cd9b..e054c478 100644 --- a/Doc/DESFireSupportReadme.md +++ b/Doc/DESFireSupportReadme.md @@ -1,132 +1,5 @@ # Chameleon Mini firmware support for DESFire tag emulation -The project began based on a few open source Java-based emulation projects (Android based) and the -prior initial work to add this support on the Chameleon Mini by **@dev-zzo**. -The starting point of the current firmware code for this project was compiled from -[this firmware mod fork](https://github.com/dev-zzo/ChameleonMini/tree/desfire) as -were the known instruction (command) and status codes from the -[Android HCE (Java based code)](https://github.com/jekkos/android-hce-desfire) -repository maintained by **@jekkos**. -After that point, **@maxieds** reorganized and began work modifying and debugging the -compiled source base in [this repository](https://github.com/maxieds/ChameleonMiniDESFireStack). -Most of the preliminary testing of these firmware mods was done using the -[Chameleon Mini Live Debugger](https://github.com/maxieds/ChameleonMiniLiveDebugger) -Android logger application, and with ``libnfc`` via a -USB NFC tag reader (host-based testing code is -[available here](https://github.com/maxieds/ChameleonMiniDESFireStack/tree/master/Firmware/Chameleon-Mini/Application/DESFire/Testing)). - -The firmware has been tested and known to work with the KAOS manufactured RevG Chameleon devices. -Unfortunately, formative RevE device support is not available due to the memory requirements to -run this firmware emulation. The device responds well using the ``libnfc``-based utility -``nfc-anticol``: -```bash -NFC reader: SCM Micro / SCL3711-NFC&RW opened - -Sent bits: 26 (7 bits) -Received bits: 03 44 -Sent bits: 93 20 -Received bits: 88 23 77 00 dc -Sent bits: 93 70 88 23 77 00 dc 4b b3 -Received bits: 04 -Sent bits: 95 20 -Received bits: 0b 99 bf 98 b5 -Sent bits: 95 70 0b 99 bf 98 b5 2f 24 -Received bits: 20 -Sent bits: e0 50 bc a5 -Received bits: 75 77 81 02 80 -Sent bits: 50 00 57 cd - -Found tag with - UID: 2377000b99bf98 -ATQA: 4403 - SAK: 20 - ATS: 75 77 81 02 80 -``` -More testing needs to be done to fine tune support for interfacing the Chameleon -with live, in-the-wild DESFire tag readers in practice. It has been verified to work with the -Proxmark3 NFC devices: -```bash -[usb] pm3 --> hf 14a read -[+] UID: 4A D9 BA 11 B9 97 57 -[+] ATQA: 44 03 -[+] SAK: 20 [1] -[+] ATS: 75 77 81 02 80 -[=] field dropped. - -[usb] pm3 --> script run debug.cmd -[+] executing Cmd debug.cmd -[+] args '' -[usb|script] pm3 --> hw dbg -4 -[usb|script] pm3 --> prefs set clientdebug --full -[=] client debug........... full -[usb|script] pm3 --> data setdebugmode -2 -[=] client debug level... 2 ( verbose debug messages ) - -[#] Debug log level......... 4 ( extended ) - -[usb] pm3 --> hf mfdes info -[#] pcb_blocknum 0 == 2 -[#] [WCMD <--: : 08/08] 02 90 60 00 00 00 14 98 -[#] pcb_blocknum 1 == 3 -[#] [WCMD <--: : 08/08] 03 90 af 00 00 00 1f 15 -[#] pcb_blocknum 0 == 2 -[#] [WCMD <--: : 08/08] 02 90 af 00 00 00 34 11 - -[=] ---------------------------------- Tag Information ---------------------------------- -[+] UID: 08 4F 8A 44 7D AE 83 -[+] Batch number: AE 83 CE E4 A5 -[+] Production date: week db / 20f1 - -[=] --- Hardware Information -[=] raw: 04010100011805 -[=] Vendor Id: NXP Semiconductors Germany -[=] Type: 0x01 -[=] Subtype: 0x01 -[=] Version: 0.1 ( DESFire MF3ICD40 ) -[=] Storage size: 0x18 ( 4096 bytes ) -[=] Protocol: 0x05 ( ISO 14443-2, 14443-3 ) - -[=] --- Software Information -[=] raw: 90AF0401010001 -[=] Vendor Id: no tag-info available -[=] Type: 0xAF -[=] Subtype: 0x04 -[=] Version: 1.1 -[=] Storage size: 0x00 ( 1 bytes ) -[=] Protocol: 0x01 ( Unknown ) - -[=] --------------------------------- Card capabilities --------------------------------- -[#] switch_off - -[usb] pm3 --> hf mfdes auth -n 0 -t 3tdea -k 000000000000000000000000000000000000000000000000 -v -c native -a -[=] Key num: 0 Key algo: 3tdea Key[24]: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[=] Secure channel: n/a Command set: native Communication mode: plain -[+] Setting ISODEP -> inactive -[+] Setting ISODEP -> NFC-A -[=] AID 000000 is selected -[=] Auth: cmd: 0x1a keynum: 0x00 -[+] raw>> 1A 00 -[+] raw<< AF EE 91 30 1E E8 F5 84 D6 C7 85 1D 05 65 13 90 A6 C6 D5 -[#] encRndB: EE 91 30 1E E8 F5 84 D6 -[#] RndB: CA FE BA BE 00 11 22 33 -[#] rotRndB: FE BA BE 00 11 22 33 CA FE BA BE 00 11 22 33 CA -[#] Both : 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 FE BA BE 00 11 22 33 CA FE BA BE 00 11 22 33 CA -[+] raw>> AF 30 EB 55 F3 29 39 04 96 77 88 CE EF 33 A3 C8 7B 18 66 1A F1 62 78 A0 28 53 84 67 98 7C BB DB 03 -[+] raw<< 00 9B 71 57 8F FB DF 80 A8 F6 EF 33 4A C6 CD F9 7A 7D BE -[=] Session key : 01 02 03 04 CA FE BA BE 07 08 09 10 22 33 CA FE 13 14 15 16 00 11 22 33 -[=] Desfire authenticated -[+] PICC selected and authenticated succesfully -[+] Context: -[=] Key num: 0 Key algo: 3tdea Key[24]: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[=] Secure channel: ev1 Command set: native Communication mode: plain -[=] Session key [24]: 01 02 03 04 CA FE BA BE 07 08 09 10 22 33 CA FE 13 14 15 16 00 11 22 33 -[=] IV [8]: 00 00 00 00 00 00 00 00 -[+] Setting ISODEP -> inactive -``` -The DESFire configuration mode has been known to see recognition problems -using the ``libfreefare`` commands ``mifare-*``. This issue may be gradually -resolved as the work to bring compatibility with the PM3 devices continues. - ## Quick configuration of cloned DESFire tags ### Chameleon Mini terminal addons to support ``CONFIG=MF_DESFIRE`` modes @@ -142,20 +15,19 @@ run these commands. ```bash CONFIG=? CONFIG=MF_DESFIRE +CONFIG=MF_DESFIRE_2KEV1 +CONFIG=MF_DESFIRE_4KEV1 +CONFIG=MF_DESFIRE_4KEV2 ``` #### DF_SETHDR -- Set PICC header information The UID for the tag can be set using separate Chameleon terminal commands as usual for all other configurations. -```bash -DF_SETHDR? -101:OK WITH TEXT -DF_SETHDR -``` -We can modify the tag header information emulated by the tag as follows: +We can modify the remaining tag header information emulated by the tag as follows: ```bash DF_SETHDR=ATS xxxxxxxxxx +DF_SETHDR=ATQA xxxx DF_SETHDR=ManuID xx DF_SETHDR=HardwareVersion mmMM DF_SETHDR=SoftwareVersion mmMM @@ -173,6 +45,10 @@ To set the ATS bytes reported to emulate a JCOP tag: ```bash DF_SETHDR=ATS 0675f7b102 ``` +To reset the ATQA value returned in the anticollision loop handshaking: +``` +DF_SETHDR=ATQA 2838 +``` ##### Documentation for cloning specific tag types @@ -338,7 +214,6 @@ reset it intentionally at will for testing and debugging purposes. The syntax is as follows: ```bash -DF_COMM_MODE? DF_COMM_MODE=Plaintext DF_COMM_MODE=Plaintext:MAC DF_COMM_MODE=Enciphered:3K3DES @@ -355,24 +230,8 @@ to the defaults. Syntax -- not guaranteeing that all of these are meaningful or distinct just yet: ```bash -DF_LOGMODE? -DF_LOGMODE= -DF_LOGMODE=<0|1|TRUE|FALSE> -``` - -#### DF_TESTMODE -- Sets whether the firmware emulation is run in testing/debugging mode - -Syntax: -```bash -DF_TESTMODE? -DF_TESTMODE=<0|1|TRUE|FALSE|OFF|ON> -``` -#### DF_COMM_MODE - -Syntax: -```bash -DF_COMM_MODE? -DF_COMM_MODE= +DF_LOGMODE=0 +DF_LOGMODE=1 ``` ## Supported functionality @@ -469,6 +328,21 @@ for development of this project: ### Sources of external code and open information about the DESFire specs +The project began based on a few open source Java-based emulation projects (Android based) and the +prior initial work to add this support on the Chameleon Mini by **@dev-zzo**. +The starting point of the current firmware code for this project was compiled from +[this firmware mod fork](https://github.com/dev-zzo/ChameleonMini/tree/desfire) as +were the known instruction (command) and status codes from the +[Android HCE (Java based code)](https://github.com/jekkos/android-hce-desfire) +repository maintained by **@jekkos**. +After that point, **@maxieds** reorganized and began work modifying and debugging the +compiled source base in [this repository](https://github.com/maxieds/ChameleonMiniDESFireStack). +Most of the preliminary testing of these firmware mods was done using the +[Chameleon Mini Live Debugger](https://github.com/maxieds/ChameleonMiniLiveDebugger) +Android logger application, and with ``libnfc`` via a +USB NFC tag reader (host-based testing code is +[available here](https://github.com/maxieds/ChameleonMiniDESFireStack/tree/master/Firmware/Chameleon-Mini/Application/DESFire/Testing)). + The source code for much of this implementation has been directly adapted, or modified, from mostly Java language open source code for Android using several primary sources. Where possible, the license and credits for the original sources for this ``avr-gcc``-compatible C language code are as specified in the next @@ -478,26 +352,3 @@ repositories and code bases: * [Android HCE Framework Library (kevinvalk)](https://github.com/kevinvalk/android-hce-framework) * [AVRCryptoLib in C](https://github.com/cantora/avr-crypto-lib) * [LibFreefare DESFire Code (mostly as a reference and check point)](https://github.com/nfc-tools/libfreefare/tree/master/libfreefare) - -### Clarification: Where the local licenses apply - -The code that is not already under direct license (see below) is released according to the normal -[license for the firmware](https://github.com/emsec/ChameleonMini/blob/master/LICENSE.txt). -Additional licenses that apply only to the code used within this DESFire stack implementation, -or to the open source libraries used to derive this code, -are indicated within the local firmware directories. - -### DESFire sources header comments - -``` -The DESFire stack portion of this firmware source is free software written by Maxie Dion Schmidt (@maxieds): You can redistribute it and/or modify it under the terms of this license. - -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. - -The complete source distribution of this firmware is available at the following link: https://github.com/maxieds/ChameleonMiniFirmwareDESFireStack. - -Based in part on the original DESFire code created by @dev-zzo (GitHub handle) [Dmitry Janushkevich] available at https://github.com/dev-zzo/ChameleonMini/tree/desfire. - -This notice must be retained at the top of all source files where indicated. -``` - diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c index dad96169..948604f2 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c @@ -29,7 +29,6 @@ This notice must be retained at the top of all source files where indicated. #include "../../Terminal/Terminal.h" #include "../../Terminal/Commands.h" #include "../../Settings.h" - #include "DESFireChameleonTerminal.h" #include "DESFireFirmwareSettings.h" #include "DESFirePICCControl.h" @@ -49,7 +48,7 @@ CommandStatusIdType ExitOnInvalidConfigurationError(char *OutParam) { #ifndef DISABLE_PERMISSIVE_DESFIRE_SETTINGS CommandStatusIdType CommandDESFireGetHeaderProperty(char *OutParam) { snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, - PSTR("%s "), + PSTR("%s "), DFCOMMAND_SET_HEADER); return COMMAND_INFO_OK_WITH_TEXT_ID; } @@ -75,6 +74,14 @@ CommandStatusIdType CommandDESFireSetHeaderProperty(char *OutParam, const char * } else { memcpy(&Picc.ATSBytes[0], propSpecBytes, dataByteCount); } + } + if (!strcasecmp_P(hdrPropSpecStr, PSTR("ATQA"))) { + if (dataByteCount != 2) { + StatusError = 1; + } else { + DesfireATQAValue = ((propSpecBytes[0] << 8) & 0xFF00) | (propSpecBytes[1] & 0x00FF); + memcpy(&Picc.ATSBytes[0], propSpecBytes, dataByteCount); + } } else if (!strcasecmp_P(hdrPropSpecStr, PSTR("ManuID"))) { if (dataByteCount != 1) { StatusError = 1; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c index d91b7d0c..ac6002df 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c @@ -38,6 +38,7 @@ This notice must be retained at the top of all source files where indicated. * ISO/IEC 14443-4 implementation */ Iso144434StateType Iso144434State = ISO14443_4_STATE_EXPECT_RATS; + uint8_t Iso144434BlockNumber = 0x00; uint8_t Iso144434CardID = 0x00; uint8_t Iso144434LastBlockLength = 0x00; @@ -49,34 +50,35 @@ uint16_t ISO14443ALastDataFrameBits = 0; uint8_t ISO14443ALastIncomingDataFrame[MAX_DATA_FRAME_XFER_SIZE] = { 0x00 }; uint16_t ISO14443ALastIncomingDataFrameBits = 0; -bool CheckStateRetryCount2(bool resetByDefault, bool performLogging) { +bool CheckStateRetryCountWithLogging(bool resetByDefault, bool performLogging) { if (resetByDefault || ++StateRetryCount > MAX_STATE_RETRY_COUNT) { - ISO144434SwitchState2(Iso144433AIdleState, performLogging); + ISO144434SwitchStateWithLogging(Iso144433AIdleState, performLogging); StateRetryCount = 0x00; - const char *debugStatusMsg = PSTR("RETRY-RESET"); - LogDebuggingMsg(debugStatusMsg); + DEBUG_PRINT_P(PSTR("RETRY-RESET")); return true; } return false; } bool CheckStateRetryCount(bool resetByDefault) { - return CheckStateRetryCount2(resetByDefault, true); + return CheckStateRetryCountWithLogging(resetByDefault, true); } -void ISO144434SwitchState2(Iso144434StateType NewState, bool performLogging) { +void ISO144434SwitchStateWithLogging(Iso144434StateType NewState, bool performLogging) { Iso144434State = NewState; StateRetryCount = 0x00; +#ifdef DESFIRE_DEBUGGING && DESFIRE_DEBUGGING != 0 if (performLogging) { - DesfireLogISOStateChange(Iso144434State, LOG_ISO14443_4_STATE); + RUN_ON_DESFIRE_DEBUG(DesfireLogISOStateChange(Iso144434State, LOG_ISO14443_4_STATE)); } +#endif } void ISO144434SwitchState(Iso144434StateType NewState) { - ISO144434SwitchState2(NewState, true); + ISO144434SwitchStateWithLogging(NewState, true); } void ISO144434Reset(void) { - /* No logging -- spams the log */ + /* No logging here -- spams the log and slows things way down! */ Iso144434State = ISO14443_4_STATE_EXPECT_RATS; Iso144434BlockNumber = 1; ISO14443ALastDataFrameBits = 0; @@ -92,9 +94,8 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 /* Verify the block's length: at the very least PCB + CRCA */ if (ByteCount < (1 + ISO14443A_CRCA_SIZE)) { - /* Huh? Broken frame? */ - const char *debugPrintStr = PSTR("ISO14443-4: length fail"); - LogDebuggingMsg(debugPrintStr); + /* Broken frame -- Respond error by returning an empty frame */ + DEBUG_PRINT_P(PSTR("ISO14443-4: length fail")); return ISO14443A_APP_NO_RESPONSE; } ByteCount -= 2; @@ -103,8 +104,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 if (!ISO14443ACheckCRCA(Buffer, ByteCount)) { LogEntry(LOG_ERR_APP_CHECKSUM_FAIL, Buffer, ByteCount); /* ISO/IEC 14443-4, clause 7.5.5. The PICC does not attempt any error recovery. */ - const char *debugPrintStr = PSTR("WARN: 14443-4: CRC fail; %04X vs %04X"); - DEBUG_PRINT_P(debugPrintStr, *(uint16_t *)&Buffer[ByteCount], + DEBUG_PRINT_P(PSTR("WARN: 14443-4: CRC fail; %04X vs %04X"), *(uint16_t *)&Buffer[ByteCount], ISO14443AAppendCRCA(Buffer, ByteCount)); return ISO14443A_APP_NO_RESPONSE; } @@ -114,8 +114,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 /* See: ISO/IEC 14443-4, clause 5.6.1.2 */ if (Buffer[0] != ISO14443A_CMD_RATS) { /* Ignore blocks other than RATS and HLTA */ - const char *debugPrintStr = PSTR("ISO14443-4: NOT RATS"); - LogDebuggingMsg(debugPrintStr); + DEBUG_PRINT_P(PSTR("ISO14443-4: NOT RATS")); return ISO14443A_APP_NO_RESPONSE; } /* Process RATS. @@ -128,8 +127,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 Buffer[5] = 0x80; /* T1: dummy value for historical bytes */ ByteCount = 6; // NOT including CRC ISO144434SwitchState(ISO14443_4_STATE_ACTIVE); - const char *debugPrintStr = PSTR("ISO14443-4: SEND RATS"); - LogDebuggingMsg(debugPrintStr); + DEBUG_PRINT_P(PSTR("ISO14443-4: SEND RATS")); return ASBITS(ByteCount); // PM3 expects no CRCA bytes } case ISO14443_4_STATE_ACTIVE: { @@ -148,9 +146,8 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 PrologueLength++; /* Verify the card ID */ if ((Buffer[1] & 0xF) != Iso144434CardID) { - /* Different card ID => the frame is ignored */ - const char *debugPrintStr = PSTR("ISO14443-4: NEW CARD ID"); - LogDebuggingMsg(debugPrintStr); + /* Different card ID -- the frame is ignored */ + DEBUG_PRINT_P(PSTR("ISO14443-4: NEW CARD ID %02d"), Iso144434CardID); return ISO14443A_APP_NO_RESPONSE; } } @@ -168,16 +165,14 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 HaveNAD = PCB & ISO14443_PCB_HAS_NAD_MASK; if (HaveNAD) { PrologueLength++; - /* Not currently supported => the frame is ignored */ - const char *debugPrintStr = PSTR("ISO144434ProcessBlock: ISO14443_PCB_I_BLOCK -- %d"); - DEBUG_PRINT_P(debugPrintStr, __LINE__); + /* Not currently supported -- the frame is ignored */ + DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_I_BLOCK -- %d"), __LINE__); } /* 7.5.3.2, rule D: toggle on each I-block */ Iso144434BlockNumber = MyBlockNumber = !MyBlockNumber; if (PCB & ISO14443_PCB_I_BLOCK_CHAINING_MASK) { - /* Currently not supported => the frame is ignored */ - const char *debugPrintStr = PSTR("ISO144434ProcessBlock: ISO14443_PCB_I_BLOCK -- %d"); - DEBUG_PRINT_P(debugPrintStr, __LINE__); + /* Currently not supported -- the frame is ignored */ + DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_I_BLOCK -- %d"), __LINE__); return ISO14443A_APP_NO_RESPONSE; } @@ -193,35 +188,30 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 ByteCount = MifareDesfireProcessCommand(&Buffer[PrologueLength], ByteCount - PrologueLength); /* Short-circuit in case the app decides not to respond at all */ if (ByteCount == 0) { - const char *debugPrintStr = PSTR("ISO14443-4: APP_NO_RESP"); - LogDebuggingMsg(debugPrintStr); + DEBUG_PRINT_P(PSTR("ISO14443-4: APP_NO_RESP")); return ISO14443A_APP_NO_RESPONSE; } ByteCount += PrologueLength; - const char *debugPrintStr = PSTR("ISO14443-4: I-BLK"); - LogDebuggingMsg(debugPrintStr); + DEBUG_PRINT_P(PSTR("ISO14443-4: I-BLK")); return GetAndSetBufferCRCA(Buffer, ByteCount); } case ISO14443_PCB_R_BLOCK: { /* 7.5.4.3, rule 11 */ if ((PCB & ISO14443_PCB_BLOCK_NUMBER_MASK) == MyBlockNumber) { - /* NOTE: This already includes the CRC */ - const char *debugPrintStr = PSTR("ISO144434ProcessBlock: ISO14443_PCB_R_BLOCK -- %d"); - DEBUG_PRINT_P(debugPrintStr, __LINE__); + DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_R_BLOCK -- %d"), __LINE__); return ISO14443A_APP_NO_RESPONSE; } if (PCB & ISO14443_PCB_R_BLOCK_ACKNAK_MASK) { /* 7.5.4.3, rule 12 */ /* This is a NAK. Send an ACK back */ Buffer[0] = ISO14443_PCB_R_BLOCK_STATIC | ISO14443_PCB_R_BLOCK_ACK | MyBlockNumber; - // Per the NXP data sheet MF1S50YYX_V1 (Table 10: ACK / NAK), we should return 4 bits: + /* The NXP data sheet MF1S50YYX_V1 (Table 10: ACK / NAK) says we should return 4 bits: */ return 4; } else { - /* This is an ACK */ + /* This is an ACK: */ /* NOTE: Chaining is not supported yet. */ - const char *debugPrintStr = PSTR("ISO144434ProcessBlock: ISO14443_PCB_R_BLOCK -- %d"); - DEBUG_PRINT_P(debugPrintStr, __LINE__); + DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_R_BLOCK -- %d"), __LINE__); // Resend the data from the last frame: if (ISO14443ALastDataFrameBits > 0) { memcpy(&Buffer[0], &ISO14443ALastDataFrame[0], ASBYTES(ISO14443ALastDataFrameBits)); @@ -230,8 +220,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 return ISO14443A_APP_NO_RESPONSE; } } - const char *debugPrintStr6 = PSTR("ISO14443-4: R-BLK"); - LogDebuggingMsg(debugPrintStr6); + DEBUG_PRINT_P(PSTR("ISO14443-4: R-BLK")); return GetAndSetBufferCRCA(Buffer, ByteCount); } @@ -244,12 +233,10 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 ISO144433AHalt(); /* Answer with S(DESELECT) -- just send the copy of the message */ ByteCount = PrologueLength; - const char *debugPrintStr = PSTR("ISO14443-4: S-BLK"); - LogDebuggingMsg(debugPrintStr); + DEBUG_PRINT_P(PSTR("ISO14443-4: S-BLK")); return GetAndSetBufferCRCA(Buffer, ByteCount); } - const char *debugPrintStr5 = PSTR("ISO14443-4: PCB_S_BLK NO_RESP"); - LogDebuggingMsg(debugPrintStr5); + DEBUG_PRINT_P(PSTR("ISO14443-4: PCB_S_BLK NO_RESP")); return ISO14443A_APP_NO_RESPONSE; } @@ -286,11 +273,11 @@ Iso144433AStateType Iso144433AIdleState = ISO14443_3A_STATE_IDLE; void ISO144433ASwitchState(Iso144433AStateType NewState) { Iso144433AState = NewState; StateRetryCount = 0x00; - DesfireLogISOStateChange(Iso144433AState, LOG_ISO14443_3A_STATE); + RUN_ON_DESFIRE_DEBUG(DesfireLogISOStateChange(Iso144433AState, LOG_ISO14443_3A_STATE)); } void ISO144433AReset(void) { - /* No logging -- spams the log */ + /* No logging performed -- spams the log and slows things way down! */ Iso144433AState = ISO14443_3A_STATE_IDLE; Iso144433AIdleState = ISO14443_3A_STATE_IDLE; ISO14443ALastDataFrameBits = 0; @@ -304,10 +291,10 @@ void ISO144433AHalt(void) { } bool ISO144433AIsHalt(const uint8_t *Buffer, uint16_t BitCount) { - return BitCount == ISO14443A_HLTA_FRAME_SIZE + ASBITS(ISO14443A_CRCA_SIZE) - && Buffer[0] == ISO14443A_CMD_HLTA - && Buffer[1] == 0x00 - && ISO14443ACheckCRCA(Buffer, ASBYTES(ISO14443A_HLTA_FRAME_SIZE)); + return BitCount == ISO14443A_HLTA_FRAME_SIZE + ASBITS(ISO14443A_CRCA_SIZE) && + Buffer[0] == ISO14443A_CMD_HLTA && + Buffer[1] == 0x00 && + ISO14443ACheckCRCA(Buffer, ASBYTES(ISO14443A_HLTA_FRAME_SIZE)); } uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { @@ -324,20 +311,16 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { bool checkStateRetryStatus = CheckStateRetryCount(false); bool incrementRetryCount = true; if (Cmd == ISO14443A_CMD_REQA) { - LOG_AT_LEVEL(LogEntry(LOG_INFO_APP_CMD_REQA, NULL, 0), VERBOSE); - //ISO144434Reset(); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_APP_CMD_REQA, NULL, 0)); ISO144433ASwitchState(ISO14443_3A_STATE_IDLE); incrementRetryCount = false; } else if (ISO14443ACmdIsWUPA(Cmd)) { - LOG_AT_LEVEL(LogEntry(LOG_INFO_APP_CMD_WUPA, NULL, 0), VERBOSE); - //ISO144434Reset(); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_APP_CMD_WUPA, NULL, 0)); ISO144433ASwitchState(ISO14443_3A_STATE_IDLE); incrementRetryCount = false; - //return ISO14443A_APP_NO_RESPONSE; } else if (ISO144433AIsHalt(Buffer, BitCount)) { - LOG_AT_LEVEL(LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0), VERBOSE); - const char *logMsg = PSTR("ISO14443-3: HALTING"); - LogDebuggingMsg(logMsg); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0)); + DEBUG_PRINT_P(PSTR("ISO14443-3: HALTING")); ISO144433AHalt(); return ISO14443A_APP_NO_RESPONSE; } @@ -352,8 +335,7 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { switch (Iso144433AState) { case ISO14443_3A_STATE_HALT: if (!ISO14443ACmdIsWUPA(Cmd)) { - const char *debugPrintStr = PSTR("ISO14443-4: HALT / NOT WUPA"); - LogDebuggingMsg(debugPrintStr); + DEBUG_PRINT_P(PSTR("ISO14443-4: HALT -- NOT WUPA")); break; } else { ISO144433ASwitchState(ISO14443_3A_STATE_IDLE); @@ -363,10 +345,9 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { case ISO14443_3A_STATE_IDLE: Iso144433AIdleState = Iso144433AState; ISO144433ASwitchState(ISO14443_3A_STATE_READY1); - Buffer[0] = (ATQA_VALUE) & 0x00FF; - Buffer[1] = (ATQA_VALUE >> 8) & 0x00FF; - const char *debugPrintStr = PSTR("ISO14443-4 (IDLE): ATQA"); - LogDebuggingMsg(debugPrintStr); + Buffer[0] = DesfireATQAValue & 0x00FF; + Buffer[1] = (DesfireATQAValue >> 8) & 0x00FF; + DEBUG_PRINT_P(PSTR("ISO14443-4 (IDLE): ATQA -- %04x"), DesfireATQAValue); return ASBITS(ISO14443A_ATQA_FRAME_SIZE_BYTES); case ISO14443_3A_STATE_READY1: @@ -382,17 +363,14 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { } if (ISO14443ASelectDesfire(Buffer, &BitCount, Uid, SAK_CL1_VALUE)) { /* CL1 stage has ended successfully */ - const char *debugPrintStr = PSTR("ISO14443-4: Select OK"); - LogDebuggingMsg(debugPrintStr); + DEBUG_PRINT_P(PSTR("ISO14443-4: Select OK")); ISO144433ASwitchState(ISO14443_3A_STATE_READY2); } else { - const char *debugPrintStr = PSTR("ISO14443-4: Select NAK"); - LogDebuggingMsg(debugPrintStr); + DEBUG_PRINT_P(PSTR("ISO14443-4: Select NAK")); } return BitCount; } - const char *debugPrintStr4 = PSTR("ISO14443-4: RDY1, NOT SLCT CMD"); - LogDebuggingMsg(debugPrintStr4); + DEBUG_PRINT_P(PSTR("ISO14443-4: RDY1 -- NOT SLCT CMD")); break; case ISO14443_3A_STATE_READY2: @@ -404,59 +382,39 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { /* CL2 stage has ended successfully. This means * our complete UID has been sent to the reader. */ ISO144433ASwitchState(ISO14443_3A_STATE_ACTIVE); - const char *debugPrintStr = PSTR("INTO ACTIVE!"); - LogDebuggingMsg(debugPrintStr); } else { - const char *debugPrintStr = PSTR("Incorrect Select value (R2)"); - LogDebuggingMsg(debugPrintStr); + DEBUG_PRINT_P(PSTR("ISO14443-4: Incorrect select value (R2)")); } return BitCount; } - const char *debugPrintStr3 = PSTR("RDY2, NOT SLCT CMD"); - LogDebuggingMsg(debugPrintStr3); + DEBUG_PRINT_P(PSTR("ISO14443-4: RDY2 -- NOT SLCT CMD")); break; case ISO14443_3A_STATE_ACTIVE: StateRetryCount = MAX_STATE_RETRY_COUNT; - /* Recognise the HLTA command */ if (ISO144433AIsHalt(Buffer, BitCount)) { - LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0); + /* Recognise the HLTA command: */ + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0)); ISO144434SwitchState(ISO14443_3A_STATE_HALT); - const char *logMsg = PSTR("ISO14443-3: Got HALT"); - LogDebuggingMsg(logMsg); + DEBUG_PRINT_P(PSTR("ISO14443-3: Got HALT")); return ISO14443A_APP_NO_RESPONSE; } else if (Cmd == ISO14443A_CMD_RATS) { ISO144433ASwitchState(ISO14443_4_STATE_EXPECT_RATS); - const char *logMsg = PSTR("ISO14443-3/4: EXPECTING RATS"); - LogDebuggingMsg(logMsg); + DEBUG_PRINT_P(PSTR("ISO14443-3/4: Expecting RATS")); } else if (Cmd == ISO14443A_CMD_SELECT_CL3) { Buffer[0] = ISO14443A_SAK_COMPLETE_NOT_COMPLIANT; ISO14443AAppendCRCA(&Buffer[0], 1); return ISO14443A_SAK_FRAME_SIZE; } else if (Cmd == ISO14443A_CMD_DESELECT) { - LOG_AT_LEVEL(LogEntry(LOG_INFO_APP_CMD_DESELECT, NULL, 0), VERBOSE); - /* See if the process can make sense of the first byte: */ - //uint16_t ByteCount = ASBYTES(BitCount); - //uint16_t ReturnBits = ISO144434ProcessBlock(Buffer, ByteCount, BitCount); - //if (ReturnBits > 0) { - // return ReturnBits; - //} - /* Otherwise (doesn't seem to work): Return a HALT frame to the reader: */ - //Buffer[0] = ISO14443A_CMD_HLTA; - //Buffer[1] = 0x00; - //ISO14443AAppendCRCA(&Buffer[0], 2); - //ISO144434SwitchState(ISO14443_3A_STATE_HALT); - //return ISO14443A_DESELECT_FRAME_SIZE; - /* Otherwise: Return a WUPA frame to the reader to reset: */ - //Buffer[0] = ISO14443A_CMD_WUPA; - //ISO144434SwitchState(ISO14443_3A_STATE_HALT); - //return ASBITS(1); + /* This has been observed to happen at this stage when swiping the + * Chameleon running CONFIG=MF_DESFIRE on an ACR122 USB external reader. + */ + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_APP_CMD_DESELECT, NULL, 0)); } /* Forward to ISO/IEC 14443-4 processing code */ uint16_t ByteCount = ASBYTES(BitCount); uint16_t ReturnBits = ISO144434ProcessBlock(Buffer, ByteCount, BitCount); - const char *debugPrintStr2 = PSTR("ISO14443-4: ACTIVE RET"); - LogDebuggingMsg(debugPrintStr2); + DEBUG_PRINT_P(PSTR("ISO14443-4: ACTIVE RET")); return ReturnBits; default: @@ -467,13 +425,12 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { /* Fallthrough: Unknown command. Reset back to idle/halt state. */ bool defaultReset = false; if (!CheckStateRetryCount(defaultReset)) { - const char *logMsg = PSTR("ISO14443-3: RESET TO IDLE 0x%02x"); - DEBUG_PRINT_P(logMsg, Cmd); + DEBUG_PRINT_P(PSTR("ISO14443-3: Fall through -- RESET TO IDLE 0x%02x"), Cmd); + return ISO14443A_APP_NO_RESPONSE; + } else { + DEBUG_PRINT_P(PSTR("ISO14443-4: UNK-CMD NO RESP")); return ISO14443A_APP_NO_RESPONSE; } - const char *debugPrintStr = PSTR("ISO14443-4: UNK-CMD NO_RESP"); - LogDebuggingMsg(debugPrintStr); - return ISO14443A_APP_NO_RESPONSE; } diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h index c2a75a83..a5cacd61 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h @@ -115,16 +115,14 @@ INLINE ISO14443AStoreLastDataFrameAndReturn(const uint8_t *Buffer, uint16_t Buff return BufferBitCount; } -/* Setup some fuzzy response handling for problematic readers like the ACR122U */ - -#define MAX_STATE_RETRY_COUNT (0x0b) +#define MAX_STATE_RETRY_COUNT (0x04) extern uint8_t StateRetryCount; bool CheckStateRetryCount(bool resetByDefault); -bool CheckStateRetryCount2(bool resetByDefault, bool performLogging); +bool CheckStateRetryCountWithLogging(bool resetByDefault, bool performLogging); /* Support functions */ void ISO144434SwitchState(Iso144434StateType NewState); -void ISO144434SwitchState2(Iso144434StateType NewState, bool performLogging); +void ISO144434SwitchStateWithLogging(Iso144434StateType NewState, bool performLogging); void ISO144434Reset(void); static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t BitCount); @@ -133,6 +131,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 * ISO/IEC 14443-3A implementation */ #define ISO14443A_CRCA_INIT ((uint16_t) 0x6363) +uint16_t ISO14443AUpdateCRCA(const uint8_t *Buffer, uint16_t ByteCount, uint16_t InitCRCA); #define GetAndSetBufferCRCA(Buffer, ByteCount) ({ \ uint16_t fullReturnBits = 0; \ @@ -147,17 +146,15 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 fullReturnBits; \ }) -uint16_t ISO14443AUpdateCRCA(const uint8_t *Buffer, uint16_t ByteCount, uint16_t InitCRCA); - typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { - /* The card is powered up but not selected */ - ISO14443_3A_STATE_IDLE = ISO14443_4_STATE_LAST, - /* Entered on REQA or WUPA; anticollision is being performed */ + /* The card is powered up but not selected: */ + ISO14443_3A_STATE_IDLE = ISO14443_4_STATE_LAST + 1, + /* Entered on REQA or WUP -- anticollision is being performed: */ ISO14443_3A_STATE_READY1, ISO14443_3A_STATE_READY2, - /* Entered when the card has been selected */ + /* Entered when the card has been selected: */ ISO14443_3A_STATE_ACTIVE, - /* Something went wrong or we've received a halt command */ + /* Something went wrong or we've received a halt command: */ ISO14443_3A_STATE_HALT, } Iso144433AStateType; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h index bea09a96..eb7474df 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h @@ -88,9 +88,11 @@ typedef enum { ISO7816_WRAPPED_CMD_TYPE_STANDARD = 1, ISO7816_WRAPPED_CMD_TYPE_PM3RAW = 2, ISO7816_WRAPPED_CMD_TYPE_PM3_ADDITIONAL_FRAME = 3, - /* ??? Others ??? */ + /* TODO -- Others ??? */ } Iso7816WrappedCommandType_t; +extern Iso7816WrappedCommandType_t Iso7816CmdType; + Iso7816WrappedCommandType_t IsWrappedISO7816CommandType(uint8_t *Buffer, uint16_t ByteCount); uint16_t SetIso7816WrappedParametersType(uint8_t *Buffer, uint16_t ByteCount); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index bf933c25..09774cb7 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -1155,7 +1155,6 @@ uint16_t EV0CmdGetFileSettings(uint8_t *Buffer, uint16_t ByteCount) { } uint16_t EV0CmdChangeFileSettings(uint8_t *Buffer, uint16_t ByteCount) { - DESFireLogSourceCodeTODO("", GetSourceFileLoggingData()); Buffer[0] = STATUS_ILLEGAL_COMMAND_CODE; // TODO return DESFIRE_STATUS_RESPONSE_SIZE; } @@ -1618,10 +1617,6 @@ uint16_t EV0CmdClearRecords(uint8_t *Buffer, uint16_t ByteCount) { Status = STATUS_LENGTH_ERROR; return ExitWithStatus(Buffer, Status, DESFIRE_STATUS_RESPONSE_SIZE); } - - - - DESFireLogSourceCodeTODO("", GetSourceFileLoggingData()); Buffer[0] = STATUS_ILLEGAL_COMMAND_CODE; // TODO return DESFIRE_STATUS_RESPONSE_SIZE; } diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.c index 5e2247b1..1285797e 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.c @@ -28,7 +28,7 @@ This notice must be retained at the top of all source files where indicated. #include "../../Log.h" #include "../../Terminal/Terminal.h" - +#include "DESFireISO14443Support.h" #include "DESFireLogging.h" #ifdef DESFIRE_DEFAULT_DEBUGGING_MODE @@ -43,34 +43,60 @@ BYTE LocalTestingMode = DESFIRE_DEFAULT_TESTING_MODE; BYTE LocalTestingMode = 0x00; #endif -void DESFireLogErrorMessage(char *fmtMsg, ...) { - char Format[80]; - char Buffer[80]; - va_list args; - strcpy_P(Format, fmtMsg); - va_start(args, fmtMsg); - vsnprintf(Buffer, sizeof(Buffer), Format, args); - va_end(args); - LogEntry(LOG_ERR_DESFIRE_GENERIC_ERROR, Buffer, StringLength(Buffer, 80) + 1); -} - -void DESFireLogSourceCodeTODO(char *implNoteMsg, char *srcFileLoggingData) { - char *bigDataBuffer = (char *) __InternalStringBuffer; - snprintf_P(bigDataBuffer, STRING_BUFFER_SIZE, PSTR("%s: %s"), - implNoteMsg, srcFileLoggingData); - SIZET logMsgBufferSize = StringLength(bigDataBuffer, STRING_BUFFER_SIZE); - LogEntry(LOG_INFO_DESFIRE_DEBUGGING_OUTPUT, bigDataBuffer, logMsgBufferSize + 1); +#ifdef DESFIRE_DEBUGGING && DESFIRE_DEBUGGING != 0 +void DesfireLogEntry(LogEntryEnum LogCode, void *LogDataBuffer, uint16_t BufSize) { + if (BufSize >= DESFIRE_MIN_OUTGOING_LOGSIZE) { + LogEntry(LogCode, (void *) LogDataBuffer, BufSize); + } } +#else +void DesfireLogEntry(LogEntryEnum LogCode, void *LogDataBuffer, uint16_t BufSize) {} +#endif -void DebugPrintP(const char *fmt, ...) { - char Format[80]; - char Buffer[80]; - va_list args; - strcpy_P(Format, fmt); - va_start(args, fmt); - vsnprintf(Buffer, sizeof(Buffer), Format, args); - va_end(args); - TerminalSendString(Buffer); +#ifdef DESFIRE_DEBUGGING && DESFIRE_DEBUGGING != 0 +void DesfireLogISOStateChange(int state, int logCode) { + const char *statePrintName; + int logLength = 0; + do { + switch (logCode) { + case ISO14443_4_STATE_EXPECT_RATS: + statePrintName = PSTR("ISO14443_4_STATE_EXPECT_RATS"); + break; + case ISO14443_4_STATE_ACTIVE: + statePrintName = PSTR("ISO14443_4_STATE_ACTIVE"); + break; + case ISO14443_4_STATE_LAST: + statePrintName = PSTR("ISO14443_4_STATE_LAST"); + break; + case ISO14443_3A_STATE_IDLE: + statePrintName = PSTR("ISO14443_3A_STATE_IDLE"); + break; + case ISO14443_3A_STATE_READY1: + statePrintName = PSTR("ISO14443_3A_STATE_READY1"); + break; + case ISO14443_3A_STATE_READY2: + statePrintName = PSTR("ISO14443_3A_STATE_READY2"); + break; + case ISO14443_3A_STATE_ACTIVE: + statePrintName = PSTR("ISO14443_3A_STATE_ACTIVE"); + break; + case ISO14443_3A_STATE_HALT: + statePrintName = PSTR("ISO14443_3A_STATE_HALT"); + break; + default: + statePrintName = PSTR("Unknown state"); + break; + } + } while (0); + snprintf_P(STRING_BUFFER_SIZE, (char *) __InternalStringBuffer, + PSTR("State CHG -- %s"), statePrintName); + logLength = StringLength((char *) __InternalStringBuffer, + STRING_BUFFER_SIZE); + DesfireLogEntry(LOG_ERR_DESFIRE_GENERIC_ERROR, + (char *) __InternalStringBuffer, logLength); } +#else +void DesfireLogISOStateChange(int state, int logCode) {} +#endif #endif /* CONFIG_MF_DESFIRE_SUPPORT */ diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h index 5dc8684f..87c94192 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h @@ -39,12 +39,6 @@ This notice must be retained at the top of all source files where indicated. #define DESFIRE_MIN_OUTGOING_LOGSIZE (1) #endif -INLINE void DesfireLogEntry(LogEntryEnum LogCode, void *LogDataBuffer, uint16_t BufSize) { - if (DESFIRE_MIN_OUTGOING_LOGSIZE <= BufSize) { - LogEntry(LogCode, (void *) LogDataBuffer, BufSize); - } -} - typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { OFF = 0, NORMAL = 1, @@ -56,14 +50,6 @@ typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { #define DESFIRE_DEFAULT_LOGGING_MODE (OFF) #endif -#define LOG_AT_LEVEL(cmdToRun, loggingThreshold) ({ \ - do { \ - if (loggingThreshold <= DESFIRE_DEFAULT_LOGGING_MODE) { \ - cmdToRun; \ - } \ - } while(0); \ - }) - extern DESFireLoggingMode LocalLoggingMode; /* @@ -75,41 +61,40 @@ extern DESFireLoggingMode LocalLoggingMode; */ extern BYTE LocalTestingMode; -void DESFireLogErrorMessage(char *fmtMsg, ...); -void DESFireLogStatus(BYTE *bufMsg, SIZET bufSize); -void DESFireLogDebuggingMessage(char *fmtMsg, ...); -void DESFireLogSourceCodeTODO(char *implNoteMsg, char *srcFileLoggingData); -void DESFireLogIncomingData(BYTE *byteBuf, SIZET bufLength); -void DESFireLogOutgoingData(BYTE *byteBuf, SIZET bufLength); -void DESFireLogNativeCommand(BYTE *Buffer, SIZET ByteCount); -void DESFireLogISO1443Command(BYTE *Buffer, SIZET ByteCount); -void DESFireLogISO7816Command(BYTE *Buffer, SIZET ByteCount); -void DESFireLogSetProtectedData(BYTE *pdataBuf, SIZET byteBufSize); -void DESFireLogPICCHardReset(BYTE *strBuf, SIZET strLength); -void DESFireLogPICCSoftReset(BYTE *strBuf, SIZET strLength); - -void DebugPrintP(const char *fmt, ...); -#define DEBUG_PRINT(fmt, ...) DebugPrintP(PSTR(fmt), ##__VA_ARGS__) +void DesfireLogEntry(LogEntryEnum LogCode, void *LogDataBuffer, uint16_t BufSize); +void DesfireLogISOStateChange(int state, int logCode); +#ifdef DESFIRE_DEBUGGING && DESFIRE_DEBUGGING != 0 #define DEBUG_PRINT_P(fmtStr, ...) ({ \ uint8_t logLength = 0; \ do { \ snprintf_P((char *) __InternalStringBuffer, STRING_BUFFER_SIZE, \ - fmtStr, ##__VA_ARGS__); \ - logLength = StringLength((char *) __InternalStringBuffer, \ - STRING_BUFFER_SIZE); \ - DesfireLogEntry(LOG_ERR_DESFIRE_GENERIC_ERROR, \ - (char *) __InternalStringBuffer, logLength); \ + fmtStr, ##__VA_ARGS__); \ + logLength = StringLength((char *) __InternalStringBuffer, \ + STRING_BUFFER_SIZE); \ + DesfireLogEntry(LOG_ERR_DESFIRE_GENERIC_ERROR, \ + (char *) __InternalStringBuffer, logLength); \ } while(0); \ }) +#else +#define DEBUG_PRINT_P(fmtStr, ...) ({}) +#endif + +#ifdef DESFIRE_DEBUGGING && DESFIRE_DEBUGGING != 0 +#define RUN_ON_DESFIRE_DEBUG(cppStmtToRun) ({ \ + cppStmtToRun; \ + }) +#else +#define RUN_ON_DESFIRE_DEBUG(cppStmtToRun) ({}) +#endif #define GetSourceFileLoggingData() ({ \ char *strBuffer; \ do { \ - snprintf_P(__InternalStringBuffer, STRING_BUFFER_SIZE, \ - PSTR("@@ LINE #%d in *%s @@"), \ - __LINE__, __FILE__); \ - __InternalStringBuffer[STRING_BUFFER_SIZE - 1] = '\0'; \ + snprintf_P(__InternalStringBuffer, STRING_BUFFER_SIZE, \ + PSTR(" @@ LINE #%d in *%s @@"), \ + __LINE__, __FILE__); \ + __InternalStringBuffer[STRING_BUFFER_SIZE - 1] = '\0'; \ } while(0); \ strBuffer = __InternalStringBuffer; \ strBuffer; \ @@ -137,19 +122,4 @@ void DebugPrintP(const char *fmt, ...); strBuffer; \ }) -#if defined(DESFIRE_DEFAULT_LOGGING_MODE) && DESFIRE_DEFAULT_LOGGING_MODE != 0 -#define LogDebuggingMsg(msg) ({ \ - do { \ - strncpy_P((char *) __InternalStringBuffer, msg, STRING_BUFFER_SIZE); \ - uint8_t sbufLength = StringLength((char *) __InternalStringBuffer, STRING_BUFFER_SIZE); \ - LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, (void *) __InternalStringBuffer, \ - sbufLength); \ - } while(0); \ - }) -#else -#define LogDebuggingMsg(msg) ({}) -#endif - -#define DesfireLogISOStateChange(state, logCode) ({}) - #endif diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c index 8d5ce194..cf04ccf6 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c @@ -59,6 +59,8 @@ SIZET DESFIRE_INITIAL_FIRST_FREE_BLOCK_ID = 0; SIZET DESFIRE_FIRST_FREE_BLOCK_ID = 0; SIZET CardCapacityBlocks = 0; +uint16_t DesfireATQAValue = DESFIRE_DEFAULT_ATQA_VALUE; + void InitBlockSizes(void) { DESFIRE_PICC_INFO_BLOCK_ID = 0; DESFIRE_APP_DIR_BLOCK_ID = DESFIRE_PICC_INFO_BLOCK_ID + @@ -103,13 +105,13 @@ TransferStatus PiccToPcdTransfer(uint8_t *Buffer) { //} /* Encrypt */ //Status.BytesProcessed = TransferState.ReadData.Encryption.Func(Buffer, XferBytes); - //Status.IsComplete = TransferState.ReadData.Encryption.AvailablePlaintext == 0; + Status.IsComplete = TransferState.ReadData.Encryption.AvailablePlaintext == 0; Status.BytesProcessed = XferBytes; Status.IsComplete = TransferState.ReadData.BytesLeft == 0; } else { /* Final encryption block */ //Status.BytesProcessed = TransferState.ReadData.Encryption.Func(Buffer, 0); - //Status.IsComplete = true; + Status.IsComplete = true; Status.BytesProcessed = 0; Status.IsComplete = true; } @@ -144,7 +146,7 @@ uint8_t ReadDataFilterSetup(uint8_t CommSettings) { SessionIVByteSize = CRYPTO_3KTDEA_KEY_SIZE; break; case DESFIRE_COMMS_CIPHERTEXT_AES128: - // A.k.a., CommMode=FULL from NXP application note AN12343: + /* A.k.a., CommMode=FULL from NXP application note AN12343: */ TransferState.Checksums.UpdateFunc = &TransferChecksumUpdateCMAC; TransferState.Checksums.FinalFunc = &TransferChecksumFinalCMAC; TransferState.Checksums.MACData.CRCA = ISO14443A_CRCA_INIT; // TODO ??? @@ -210,9 +212,8 @@ void InitialisePiccBackendEV0(uint8_t StorageSize, bool formatPICC) { MemoryRecall(); ReadBlockBytes(&Picc, DESFIRE_PICC_INFO_BLOCK_ID, sizeof(DESFirePICCInfoType)); if (formatPICC) { - snprintf_P(__InternalStringBuffer, STRING_BUFFER_SIZE, PSTR("Factory reset -- EV0")); - LogEntry(LOG_INFO_DESFIRE_PICC_RESET, (void *) __InternalStringBuffer, - StringLength(__InternalStringBuffer, STRING_BUFFER_SIZE)); + DEBUG_PRINT_P(PSTR("Factory reset -- EV0")); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_PICC_RESET, (void *) NULL, 0)); FactoryFormatPiccEV0(); } else { ReadBlockBytes(&AppDir, DESFIRE_APP_DIR_BLOCK_ID, sizeof(DESFireAppDirType)); @@ -230,9 +231,8 @@ void InitialisePiccBackendEV1(uint8_t StorageSize, bool formatPICC) { MemoryRecall(); ReadBlockBytes(&Picc, DESFIRE_PICC_INFO_BLOCK_ID, sizeof(DESFirePICCInfoType)); if (formatPICC) { - snprintf_P(__InternalStringBuffer, STRING_BUFFER_SIZE, PSTR("Factory reset -- EV1")); - LogEntry(LOG_INFO_DESFIRE_PICC_RESET, (void *) __InternalStringBuffer, - StringLength(__InternalStringBuffer, STRING_BUFFER_SIZE)); + DEBUG_PRINT_P(PSTR("Factory reset -- EV1")); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_PICC_RESET, (void *) NULL, 0)); FactoryFormatPiccEV1(StorageSize); } else { ReadBlockBytes(&AppDir, DESFIRE_APP_DIR_BLOCK_ID, sizeof(DESFireAppDirType)); @@ -240,6 +240,26 @@ void InitialisePiccBackendEV1(uint8_t StorageSize, bool formatPICC) { } } +void InitialisePiccBackendEV2(uint8_t StorageSize, bool formatPICC) { +#ifdef DESFIRE_RUN_CRYPTO_TESTING_PROCEDURE + RunCryptoUnitTests(); +#endif + /* Init backend */ + InitBlockSizes(); + CardCapacityBlocks = StorageSize; + MemoryRecall(); + ReadBlockBytes(&Picc, DESFIRE_PICC_INFO_BLOCK_ID, sizeof(DESFirePICCInfoType)); + if (formatPICC) { + DEBUG_PRINT_P(PSTR("Factory reset -- EV1")); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_PICC_RESET, (void *) NULL, 0)); + FactoryFormatPiccEV2(StorageSize); + } else { + ReadBlockBytes(&AppDir, DESFIRE_APP_DIR_BLOCK_ID, sizeof(DESFireAppDirType)); + SelectPiccApp(); + } + +} + void ResetPiccBackend(void) { InitBlockSizes(); SelectPiccApp(); @@ -293,9 +313,9 @@ void FormatPicc(void) { BYTE batchNumberData[5]; RandomGetBuffer(batchNumberData, 5); memcpy(&Picc.BatchNumber[0], batchNumberData, 5); - /* Production dates should be obvious until the user changes them: */ - Picc.ProductionWeek = 0x44; - Picc.ProductionYear = 0x7c; + /* Default production date -- until the user changes them: */ + Picc.ProductionWeek = 0x00; + Picc.ProductionYear = 0x00; /* Assign the default manufacturer ID: */ Picc.ManufacturerID = DESFIRE_MANUFACTURER_ID; /* Set the ATS bytes to defaults: */ @@ -359,6 +379,22 @@ void FactoryFormatPiccEV1(uint8_t StorageSize) { FormatPicc(); } +void FactoryFormatPiccEV2(uint8_t StorageSize) { + /* Wipe PICC data */ + memset(&Picc, PICC_FORMAT_BYTE, sizeof(Picc)); + /* Initialize params to look like EV1 */ + Picc.StorageSize = StorageSize; + Picc.HwVersionMajor = DESFIRE_HW_MAJOR_EV2; + Picc.HwVersionMinor = DESFIRE_HW_MINOR_EV2; + Picc.SwVersionMajor = DESFIRE_SW_MAJOR_EV2; + Picc.SwVersionMinor = DESFIRE_SW_MINOR_EV2; + /* Reset the free block pointer */ + Picc.FirstFreeBlock = DESFIRE_FIRST_FREE_BLOCK_ID; + /* Continue with user data initialization */ + SynchronizePICCInfo(); + FormatPicc(); +} + void GetPiccUid(ConfigurationUidType Uid) { memcpy(Uid, Picc.Uid, DESFIRE_UID_SIZE); } diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.h index 8ddfb0ff..919e4d5d 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.h @@ -114,18 +114,26 @@ uint8_t ReadDataFilterSetup(uint8_t CommSettings); uint8_t WriteDataFilterSetup(uint8_t CommSettings); /* PICC management */ +void FormatPicc(void); +void CreatePiccApp(void); + void InitialisePiccBackendEV0(uint8_t StorageSize, bool formatPICC); void InitialisePiccBackendEV1(uint8_t StorageSize, bool formatPICC); +void InitialisePiccBackendEV2(uint8_t StorageSize, bool formatPICC); + +void FactoryFormatPiccEV0(void); +void FactoryFormatPiccEV1(uint8_t StorageSize); +void FactoryFormatPiccEV2(uint8_t StorageSize); + void ResetPiccBackend(void); + bool IsEmulatingEV1(void); + void GetPiccHardwareVersionInfo(uint8_t *Buffer); void GetPiccSoftwareVersionInfo(uint8_t *Buffer); void GetPiccManufactureInfo(uint8_t *Buffer); uint8_t GetPiccKeySettings(void); -void FormatPicc(void); -void CreatePiccApp(void); -void FactoryFormatPiccEV0(void); -void FactoryFormatPiccEV1(uint8_t StorageSize); + void GetPiccUid(ConfigurationUidType Uid); void SetPiccUid(ConfigurationUidType Uid); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h index 592b542f..c3866e20 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h @@ -30,44 +30,42 @@ This notice must be retained at the top of all source files where indicated. #include "DESFireFirmwareSettings.h" #include "DESFireISO14443Support.h" -#define DESFIRE_PICC_APP_SLOT 0x00 -#define DESFIRE_MASTER_KEY_ID 0x00 +#define DESFIRE_PICC_APP_SLOT 0x00 +#define DESFIRE_MASTER_KEY_ID 0x00 -#define DESFIRE_NATIVE_CLA 0x90 -#define DESFIRE_ISO7816_CLA 0x00 +#define DESFIRE_NATIVE_CLA 0x90 +#define DESFIRE_ISO7816_CLA 0x00 /* Storage allocation constants */ -#define DESFIRE_BLOCK_SIZE (1) /* Bytes */ -#define DESFIRE_BYTES_TO_BLOCKS(x) ( ((x) + DESFIRE_BLOCK_SIZE - 1) / DESFIRE_BLOCK_SIZE ) +#define DESFIRE_BLOCK_SIZE (1) /* Bytes */ +#define DESFIRE_BYTES_TO_BLOCKS(x) (((x) + DESFIRE_BLOCK_SIZE - 1) / DESFIRE_BLOCK_SIZE) -#define DESFIRE_UID_SIZE ISO14443A_UID_SIZE_DOUBLE -#define DESFIRE_MAX_PAYLOAD_SIZE (64) /* Bytes */ +#define DESFIRE_UID_SIZE ISO14443A_UID_SIZE_DOUBLE +#define DESFIRE_MAX_PAYLOAD_SIZE (64) /* Bytes */ /* * Definitions pertaining to on-card data */ /* Anticollision parameters */ -#define ATQA_VALUE 0x0344 +#define DESFIRE_DEFAULT_ATQA_VALUE 0x0344 +extern uint16_t DesfireATQAValue; + #ifndef FORCE_SAK_NOT_COMPLIANT -#define SAK_CL1_VALUE (ISO14443A_SAK_INCOMPLETE) -#define SAK_CL2_VALUE (ISO14443A_SAK_COMPLETE_COMPLIANT) +#define SAK_CL1_VALUE (ISO14443A_SAK_INCOMPLETE) +#define SAK_CL2_VALUE (ISO14443A_SAK_COMPLETE_COMPLIANT) #else -#define SAK_CL1_VALUE (ISO14443A_SAK_INCOMPLETE_NOT_COMPLIANT) -#define SAK_CL2_VALUE (ISO14443A_SAK_COMPLETE_NOT_COMPLIANT) +#define SAK_CL1_VALUE (ISO14443A_SAK_INCOMPLETE_NOT_COMPLIANT) +#define SAK_CL2_VALUE (ISO14443A_SAK_COMPLETE_NOT_COMPLIANT) #endif -#define STATUS_FRAME_SIZE (1 * 8) /* Bits */ - -#define DESFIRE_EV0_ATS_TL_BYTE 0x06 /* TL: ATS length, 6 bytes */ -#define DESFIRE_EV0_ATS_T0_BYTE 0x75 /* T0: TA, TB, TC present; max accepted frame is 64 bytes */ -#define DESFIRE_EV0_ATS_TA_BYTE 0x00 /* TA: Only the lowest bit rate is supported (normal is 0x77) */ -#define DESFIRE_EV0_ATS_TB_BYTE 0x81 /* TB: taken from the DESFire spec */ -#define DESFIRE_EV0_ATS_TC_BYTE 0x02 /* TC: taken from the DESFire spec */ +#define STATUS_FRAME_SIZE (1 * 8) /* Bits */ -#define GET_LE16(p) (*((uint16_t*)&(p)[0])) -#define GET_LE24(p) (*((__uint24*)&(p)[0])) -#define GET_LE32(p) (*((uint32_t*)&(p)[0])) +#define DESFIRE_EV0_ATS_TL_BYTE 0x06 /* TL: ATS length, 6 bytes */ +#define DESFIRE_EV0_ATS_T0_BYTE 0x75 /* T0: TA, TB, TC present; max accepted frame is 64 bytes */ +#define DESFIRE_EV0_ATS_TA_BYTE 0x00 /* TA: Only the lowest bit rate is supported (normal is 0x77) */ +#define DESFIRE_EV0_ATS_TB_BYTE 0x81 /* TB: taken from the DESFire spec */ +#define DESFIRE_EV0_ATS_TC_BYTE 0x02 /* TC: taken from the DESFire spec */ /* Defines for GetVersion */ #define ID_PHILIPS_NXP 0x04 @@ -80,36 +78,42 @@ This notice must be retained at the top of all source files where indicated. #define DESFIRE_SW_PROTOCOL_TYPE 0x05 /** Source: http://www.proxmark.org/forum/viewtopic.php?id=2982 **/ +#define MIFARE_DESFIRE_EV0 0x00 +#define MIFARE_DESFIRE_EV1 0x01 +#define MIFARE_DESFIRE_EV2 0x02 + /* DESFire EV0 versions */ -#define DESFIRE_HW_MAJOR_EV0 0x00 -#define DESFIRE_HW_MINOR_EV0 0x01 -#define DESFIRE_SW_MAJOR_EV0 0x00 -#define DESFIRE_SW_MINOR_EV0 0x01 +#define DESFIRE_HW_MAJOR_EV0 0x00 +#define DESFIRE_HW_MINOR_EV0 0x01 +#define DESFIRE_SW_MAJOR_EV0 0x00 +#define DESFIRE_SW_MINOR_EV0 0x01 -#define IsPiccEV0(picc) (picc.HwVersionMajor == DESFIRE_HW_MAJOR_EV0 && picc.SwVersionMajor == DESFIRE_SW_MAJOR_EV0) +#define IsPiccEV0(picc) \ + (picc.HwVersionMajor == DESFIRE_HW_MAJOR_EV0 && \ + picc.SwVersionMajor == DESFIRE_SW_MAJOR_EV0) /* DESFire EV1 versions */ -#define DESFIRE_HW_MAJOR_EV1 0x01 -#define DESFIRE_HW_MINOR_EV1 0x01 -#define DESFIRE_SW_MAJOR_EV1 0x01 -#define DESFIRE_SW_MINOR_EV1 0x01 +#define DESFIRE_HW_MAJOR_EV1 0x01 +#define DESFIRE_HW_MINOR_EV1 0x01 +#define DESFIRE_SW_MAJOR_EV1 0x01 +#define DESFIRE_SW_MINOR_EV1 0x01 /* DESFire EV2 versions */ -#define DESFIRE_HW_MAJOR_EV2 0x12 -#define DESFIRE_HW_MINOR_EV2 0x01 -#define DESFIRE_SW_MAJOR_EV2 0x12 -#define DESFIRE_SW_MINOR_EV2 0x01 +#define DESFIRE_HW_MAJOR_EV2 0x12 +#define DESFIRE_HW_MINOR_EV2 0x01 +#define DESFIRE_SW_MAJOR_EV2 0x12 +#define DESFIRE_SW_MINOR_EV2 0x01 -#define DESFIRE_STORAGE_SIZE_2K 0x16 -#define DESFIRE_STORAGE_SIZE_4K 0x18 -#define DESFIRE_STORAGE_SIZE_8K 0x1A +#define DESFIRE_STORAGE_SIZE_2K 0x16 +#define DESFIRE_STORAGE_SIZE_4K 0x18 +#define DESFIRE_STORAGE_SIZE_8K 0x1A /* * Defines the global PICC configuration. * This is located in the very first block on the card. */ -#define PICC_FORMAT_BYTE (0x00) -#define PICC_EMPTY_BYTE (0x00) +#define PICC_FORMAT_BYTE 0x00 +#define PICC_EMPTY_BYTE 0x00 typedef struct { /* Static data: does not change during the PICC's lifetime. @@ -148,7 +152,6 @@ typedef struct { SIZET KeyVersionsArray; /* Block offset in FRAM */ SIZET KeyTypesArray; /* Block offset in FRAM */ SIZET KeyAddress; /* Block offset in FRAM */ - //UINT DirtyFlags; // USED ANYWHERE ??? } SelectedAppCacheType DESFIRE_FIRMWARE_PACKING; extern BYTE SELECTED_APP_CACHE_TYPE_BLOCK_SIZE; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h index e2eb91a4..25cc6f0e 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h @@ -34,6 +34,10 @@ This notice must be retained at the top of all source files where indicated. #define ASBYTES(bc) (((bc) + BITS_PER_BYTE - 1) / BITS_PER_BYTE) #define ASBITS(bc) ((bc) * BITS_PER_BYTE) +#define GET_LE16(p) (*((uint16_t*)&(p)[0])) +#define GET_LE24(p) (*((__uint24*)&(p)[0])) +#define GET_LE32(p) (*((uint32_t*)&(p)[0])) + #define UnsignedTypeToUINT(typeValue) \ ((UINT) typeValue) #define ExtractLSBLE(ui) \ @@ -68,7 +72,7 @@ bool DesfireCheckParityBits(uint8_t *Buffer, uint16_t BitCount); * SessionKey arrays are initialized in the Authenticate(Legacy|ISO|AES) commands * used to initiate the working session from PCD <--> PICC. * - * Helper methods to format and encode quirky or pathological cases of the + * Helper methods to format and encode quirky cases of the * CommSettings and wrapped APDU format combinations are defined statically in the * C source file to save space in the symbol table for the firmware (ELF) binary. */ diff --git a/Firmware/Chameleon-Mini/Application/ISO14443-3A.c b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c index 2ba520e7..067a04f6 100644 --- a/Firmware/Chameleon-Mini/Application/ISO14443-3A.c +++ b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c @@ -11,10 +11,8 @@ #include "DESFire/DESFireISO14443Support.h" bool ISO14443ASelectDesfire(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, uint8_t SAKValue) { - uint8_t *DataPtr = (uint8_t *) Buffer; uint8_t NVB = DataPtr[1]; - switch (NVB) { case ISO14443A_NVB_AC_START: @@ -30,10 +28,7 @@ bool ISO14443ASelectDesfire(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, ui case ISO14443A_NVB_AC_END: /* End of anticollision procedure. * Send SAK CLn if we are selected. */ - if ((DataPtr[2] == UidCL[0]) && - (DataPtr[3] == UidCL[1]) && - (DataPtr[4] == UidCL[2]) && - (DataPtr[5] == UidCL[3])) { + if (!memcmp(&DataPtr[2], &UidCL[0], 4)) { DataPtr[0] = SAKValue; ISO14443AAppendCRCA(Buffer, 1); *BitCount = ISO14443A_SAK_FRAME_SIZE; diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index a266a482..9941797a 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -43,36 +43,32 @@ This notice must be retained at the top of all source files where indicated. #include "DESFire/DESFireLogging.h" #include "DESFire/DESFireUtils.h" -#define MIFARE_DESFIRE_EV0 (0x00) -#define MIFARE_DESFIRE_EV1 (0x01) -#define MIFARE_DESFIRE_EV2 (0x02) - -#define IsControlCmd(Buffer, BitCount) \ - (BitCount > 0 && \ +#define IsControlCmd(Buffer, BitCount) \ + (BitCount > 0 && \ ((Buffer[0] == ISO14443A_CMD_WUPA) || \ (Buffer[0] == ISO14443A_CMD_REQA))) DesfireStateType DesfireState = DESFIRE_HALT; DesfireStateType DesfirePreviousState = DESFIRE_IDLE; -bool DesfireFromHalt = false; -BYTE DesfireCmdCLA = DESFIRE_NATIVE_CLA; + Iso7816WrappedCommandType_t Iso7816CmdType; -/* Dispatching routines */ -void MifareDesfireReset(void) { - DesfireState = DESFIRE_IDLE; -} +bool DesfireFromHalt = false; +BYTE DesfireCmdCLA = DESFIRE_NATIVE_CLA; static void MifareDesfireAppInitLocal(uint8_t StorageSize, uint8_t Version, bool FormatPICC) { ResetLocalStructureData(); DesfireState = DESFIRE_IDLE; DesfireFromHalt = false; switch (Version) { + case MIFARE_DESFIRE_EV2: + InitialisePiccBackendEV1(StorageSize, FormatPICC); + break; case MIFARE_DESFIRE_EV1: InitialisePiccBackendEV1(StorageSize, FormatPICC); break; case MIFARE_DESFIRE_EV0: - default: /* Fall through */ + default: /* Fall through: */ InitialisePiccBackendEV0(StorageSize, FormatPICC); break; } @@ -103,33 +99,30 @@ void MifareDesfire4kEV1AppInitRunOnce(void) { MifareDesfireAppInitLocal(DESFIRE_STORAGE_SIZE_4K, MIFARE_DESFIRE_EV1, true); } -void MifareDesfire8kEV1AppInit(void) { - MifareDesfireAppInitLocal(DESFIRE_STORAGE_SIZE_8K, MIFARE_DESFIRE_EV1, false); +void MifareDesfire4kEV2AppInit(void) { + MifareDesfireAppInitLocal(DESFIRE_STORAGE_SIZE_4K, MIFARE_DESFIRE_EV2, false); } -void MifareDesfire8kEV1AppInitRunOnce(void) { - MifareDesfireAppInitLocal(DESFIRE_STORAGE_SIZE_8K, MIFARE_DESFIRE_EV1, true); +void MifareDesfire4kEV2AppInitRunOnce(void) { + MifareDesfireAppInitLocal(DESFIRE_STORAGE_SIZE_4K, MIFARE_DESFIRE_EV2, true); } void MifareDesfireAppReset(void) { - /* This is called repeatedly, so limit the amount of work done */ - ISO144433AReset(); - ISO144434Reset(); + /* This is called repeatedly -- limit the amount of work done */ MifareDesfireReset(); } void MifareDesfireAppTick(void) { - if (CheckStateRetryCount2(false, true)) { - MifareDesfireAppReset(); - } + /* EMPTY -- Do nothing. */ } void MifareDesfireAppTask(void) { - /* Empty */ + /* EMPTY -- Do nothing. */ } uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount)); if (ByteCount == 0) { return ISO14443A_APP_NO_RESPONSE; } else if (MutualAuthenticateCmd(Buffer[0])) { @@ -164,15 +157,15 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { ReturnBytes = DesfireCmdAuthenticateAES2(Buffer, ByteCount); break; case DESFIRE_ISO7816_EXT_AUTH: - DEBUG_PRINT_P(PSTR("TODO -- ISO7816-ExtAuth")); + DEBUG_PRINT_P(PSTR("Not Implemented -- ISO7816-ExtAuth")); ReturnBytes = ISO14443A_APP_NO_RESPONSE; break; case DESFIRE_ISO7816_INT_AUTH: - DEBUG_PRINT_P(PSTR("TODO -- ISO7816-IntAuth")); + DEBUG_PRINT_P(PSTR("Not Implemented -- ISO7816-IntAuth")); ReturnBytes = ISO14443A_APP_NO_RESPONSE; break; case DESFIRE_ISO7816_GET_CHALLENGE: - DEBUG_PRINT_P(PSTR("TODO -- ISO7816-GetChall")); + DEBUG_PRINT_P(PSTR("Not Implemented -- ISO7816-GetChal")); ReturnBytes = ISO14443A_APP_NO_RESPONSE; break; case DESFIRE_READ_DATA_FILE: @@ -183,6 +176,7 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { break; default: /* Should not happen. */ + DEBUG_PRINT_P(PSTR("ERROR -- Unexpected state!")); Buffer[0] = STATUS_PICC_INTEGRITY_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; } @@ -193,7 +187,8 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { DesfireCmdCLA = Buffer[0]; size_t ByteCount = ASBYTES(BitCount); - LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount)); + ResetISOState(); if (ByteCount == 0) { return ISO14443A_APP_NO_RESPONSE; } else if (ByteCount >= 2 && Buffer[1] == STATUS_ADDITIONAL_FRAME && DesfireCLA(Buffer[0])) { @@ -247,12 +242,11 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { uint16_t ReturnedBytes = 0; uint16_t ByteCount = ASBYTES(BitCount); - LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount); - if (ByteCount > 1 && - !memcmp(&Buffer[0], &ISO14443ALastIncomingDataFrame[0], MIN(ASBYTES(ISO14443ALastIncomingDataFrameBits), ByteCount))) { + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount)); + if (ByteCount > 1 && !memcmp(&Buffer[0], &ISO14443ALastIncomingDataFrame[0], MIN(ASBYTES(ISO14443ALastIncomingDataFrameBits), ByteCount))) { /* The PCD resent the same data frame (probably a synchronization issue): * Send out the same data as last time: - */ + */ memcpy(&Buffer[0], &ISO14443ALastDataFrame[0], ASBYTES(ISO14443ALastDataFrameBits)); return ISO14443ALastDataFrameBits; } else { @@ -260,8 +254,7 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { ISO14443ALastIncomingDataFrameBits = BitCount; LastReaderSentCmd = Buffer[0]; } - if (ByteCount >= 3 && Buffer[2] == STATUS_ADDITIONAL_FRAME && - DesfireStateExpectingAdditionalFrame(DesfireState)) { + if (ByteCount >= 3 && Buffer[2] == STATUS_ADDITIONAL_FRAME && DesfireStateExpectingAdditionalFrame(DesfireState)) { /* [PM3-V1] : Handle the ISO-prologue-only-wrapped version of the additional frame data: */ uint8_t ISO7816PrologueBytes[2]; memcpy(&ISO7816PrologueBytes[0], &Buffer[0], 2); @@ -277,7 +270,7 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { } memcpy(&Buffer[0], &ISO7816PrologueBytes[0], 2); ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount + 2); - LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount)); return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ProcessedByteCount)); } else if (ByteCount >= 5 && DesfireCLA(Buffer[0]) && Buffer[1] == STATUS_ADDITIONAL_FRAME && Buffer[2] == 0x00 && Buffer[3] == 0x00 && Buffer[4] == ByteCount - 9 && @@ -302,7 +295,7 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { Buffer[ProcessedByteCount - 1] = 0x91; ++ProcessedByteCount; ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount + 2); - LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount)); return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ProcessedByteCount)); } else if (ByteCount >= 8 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && Buffer[3] == 0x00 && Buffer[4] == ByteCount - 8) { @@ -315,7 +308,7 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { return ISO14443A_APP_NO_RESPONSE; } ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount); - LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount)); return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ProcessedByteCount)); } else if (ByteCount >= 8 && DesfireCLA(Buffer[1]) && Buffer[3] == 0x00 && Buffer[4] == 0x00 && Buffer[5] == ByteCount - 8) { @@ -335,7 +328,7 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { memmove(&Buffer[1], &Buffer[0], ProcessedByteCount); Buffer[0] = hf14AScanPrologue; ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount); - LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount)); return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ProcessedByteCount)); } Iso7816CmdType = IsWrappedISO7816CommandType(Buffer, ByteCount); @@ -385,11 +378,12 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { } memcpy(&Buffer[0], &ISO7816PrologueBytes[0], 2); ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount + 2); - LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount)); return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ProcessedByteCount)); } else if ((ReturnedBytes = CallInstructionHandler(Buffer, ByteCount)) != ISO14443A_APP_NO_RESPONSE) { /* This case should handle non-wrappped native commands. No pre/postprocessing afterwards: */ - LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ReturnedBytes); + ResetISOState(); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ReturnedBytes)); return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ReturnedBytes)); } else { uint16_t PiccProcessRespBits = ISO144433APiccProcess(Buffer, BitCount); @@ -397,12 +391,17 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { if (PiccProcessRespBits >= BITS_PER_BYTE) { PiccProcessRespBits = ASBITS(PiccProcessRespBytesCeil); } - LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, PiccProcessRespBytesCeil); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, PiccProcessRespBytesCeil)); return ISO14443AStoreLastDataFrameAndReturn(Buffer, PiccProcessRespBits); } return ISO14443A_APP_NO_RESPONSE; } +void MifareDesfireReset(void) { + ResetISOState(); + DesfireState = DESFIRE_IDLE; +} + void ResetLocalStructureData(void) { DesfirePreviousState = DESFIRE_IDLE; DesfireState = DESFIRE_HALT; @@ -417,11 +416,15 @@ void ResetLocalStructureData(void) { SessionIVByteSize = 0x00; SelectedApp.Slot = 0; SelectedFile.Num = -1; + MifareDesfireReset(); +} + +void ResetISOState(void) { ISO144433AReset(); ISO144434Reset(); - MifareDesfireReset(); } + void MifareDesfireGetUid(ConfigurationUidType Uid) { GetPiccUid(Uid); } diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.h b/Firmware/Chameleon-Mini/Application/MifareDESFire.h index 59792dc8..c4c6a2cf 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.h +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.h @@ -37,19 +37,15 @@ This notice must be retained at the top of all source files where indicated. #include "DESFire/DESFireISO7816Support.h" #include "DESFire/DESFireInstructions.h" -/* The core functions used outside of this implementation - * to describe the DESFire emulation to the Chameleon firmware: - */ -void ResetLocalStructureData(void); -void MifareDesfireReset(void); void MifareDesfireEV0AppInit(void); void MifareDesfireEV0AppInitRunOnce(void); void MifareDesfire2kEV1AppInit(void); void MifareDesfire2kEV1AppInitRunOnce(void); void MifareDesfire4kEV1AppInit(void); void MifareDesfire4kEV1AppInitRunOnce(void); -void MifareDesfire8kEV1AppInit(void); -void MifareDesfire8kEV1AppInitRunOnce(void); +void MifareDesfire4kEV2AppInit(void); +void MifareDesfire4kEV2AppInitRunOnce(void); + void MifareDesfireAppReset(void); void MifareDesfireAppTick(void); void MifareDesfireAppTask(void); @@ -58,18 +54,15 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount); uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t ByteCount); uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount); +void MifareDesfireReset(void); +void ResetLocalStructureData(void); +void ResetISOState(void); + void MifareDesfireGetUid(ConfigurationUidType Uid); void MifareDesfireSetUid(ConfigurationUidType Uid); -/* Helper function definitions since we need them - * elsewhere in the backend, and so we do not need to - * declare them as static in the source. - */ -#define DesfireCLA(cmdCode) \ - ((cmdCode == DESFIRE_NATIVE_CLA) || Iso7816CLA(cmdCode)) - typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { - DESFIRE_HALT, + DESFIRE_HALT = ISO14443_3A_STATE_HALT + 1, DESFIRE_IDLE, DESFIRE_IDLE2, DESFIRE_GET_VERSION2, @@ -88,6 +81,17 @@ typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { DESFIRE_WRITE_DATA_FILE, } DesfireStateType; +extern DesfireStateType DesfireState; +extern DesfireStateType DesfirePreviousState; + +extern Iso7816WrappedCommandType_t Iso7816CmdType; + +extern bool DesfireFromHalt; +extern BYTE DesfireCmdCLA; + +#define DesfireCLA(cmdCode) \ + ((cmdCode == DESFIRE_NATIVE_CLA) || Iso7816CLA(cmdCode)) + #define DesfireStateExpectingAdditionalFrame(dfState) \ ((dfState == DESFIRE_GET_VERSION2) || \ (dfState == DESFIRE_GET_VERSION3) || \ @@ -103,10 +107,4 @@ typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { (cmdCode == CMD_ISO7816_INTERNAL_AUTHENTICATE) || \ (cmdCode == CMD_ISO7816_GET_CHALLENGE)) -extern DesfireStateType DesfireState; -extern DesfireStateType DesfirePreviousState; -extern bool DesfireFromHalt; -extern BYTE DesfireCmdCLA; -extern Iso7816WrappedCommandType_t Iso7816CmdType; - #endif /* MIFAREDESFIRE_H_ */ diff --git a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk index 8f41d4e0..17dcb327 100644 --- a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk +++ b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk @@ -63,7 +63,7 @@ desfire: TARGET_CUSTOM_BUILD_NAME:=DESFire desfire: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) desfire: custom-build -desfire-dev: FLASH_DATA_SIZE_CONST:=0C000 # Six settings (save some space): 6 * 0x2000 +desfire-dev: FLASH_DATA_SIZE_CONST:=08000 # Four settings (save some space): 4 * 0x2000 desfire-dev: FLASH_DATA_SIZE:=0x$(FLASH_DATA_SIZE_CONST) desfire-dev: FLASH_DATA_SIZE_UPPER_CONST:=20000 desfire-dev: FLASH_DATA_ADDR:=0x$(shell echo "obase=16;ibase=16;$(FLASH_DATA_SIZE_UPPER_CONST)-$(FLASH_DATA_SIZE_CONST)" | bc) @@ -74,7 +74,8 @@ desfire-dev: EXTRA_CONFIG_SETTINGS:=-DMEMORY_LIMITED_TESTING \ -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 \ -DDESFIRE_MIN_INCOMING_LOGSIZE=0 \ -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING \ - -DDESFIRE_DEFAULT_TESTING_MODE=1 + -DDESFIRE_DEFAULT_TESTING_MODE=1 \ + -DDESFIRE_DEBUGGING=1 desfire-dev: TARGET_CUSTOM_BUILD_NAME:=DESFire_DEV desfire-dev: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) desfire-dev: custom-build diff --git a/Firmware/Chameleon-Mini/Configuration.c b/Firmware/Chameleon-Mini/Configuration.c index fe804ab4..8a314be8 100644 --- a/Firmware/Chameleon-Mini/Configuration.c +++ b/Firmware/Chameleon-Mini/Configuration.c @@ -492,6 +492,22 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .MemorySize = MIFARE_CLASSIC_4K_MEM_SIZE, .ReadOnly = false }, + [CONFIG_MF_DESFIRE_4KEV2] = { + .CodecInitFunc = ISO14443ACodecInit, + .CodecDeInitFunc = ISO14443ACodecDeInit, + .CodecTaskFunc = ISO14443ACodecTask, + .ApplicationInitFunc = MifareDesfire4kEV2AppInit, + .ApplicationInitRunOnceFunc = MifareDesfire4kEV2AppInitRunOnce, + .ApplicationResetFunc = MifareDesfireAppReset, + .ApplicationTaskFunc = MifareDesfireAppTask, + .ApplicationTickFunc = MifareDesfireAppTick, + .ApplicationProcessFunc = MifareDesfireAppProcess, + .ApplicationGetUidFunc = MifareDesfireGetUid, + .ApplicationSetUidFunc = MifareDesfireSetUid, + .UidSize = ISO14443A_UID_SIZE_DOUBLE, + .MemorySize = MIFARE_CLASSIC_4K_MEM_SIZE, + .ReadOnly = false + }, #endif }; diff --git a/Firmware/Chameleon-Mini/Configuration.h b/Firmware/Chameleon-Mini/Configuration.h index 2ed04938..9a0f5aba 100644 --- a/Firmware/Chameleon-Mini/Configuration.h +++ b/Firmware/Chameleon-Mini/Configuration.h @@ -74,6 +74,7 @@ typedef enum { CONFIG_MF_DESFIRE, CONFIG_MF_DESFIRE_2KEV1, CONFIG_MF_DESFIRE_4KEV1, + CONFIG_MF_DESFIRE_4KEV2, #endif /* This HAS to be the last element */ CONFIG_COUNT diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 3965ffe6..d184bcb7 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -365,17 +365,17 @@ dfu-prog: $(TARGET).hex $(TARGET).eep check_size dfu-programmer $(MCU) reset check_size: BASH:=$(if $(shell which bash), $(shell which bash), /bin/bash) -check_size: BASH_SCRIPT_EXEC_LINES:=' \ +check_size: BASH_SCRIPT_EXEC_LINES:=' \ set -e; \ if [[ ! -f $(TARGET).elf ]]; then \ - exit 0; \ + exit 0; \ fi; \ PROGMEM_SIZE=$$(avr-size $(TARGET).elf | grep $(CHECK_SIZE_GREP_ARGS) | sed -n 4p); \ MAX_PRGMEM_SIZE=$$(printf "%d\n" $(FLASH_DATA_ADDR)); \ if [[ $$PROGMEM_SIZE -gt $$MAX_PRGMEM_SIZE ]]; then \ - echo \"make: *** $(TARGET).elf Application Section size $$PROGMEM_SIZE \" \ - echo \"excedes maximum allowed $$MAX_PRGMEM_SIZE. Please disable some features in Makefile\"; \ - exit 1; \ + $(ECHO) \"make: *** $(TARGET).elf Application Section size $$PROGMEM_SIZE \" \ + $(ECHO) \"excedes maximum allowed $$MAX_PRGMEM_SIZE. Please disable some features in Makefile\"; \ + exit 1; \ fi; \ ' check_size: