From aafc5ab2e24a484eecb80df4459ba9c2b16346a6 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Wed, 16 Mar 2022 03:03:03 -0400 Subject: [PATCH] Stashing more incremental updates to the code to get/verify PM3 compatibility --- .../DESFire/DESFireISO14443Support.c | 23 +++++++++---------- .../DESFire/DESFireISO14443Support.h | 5 +++- .../DESFire/DESFireISO7816Support.c | 10 ++++---- .../DESFire/DESFireISO7816Support.h | 7 ++++++ .../Application/MifareDESFire.c | 20 ++++++++++++---- .../Application/MifareDESFire.h | 1 + 6 files changed, 45 insertions(+), 21 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c index 80043722..bac41854 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c @@ -127,7 +127,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 ISO144434SwitchState(ISO14443_4_STATE_ACTIVE); const char *debugPrintStr = PSTR("ISO14443-4: SEND RATS"); LogDebuggingMsg(debugPrintStr); - return GetAndSetBufferCRCA(Buffer, ByteCount); + return ByteCount * BITS_PER_BYTE; // PM3 expects no CRCA bytes } case ISO14443_4_STATE_ACTIVE: { /* See: ISO/IEC 14443-4; 7.1 Block format */ @@ -277,6 +277,7 @@ Iso144433AStateType Iso144433AIdleState = ISO14443_3A_STATE_IDLE; void ISO144433ASwitchState(Iso144433AStateType NewState) { Iso144433AState = NewState; + StateRetryCount = 0x00; DesfireLogISOStateChange(Iso144433AState, LOG_ISO14443_3A_STATE); } @@ -316,9 +317,9 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { REQA bytes, in between which we would have already sent back a response, so that we should not reset. */ decrementRetryCount = false; - } else if (Cmd == ISO14443A_CMD_REQA || Cmd == ISO14443A_CMD_WUPA) { + } else if (Cmd == ISO14443A_CMD_REQA || ISO14443ACmdIsWUPA(Cmd)) { ISO144434Reset(); - ISO144433ASwitchState(ISO14443_3A_STATE_READY1); + ISO144433ASwitchState(ISO14443_3A_STATE_IDLE); decrementRetryCount = false; } else if (ISO144433AIsHalt(Buffer, BitCount)) { LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0); @@ -339,7 +340,7 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { /* See: ISO/IEC 14443-3, clause 6.2 */ switch (Iso144433AState) { case ISO14443_3A_STATE_HALT: - if (Cmd != ISO14443A_CMD_WUPA) { + if (!ISO14443ACmdIsWUPA(Cmd)) { const char *debugPrintStr = PSTR("ISO14443-4: HALT / NOT WUPA"); LogDebuggingMsg(debugPrintStr); break; @@ -349,12 +350,6 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { /* Fall-through */ case ISO14443_3A_STATE_IDLE: - if (Cmd != ISO14443A_CMD_REQA && - Cmd != ISO14443A_CMD_WUPA) { - const char *debugPrintStr = PSTR("ISO14443-4: IDLE / NOT WUPA 0x%02x"); - DEBUG_PRINT_P(debugPrintStr); - break; - } Iso144433AIdleState = Iso144433AState; ISO144433ASwitchState(ISO14443_3A_STATE_READY1); Buffer[0] = (ATQA_VALUE) & 0x00FF; @@ -364,7 +359,7 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { return ISO14443A_ATQA_FRAME_SIZE_BYTES * BITS_PER_BYTE; case ISO14443_3A_STATE_READY1: - if (Cmd == ISO14443A_CMD_SELECT_CL1 || Cmd == ISO14443A_CMD_REQA || Cmd == ISO14443A_CMD_WUPA) { + if (Cmd == ISO14443A_CMD_SELECT_CL1 || Cmd == ISO14443A_CMD_REQA || ISO14443ACmdIsWUPA(Cmd)) { /* Load UID CL1 and perform anticollision. */ ConfigurationUidType Uid; ApplicationGetUid(Uid); @@ -414,10 +409,14 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { /* Recognise the HLTA command */ if (ISO144433AIsHalt(Buffer, BitCount)) { LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0); - ISO144433ASwitchState(ISO14443_3A_STATE_HALT); + ISO144434SwitchState(ISO14443_3A_STATE_HALT); const char *logMsg = PSTR("ISO14443-3: Got HALT"); LogDebuggingMsg(logMsg); 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); } /* Forward to ISO/IEC 14443-4 processing code */ uint16_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h index b7c02096..73931a75 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h @@ -45,6 +45,9 @@ This notice must be retained at the top of all source files where indicated. #define ISO14443A_CMD_RNAK 0xB2 #define ISO14443A_CRC_FRAME_SIZE (ISO14443A_CRCA_SIZE * BITS_PER_BYTE) +#define ISO14443ACmdIsPM3WUPA(cmd) ((cmd & 0x54) == 0x54) +#define ISO14443ACmdIsWUPA(cmd) ((cmd == ISO14443A_CMD_WUPA) || ISO14443ACmdIsPM3WUPA(cmd)) + #define ISO14443_PCB_BLOCK_TYPE_MASK 0xC0 #define ISO14443_PCB_I_BLOCK 0x00 #define ISO14443_PCB_R_BLOCK 0x80 @@ -109,7 +112,7 @@ INLINE ISO14443AStoreLastDataFrameAndReturn(const uint8_t *Buffer, uint16_t Buff /* Setup some fuzzy response handling for problematic readers like the ACR122U */ -#define MAX_STATE_RETRY_COUNT (4) +#define MAX_STATE_RETRY_COUNT (0x8f) /* For all intensive purposes, as many as necessary */ extern uint8_t StateRetryCount; bool CheckStateRetryCount(bool resetByDefault); bool CheckStateRetryCount2(bool resetByDefault, bool performLogging); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c index 52b2e547..749ce28d 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c @@ -36,13 +36,15 @@ uint8_t Iso7816EfIdNumber = ISO7816_EF_NOT_SPECIFIED; bool IsWrappedISO7816CommandType(uint8_t *Buffer, uint16_t ByteCount) { if (ByteCount <= ISO7816_PROLOGUE_SIZE + ISO14443A_CRCA_SIZE + 2) { - return false; + return ISO7816_WRAPPED_CMD_TYPE_NONE; } else if (!ISO14443ACheckCRCA(Buffer, ByteCount - 2)) { - return false; + return ISO7816_WRAPPED_CMD_TYPE_NONE; + } else if (ByteCount >= 4 && Buffer[3] == ByteCount - 4) { + return ISO7816_WRAPPED_CMD_TYPE_PM3RAW; } else if (!Iso7816CLA(Buffer[2])) { - return false; + return ISO7816_WRAPPED_CMD_TYPE_NONE; } - return true; + return ISO7816_WRAPPED_CMD_TYPE_STANDARD; } uint16_t SetIso7816WrappedParametersType(uint8_t *Buffer, uint16_t ByteCount) { diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h index 4330d7f2..c24b82ca 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h @@ -83,6 +83,13 @@ extern bool Iso7816FileSelected; extern uint8_t Iso7816FileOffset; extern uint8_t Iso7816EfIdNumber; +typedef enum { + ISO7816_WRAPPED_CMD_TYPE_NONE = 0, + ISO7816_WRAPPED_CMD_TYPE_STANDARD, + ISO7816_WRAPPED_CMD_TYPE_PM3RAW, + /* Others ??? */ +} Iso7816WrappedCommandType_t; + bool IsWrappedISO7816CommandType(uint8_t *Buffer, uint16_t ByteCount); uint16_t SetIso7816WrappedParametersType(uint8_t *Buffer, uint16_t ByteCount); diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index 13ed9684..181a9585 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -51,6 +51,7 @@ DesfireStateType DesfireState = DESFIRE_HALT; DesfireStateType DesfirePreviousState = DESFIRE_IDLE; bool DesfireFromHalt = false; BYTE DesfireCmdCLA = DESFIRE_NATIVE_CLA; +Iso7816WrappedCommandType_t Iso7816CmdType; static bool AnticolNoResp = false; /* Dispatching routines */ @@ -223,13 +224,22 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { uint16_t UnwrappedBitCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, IncomingByteCount) * BITS_PER_BYTE; uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; - return ISO14443AStoreLastDataFrameAndReturn(Buffer, DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount) * BITS_PER_BYTE); - } else if (IsWrappedISO7816CommandType(Buffer, ByteCount)) { - DesfireCmdCLA = Buffer[2]; + return ISO14443AStoreLastDataFrameAndReturn(Buffer, + DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount) * BITS_PER_BYTE); + } else if ((Iso7816CmdType = IsWrappedISO7816CommandType(Buffer, ByteCount)) && Iso7816CmdType != ISO7816_WRAPPED_CMD_TYPE_NONE) { + DesfireCmdCLA = (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_STANDARD) ? Buffer[2] : DESFIRE_ISO7816_CLA; uint8_t ISO7816PrologueBytes[2]; memcpy(&ISO7816PrologueBytes[0], Buffer, 2); uint16_t IncomingByteCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, IncomingByteCount); - memmove(&Buffer[0], &Buffer[2], IncomingByteCount - 2); + if (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_STANDARD) { + memmove(&Buffer[0], &Buffer[2], IncomingByteCount - 2); + } else if (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_PM3RAW) { + Buffer[0] = DesfireCmdCLA; + Buffer[1] = Buffer[2]; + Buffer[2] = 0x04; + memmove(&Buffer[4], &Buffer[3], IncomingByteCount - 2); + Buffer[3] = 0x00; + } uint16_t UnwrappedBitCount = (IncomingByteCount - 2) * BITS_PER_BYTE; uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; @@ -255,6 +265,8 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { // even when the reader has not been put in scan mode -- // and it really screws things up timing-wise! AnticolNoResp = true; + const char *debugPrintStr = PSTR("DESFire: Anticol NO-RESP set"); + LogDebuggingMsg(debugPrintStr); } return ISO14443AStoreLastDataFrameAndReturn(Buffer, PiccProcessRespBits); } diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.h b/Firmware/Chameleon-Mini/Application/MifareDESFire.h index add26775..c865e2ab 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.h +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.h @@ -89,5 +89,6 @@ extern DesfireStateType DesfireState; extern DesfireStateType DesfirePreviousState; extern bool DesfireFromHalt; extern BYTE DesfireCmdCLA; +extern Iso7816WrappedCommandType_t Iso7816CmdType; #endif /* MIFAREDESFIRE_H_ */