diff --git a/Doc/DESFireSupportReadme.md b/Doc/DESFireSupportReadme.md index 11f94670..7433bb75 100644 --- a/Doc/DESFireSupportReadme.md +++ b/Doc/DESFireSupportReadme.md @@ -2,13 +2,7 @@ ## Quick configuration of cloned DESFire tags -### Chameleon Mini terminal addons to support ``CONFIG=MF_DESFIRE`` modes - -Note that these commands are only compiled into the firmware when the compiler -option ``-DALLOW_DESFIRE_TERMINAL_COMMANDS`` and ``-DCONFIG_MF_DESFIRE_SUPPORT`` are -specified. If you do not at miniumum have a configuration, ``CONFIG=MF_DESFIRE``, then -these commands will not work. Note that LIVE logging should be disabled before attempting to -run these commands. +### Chameleon Mini terminal addons to support DESFire tag configurations #### Selecting a DESFire configuration @@ -47,6 +41,7 @@ DF_SETHDR=ATS 0675f7b102 ``` To reset the ATQA value returned in the anticollision loop handshaking: ``` +DF_SETHDR=ATQA 0344 DF_SETHDR=ATQA 2838 ``` diff --git a/Firmware/Chameleon-Mini/AntennaLevel.c b/Firmware/Chameleon-Mini/AntennaLevel.c index 834d18de..499ad922 100644 --- a/Firmware/Chameleon-Mini/AntennaLevel.c +++ b/Firmware/Chameleon-Mini/AntennaLevel.c @@ -11,7 +11,7 @@ void AntennaLevelTick(void) { if (rssi < FIELD_MIN_RSSI) { LEDHook(LED_FIELD_DETECTED, LED_OFF); if (ActiveConfiguration.UidSize != 0) // this implies that we are emulating right now - ApplicationReset(); // reset the application just like a real card gets reset when there is no field + ApplicationReset(); // reset the application just like a real card gets reset when there is no field } else { LEDHook(LED_FIELD_DETECTED, LED_ON); AntennaLevelLogReaderDetectCount = (++AntennaLevelLogReaderDetectCount) % ANTENNA_LEVEL_LOG_RDRDETECT_INTERVAL; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.c index d66cc85a..afa6c51c 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.c @@ -703,7 +703,7 @@ uint16_t DeleteApp(const DESFireAidType Aid) { AppDir.FirstFreeSlot = MIN(Slot, AppDir.FirstFreeSlot); SynchronizeAppDir(); if (!IsPiccAppSelected()) { - InvalidateAuthState(0x00); + InvalidateAuthState(0); } SelectAppBySlot(DESFIRE_PICC_APP_SLOT); return STATUS_OPERATION_OK; @@ -720,11 +720,11 @@ TransferStatus GetApplicationIdsTransfer(uint8_t *Buffer) { Status.BytesProcessed = 0; for (EntryIndex = TransferState.GetApplicationIds.NextIndex; EntryIndex < DESFIRE_MAX_SLOTS; ++EntryIndex) { - if ((AppDir.AppIds[EntryIndex][0] | AppDir.AppIds[EntryIndex][1] | - AppDir.AppIds[EntryIndex][2]) == 0) + if ((AppDir.AppIds[EntryIndex][0] | AppDir.AppIds[EntryIndex][1] | AppDir.AppIds[EntryIndex][2]) == 0) { continue; + } /* If it won't fit -- remember and return */ - if (Status.BytesProcessed >= TERMINAL_BUFFER_SIZE) { // TODO ??? 19 / Magic Number ??? + if (Status.BytesProcessed >= TERMINAL_BUFFER_SIZE) { TransferState.GetApplicationIds.NextIndex = EntryIndex; Status.IsComplete = false; return Status; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c index 268e86c7..92b526d9 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c @@ -216,7 +216,7 @@ uint8_t CryptoAESTransferEncryptSend(uint8_t *Buffer, uint8_t Count, const uint8 } uint8_t CryptoAESTransferEncryptReceive(uint8_t *Buffer, uint8_t Count, const uint8_t *Key) { - LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA_ENC, Buffer, Count); + DesfireLogEntry(LOG_INFO_DESFIRE_INCOMING_DATA_ENC, Buffer, Count); return STATUS_OPERATION_OK; } #endif @@ -322,7 +322,7 @@ uint8_t TransferEncryptTDEASend(uint8_t *Buffer, uint8_t Count) { } uint8_t TransferEncryptTDEAReceive(uint8_t *Buffer, uint8_t Count) { - LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA_ENC, Buffer, Count); + DesfireLogEntry(LOG_INFO_DESFIRE_INCOMING_DATA_ENC, Buffer, Count); return 0; } diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireFile.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireFile.c index 8e252495..b0478fa7 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireFile.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireFile.c @@ -370,31 +370,4 @@ uint8_t ValidateAuthentication(uint16_t AccessRights, uint16_t CheckMask) { return VALIDATED_ACCESS_DENIED; } -const char *GetFileAccessPermissionsDesc(uint16_t fileAccessRights) { - __InternalStringBuffer[0] = '\0'; - BYTE removeTrailingText = 0x00; - if (GetReadPermissions(fileAccessRights) != DESFIRE_ACCESS_DENY) { - strcat_P(__InternalStringBuffer, PSTR("R/")); - removeTrailingText = 0x01; - } - if (GetWritePermissions(fileAccessRights) != DESFIRE_ACCESS_DENY) { - strcat_P(__InternalStringBuffer, PSTR("W/")); - removeTrailingText = 0x01; - - } - if (GetReadWritePermissions(fileAccessRights) != DESFIRE_ACCESS_DENY) { - strcat_P(__InternalStringBuffer, PSTR("RW/")); - removeTrailingText = 0x01; - } - if (GetChangePermissions(fileAccessRights) != DESFIRE_ACCESS_DENY) { - strcat_P(__InternalStringBuffer, PSTR("CHG")); - removeTrailingText = 0x00; - } - if (removeTrailingText) { - BYTE bufSize = StringLength(__InternalStringBuffer, STRING_BUFFER_SIZE); - __InternalStringBuffer[bufSize - 1] = '\0'; - } - return __InternalStringBuffer; -} - #endif /* CONFIG_MF_DESFIRE_SUPPORT */ diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireFile.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireFile.h index 2e91b65c..974b0723 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireFile.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireFile.h @@ -52,7 +52,7 @@ This notice must be retained at the top of all source files where indicated. /* Data about an application's file is currently kept in this structure. * The location of these structures is defined by the file index. */ -typedef struct DESFIRE_FIRMWARE_PACKING { +typedef struct DESFIRE_FIRMWARE_PACKING DESFIRE_FIRMWARE_ALIGNAT { uint8_t FileType; uint8_t FileNumber; uint16_t FileSize; @@ -86,7 +86,7 @@ typedef struct DESFIRE_FIRMWARE_PACKING { uint16_t GetFileSizeFromFileType(DESFireFileTypeSettings *File); -typedef struct DESFIRE_FIRMWARE_PACKING { +typedef struct DESFIRE_FIRMWARE_PACKING DESFIRE_FIRMWARE_ALIGNAT { BYTE Num; DESFireFileTypeSettings File; } SelectedFileCacheType; @@ -149,8 +149,6 @@ uint16_t WriteDataFileIterator(uint8_t *Buffer, uint16_t ByteCount); #define GetChangePermissions(AccessRights) \ (BYTE) (((0xf000 & AccessRights) >> 12) & 0x000f) -const char *GetFileAccessPermissionsDesc(uint16_t fileAccessRights); - /* * There are also command/instruction-wise * citations given from file's access permissions. This data is taken diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c index ac6002df..3be3a17b 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c @@ -39,10 +39,10 @@ This notice must be retained at the top of all source files where indicated. */ Iso144434StateType Iso144434State = ISO14443_4_STATE_EXPECT_RATS; -uint8_t Iso144434BlockNumber = 0x00; -uint8_t Iso144434CardID = 0x00; -uint8_t Iso144434LastBlockLength = 0x00; -uint8_t StateRetryCount = 0x00; +uint8_t Iso144434BlockNumber = 0; +uint8_t Iso144434CardID = 1; +uint8_t Iso144434LastBlockLength = 0; +uint8_t StateRetryCount = 0; uint8_t LastReaderSentCmd = 0x00; uint8_t ISO14443ALastDataFrame[MAX_DATA_FRAME_XFER_SIZE] = { 0x00 }; @@ -53,8 +53,7 @@ uint16_t ISO14443ALastIncomingDataFrameBits = 0; bool CheckStateRetryCountWithLogging(bool resetByDefault, bool performLogging) { if (resetByDefault || ++StateRetryCount > MAX_STATE_RETRY_COUNT) { ISO144434SwitchStateWithLogging(Iso144433AIdleState, performLogging); - StateRetryCount = 0x00; - DEBUG_PRINT_P(PSTR("RETRY-RESET")); + StateRetryCount = 0; return true; } return false; @@ -65,12 +64,10 @@ bool CheckStateRetryCount(bool resetByDefault) { void ISO144434SwitchStateWithLogging(Iso144434StateType NewState, bool performLogging) { Iso144434State = NewState; - StateRetryCount = 0x00; -#ifdef DESFIRE_DEBUGGING && DESFIRE_DEBUGGING != 0 - if (performLogging) { - RUN_ON_DESFIRE_DEBUG(DesfireLogISOStateChange(Iso144434State, LOG_ISO14443_4_STATE)); + StateRetryCount = 0; + if (DesfireDebuggingOn && performLogging) { + DesfireLogISOStateChange(Iso144434State, LOG_ISO14443_4_STATE); } -#endif } void ISO144434SwitchState(Iso144434StateType NewState) { @@ -82,15 +79,16 @@ void ISO144434Reset(void) { Iso144434State = ISO14443_4_STATE_EXPECT_RATS; Iso144434BlockNumber = 1; ISO14443ALastDataFrameBits = 0; + ISO14443ALastDataFrame[0] = 0x00; LastReaderSentCmd = 0x00; } -static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t BitCount) { +uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t BitCount) { uint8_t PCB = Buffer[0]; uint8_t MyBlockNumber = Iso144434BlockNumber; - uint8_t PrologueLength; - uint8_t HaveCID, HaveNAD; + uint8_t PrologueLength = 0; + uint8_t HaveCID = 0, HaveNAD = 0; /* Verify the block's length: at the very least PCB + CRCA */ if (ByteCount < (1 + ISO14443A_CRCA_SIZE)) { @@ -102,14 +100,14 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 /* Verify the checksum; fail if doesn't match */ if (!ISO14443ACheckCRCA(Buffer, ByteCount)) { - LogEntry(LOG_ERR_APP_CHECKSUM_FAIL, Buffer, ByteCount); + DesfireLogEntry(LOG_ERR_APP_CHECKSUM_FAIL, (uint8_t *) NULL, 0); /* ISO/IEC 14443-4, clause 7.5.5. The PICC does not attempt any error recovery. */ - DEBUG_PRINT_P(PSTR("WARN: 14443-4: CRC fail; %04X vs %04X"), *(uint16_t *)&Buffer[ByteCount], - ISO14443AAppendCRCA(Buffer, ByteCount)); + DEBUG_PRINT_P(PSTR("WARN: 14443-4: CRC fail")); return ISO14443A_APP_NO_RESPONSE; } switch (Iso144434State) { + case ISO14443_4_STATE_EXPECT_RATS: { /* See: ISO/IEC 14443-4, clause 5.6.1.2 */ if (Buffer[0] != ISO14443A_CMD_RATS) { @@ -121,14 +119,14 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 * NOTE: ATS bytes are tailored to Chameleon implementation and differ from DESFire spec. * NOTE: Some PCD implementations do a memcmp() over ATS bytes, which is completely wrong. */ + //DEBUG_PRINT_P(PSTR("ISO14443-4: SEND RATS")); Iso144434CardID = Buffer[1] & 0x0F; Buffer[0] = 0x06; memcpy(&Buffer[1], &Picc.ATSBytes[1], 4); Buffer[5] = 0x80; /* T1: dummy value for historical bytes */ - ByteCount = 6; // NOT including CRC + ByteCount = 6; /* NOT including CRC */ ISO144434SwitchState(ISO14443_4_STATE_ACTIVE); - DEBUG_PRINT_P(PSTR("ISO14443-4: SEND RATS")); - return ASBITS(ByteCount); // PM3 expects no CRCA bytes + return ASBITS(ByteCount); /* PM3 expects no CRCA bytes */ } case ISO14443_4_STATE_ACTIVE: { /* See: ISO/IEC 14443-4; 7.1 Block format */ @@ -161,18 +159,19 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 } switch (PCB & ISO14443_PCB_BLOCK_TYPE_MASK) { + case ISO14443_PCB_I_BLOCK: { HaveNAD = PCB & ISO14443_PCB_HAS_NAD_MASK; if (HaveNAD) { PrologueLength++; /* Not currently supported -- the frame is ignored */ - DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_I_BLOCK -- %d"), __LINE__); + DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_I_BLOCK")); } /* 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 */ - DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_I_BLOCK -- %d"), __LINE__); + DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_I_BLOCK")); return ISO14443A_APP_NO_RESPONSE; } @@ -199,7 +198,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 case ISO14443_PCB_R_BLOCK: { /* 7.5.4.3, rule 11 */ if ((PCB & ISO14443_PCB_BLOCK_NUMBER_MASK) == MyBlockNumber) { - DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_R_BLOCK -- %d"), __LINE__); + DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_R_BLOCK")); return ISO14443A_APP_NO_RESPONSE; } if (PCB & ISO14443_PCB_R_BLOCK_ACKNAK_MASK) { @@ -211,7 +210,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 } else { /* This is an ACK: */ /* NOTE: Chaining is not supported yet. */ - DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_R_BLOCK -- %d"), __LINE__); + DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_R_BLOCK")); // Resend the data from the last frame: if (ISO14443ALastDataFrameBits > 0) { memcpy(&Buffer[0], &ISO14443ALastDataFrame[0], ASBYTES(ISO14443ALastDataFrameBits)); @@ -245,7 +244,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 } - /* Fall through (default handling when there is no response to register/return to the sender): */ + /* Fall through: */ return ISO14443A_APP_NO_RESPONSE; } @@ -272,14 +271,15 @@ Iso144433AStateType Iso144433AIdleState = ISO14443_3A_STATE_IDLE; void ISO144433ASwitchState(Iso144433AStateType NewState) { Iso144433AState = NewState; - StateRetryCount = 0x00; - RUN_ON_DESFIRE_DEBUG(DesfireLogISOStateChange(Iso144433AState, LOG_ISO14443_3A_STATE)); + DesfireLogISOStateChange(Iso144433AState, LOG_ISO14443_3A_STATE); } void ISO144433AReset(void) { /* No logging performed -- spams the log and slows things way down! */ Iso144433AState = ISO14443_3A_STATE_IDLE; Iso144433AIdleState = ISO14443_3A_STATE_IDLE; + StateRetryCount = 0; + ISO14443ALastDataFrame[0] = 0x00; ISO14443ALastDataFrameBits = 0; } @@ -287,7 +287,6 @@ void ISO144433AHalt(void) { ISO144433ASwitchState(ISO14443_3A_STATE_HALT); Iso144433AIdleState = ISO14443_3A_STATE_HALT; ISO144433AReset(); - StateRetryCount = 0x00; } bool ISO144433AIsHalt(const uint8_t *Buffer, uint16_t BitCount) { @@ -300,39 +299,33 @@ bool ISO144433AIsHalt(const uint8_t *Buffer, uint16_t BitCount) { uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { if (BitCount == 0) { - ISO144434Reset(); - ISO144433AHalt(); + //ISO144434Reset(); + //ISO144433AHalt(); return ISO14443A_APP_NO_RESPONSE; } uint8_t Cmd = Buffer[0]; /* Wakeup and Request may occure in all states */ - bool checkStateRetryStatus = CheckStateRetryCount(false); - bool incrementRetryCount = true; if (Cmd == ISO14443A_CMD_REQA) { - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_APP_CMD_REQA, NULL, 0)); + DesfireLogEntry(LOG_INFO_APP_CMD_REQA, NULL, 0); ISO144433ASwitchState(ISO14443_3A_STATE_IDLE); - incrementRetryCount = false; + StateRetryCount = 0; } else if (ISO14443ACmdIsWUPA(Cmd)) { - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_APP_CMD_WUPA, NULL, 0)); + DesfireLogEntry(LOG_INFO_APP_CMD_WUPA, NULL, 0); ISO144433ASwitchState(ISO14443_3A_STATE_IDLE); - incrementRetryCount = false; + StateRetryCount = 0; } else if (ISO144433AIsHalt(Buffer, BitCount)) { - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0)); + DesfireLogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0); DEBUG_PRINT_P(PSTR("ISO14443-3: HALTING")); ISO144433AHalt(); return ISO14443A_APP_NO_RESPONSE; } - LastReaderSentCmd = Cmd; - if (incrementRetryCount) { - StateRetryCount += 1; - } - /* This implements ISO 14443-3A state machine */ /* See: ISO/IEC 14443-3, clause 6.2 */ switch (Iso144433AState) { + case ISO14443_3A_STATE_HALT: if (!ISO14443ACmdIsWUPA(Cmd)) { DEBUG_PRINT_P(PSTR("ISO14443-4: HALT -- NOT WUPA")); @@ -340,68 +333,81 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { } else { ISO144433ASwitchState(ISO14443_3A_STATE_IDLE); } - /* Fall-through */ case ISO14443_3A_STATE_IDLE: Iso144433AIdleState = Iso144433AState; - ISO144433ASwitchState(ISO14443_3A_STATE_READY1); + ISO144433ASwitchState(ISO14443_3A_STATE_READY_CL1); 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: + case ISO14443_3A_STATE_READY_CL1: + case ISO14443_3A_STATE_READY_CL1_NVB_END: if (Cmd == ISO14443A_CMD_SELECT_CL1) { - /* Load UID CL1 and perform anticollision. */ + /* Load UID CL1 and perform anticollisio: */ ConfigurationUidType Uid; ApplicationGetUid(Uid); if (ActiveConfiguration.UidSize >= ISO14443A_UID_SIZE_DOUBLE) { - Uid[3] = Uid[2]; - Uid[2] = Uid[1]; - Uid[1] = Uid[0]; Uid[0] = ISO14443A_UID0_CT; } - if (ISO14443ASelectDesfire(Buffer, &BitCount, Uid, SAK_CL1_VALUE)) { - /* CL1 stage has ended successfully */ - DEBUG_PRINT_P(PSTR("ISO14443-4: Select OK")); - ISO144433ASwitchState(ISO14443_3A_STATE_READY2); + uint8_t cl1SAKValue = IS_ISO14443A_4_COMPLIANT(Buffer[1]) ? ISO14443A_SAK_INCOMPLETE : ISO14443A_SAK_INCOMPLETE_NOT_COMPLIANT; + Buffer[1] = MAKE_ISO14443A_4_COMPLIANT(Buffer[1]); + if (Buffer[1] == ISO14443A_NVB_AC_START && !ISO14443ASelectDesfire(Buffer, &BitCount, Uid, cl1SAKValue) && BitCount > 0) { + //DEBUG_PRINT_P(PSTR("ISO14443-4: Select CL1 NVB START -- OK")); + ISO144433ASwitchState(ISO14443_3A_STATE_READY_CL1_NVB_END); + return BitCount; + } else if (Buffer[1] == ISO14443A_NVB_AC_END && ISO14443ASelectDesfire(Buffer, &BitCount, Uid, cl1SAKValue)) { + //DEBUG_PRINT_P(PSTR("ISO14443-4: Select CL1 NVB END -- OK")); + ISO144433ASwitchState(ISO14443_3A_STATE_READY_CL2); + return BitCount; + } else { - DEBUG_PRINT_P(PSTR("ISO14443-4: Select NAK")); + DEBUG_PRINT_P(PSTR("ISO14443-4: Select CL1 NOT OK")); } - return BitCount; + } else { + DEBUG_PRINT_P(PSTR("ISO14443-4: RDY1 -- NOT SLCT CMD")); } - DEBUG_PRINT_P(PSTR("ISO14443-4: RDY1 -- NOT SLCT CMD")); - break; + CheckStateRetryCount(false); + return ISO14443A_APP_NO_RESPONSE; - case ISO14443_3A_STATE_READY2: + case ISO14443_3A_STATE_READY_CL2: + case ISO14443_3A_STATE_READY_CL2_NVB_END: if (Cmd == ISO14443A_CMD_SELECT_CL2 && ActiveConfiguration.UidSize >= ISO14443A_UID_SIZE_DOUBLE) { - /* Load UID CL2 and perform anticollision */ + /* Load UID CL2 and perform anticollision: */ ConfigurationUidType Uid; ApplicationGetUid(Uid); - if (ISO14443ASelectDesfire(Buffer, &BitCount, &Uid[3], SAK_CL2_VALUE)) { - /* CL2 stage has ended successfully. This means - * our complete UID has been sent to the reader. */ + uint8_t cl2SAKValue = IS_ISO14443A_4_COMPLIANT(Buffer[1]) ? ISO14443A_SAK_COMPLETE_COMPLIANT : ISO14443A_SAK_COMPLETE_NOT_COMPLIANT; + Buffer[1] = MAKE_ISO14443A_4_COMPLIANT(Buffer[1]); + if (Buffer[1] == ISO14443A_NVB_AC_START && !ISO14443ASelectDesfire(Buffer, &BitCount, &Uid[4], cl2SAKValue) && BitCount > 0) { + //DEBUG_PRINT_P(PSTR("ISO14443-4: Select CL2 NVB START -- OK")); + ISO144433ASwitchState(ISO14443_3A_STATE_READY_CL2_NVB_END); + return BitCount; + } else if (Buffer[1] == ISO14443A_NVB_AC_END && ISO14443ASelectDesfire(Buffer, &BitCount, &Uid[4], cl2SAKValue)) { + //DEBUG_PRINT_P(PSTR("ISO14443-4: Select CL2 NVB END -- OK")); ISO144433ASwitchState(ISO14443_3A_STATE_ACTIVE); + return BitCount; + } else { - DEBUG_PRINT_P(PSTR("ISO14443-4: Incorrect select value (R2)")); + DEBUG_PRINT_P(PSTR("ISO14443-4: Select CL2 NOT OK")); } - return BitCount; + } else { + DEBUG_PRINT_P(PSTR("ISO14443-4: RDY2 -- NOT SLCT CMD")); } - DEBUG_PRINT_P(PSTR("ISO14443-4: RDY2 -- NOT SLCT CMD")); - break; + CheckStateRetryCount(false); + return ISO14443A_APP_NO_RESPONSE; case ISO14443_3A_STATE_ACTIVE: StateRetryCount = MAX_STATE_RETRY_COUNT; if (ISO144433AIsHalt(Buffer, BitCount)) { /* Recognise the HLTA command: */ - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0)); - ISO144434SwitchState(ISO14443_3A_STATE_HALT); - DEBUG_PRINT_P(PSTR("ISO14443-3: Got HALT")); + DesfireLogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0); + ISO144433AHalt(); return ISO14443A_APP_NO_RESPONSE; } else if (Cmd == ISO14443A_CMD_RATS) { - ISO144433ASwitchState(ISO14443_4_STATE_EXPECT_RATS); - DEBUG_PRINT_P(PSTR("ISO14443-3/4: Expecting RATS")); + //DEBUG_PRINT_P(PSTR("ISO14443-3/4: Expecting RATS")); + ISO144434SwitchState(ISO14443_4_STATE_EXPECT_RATS); } else if (Cmd == ISO14443A_CMD_SELECT_CL3) { + /* DESFire UID size is of insufficient size to support this: */ Buffer[0] = ISO14443A_SAK_COMPLETE_NOT_COMPLIANT; ISO14443AAppendCRCA(&Buffer[0], 1); return ISO14443A_SAK_FRAME_SIZE; @@ -409,12 +415,12 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { /* 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)); + DesfireLogEntry(LOG_INFO_APP_CMD_DESELECT, NULL, 0); } /* Forward to ISO/IEC 14443-4 processing code */ + //DEBUG_PRINT_P(PSTR("ISO14443-4: ACTIVE RET")); uint16_t ByteCount = ASBYTES(BitCount); uint16_t ReturnBits = ISO144434ProcessBlock(Buffer, ByteCount, BitCount); - DEBUG_PRINT_P(PSTR("ISO14443-4: ACTIVE RET")); return ReturnBits; default: @@ -423,8 +429,7 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { } /* Fallthrough: Unknown command. Reset back to idle/halt state. */ - bool defaultReset = false; - if (!CheckStateRetryCount(defaultReset)) { + if (!CheckStateRetryCount(false)) { DEBUG_PRINT_P(PSTR("ISO14443-3: Fall through -- RESET TO IDLE 0x%02x"), Cmd); return ISO14443A_APP_NO_RESPONSE; } else { diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h index a5cacd61..5bd7909e 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h @@ -75,8 +75,8 @@ This notice must be retained at the top of all source files where indicated. #define ISO14443_PCB_S_WTX (ISO14443_PCB_S_BLOCK_STATIC | 0x30) #define ISO14443A_CMD_PPS 0xD0 -#define IS_ISO14443A_4_COMPLIANT(buf) (buf[0] & 0x20) -#define MAKE_ISO14443A_4_COMPLIANT(buf) (buf[0] |= 0x20) +#define IS_ISO14443A_4_COMPLIANT(bufByte) (bufByte & 0x20) +#define MAKE_ISO14443A_4_COMPLIANT(bufByte) (bufByte |= 0x20) /* * ISO/IEC 14443-4 implementation @@ -100,22 +100,14 @@ extern uint8_t LastReaderSentCmd; /* Configure saving last data frame state so can resend on ACK from the PCD */ -#define MAX_DATA_FRAME_XFER_SIZE (64) +#define MAX_DATA_FRAME_XFER_SIZE (72) extern uint8_t ISO14443ALastDataFrame[MAX_DATA_FRAME_XFER_SIZE]; extern uint16_t ISO14443ALastDataFrameBits; extern uint8_t ISO14443ALastIncomingDataFrame[MAX_DATA_FRAME_XFER_SIZE]; extern uint16_t ISO14443ALastIncomingDataFrameBits; +uint16_t ISO14443AStoreLastDataFrameAndReturn(const uint8_t *Buffer, uint16_t BufferBitCount); -INLINE ISO14443AStoreLastDataFrameAndReturn(const uint8_t *Buffer, uint16_t BufferBitCount) { - uint16_t ISO14443ALastDataFrameBytes = MIN((BufferBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE, MAX_DATA_FRAME_XFER_SIZE); - if (ISO14443ALastDataFrameBytes > 0) { - memcpy(ISO14443ALastDataFrame, &Buffer[0], ISO14443ALastDataFrameBytes); - } - ISO14443ALastDataFrameBits = BufferBitCount; - return BufferBitCount; -} - -#define MAX_STATE_RETRY_COUNT (0x04) +#define MAX_STATE_RETRY_COUNT (0x0B) extern uint8_t StateRetryCount; bool CheckStateRetryCount(bool resetByDefault); bool CheckStateRetryCountWithLogging(bool resetByDefault, bool performLogging); @@ -125,12 +117,12 @@ void ISO144434SwitchState(Iso144434StateType NewState); void ISO144434SwitchStateWithLogging(Iso144434StateType NewState, bool performLogging); void ISO144434Reset(void); -static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t BitCount); +uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t BitCount); /* * ISO/IEC 14443-3A implementation */ -#define ISO14443A_CRCA_INIT ((uint16_t) 0x6363) +#define ISO14443A_CRCA_INIT ((uint16_t) 0x6363) uint16_t ISO14443AUpdateCRCA(const uint8_t *Buffer, uint16_t ByteCount, uint16_t InitCRCA); #define GetAndSetBufferCRCA(Buffer, ByteCount) ({ \ @@ -141,7 +133,7 @@ uint16_t ISO14443AUpdateCRCA(const uint8_t *Buffer, uint16_t ByteCount, uint16_t }) #define GetAndSetNoResponseCRCA(Buffer) ({ \ uint16_t fullReturnBits = 0; \ - ISO14443AAppendCRCA(Buffer, 0); \ + ISO14443AUpdateCRCA(Buffer, 0, ISO14443A_CRCA_INIT); \ fullReturnBits = ISO14443A_CRC_FRAME_SIZE; \ fullReturnBits; \ }) @@ -150,8 +142,10 @@ typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { /* 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, + ISO14443_3A_STATE_READY_CL1, + ISO14443_3A_STATE_READY_CL1_NVB_END, + ISO14443_3A_STATE_READY_CL2, + ISO14443_3A_STATE_READY_CL2_NVB_END, /* Entered when the card has been selected: */ ISO14443_3A_STATE_ACTIVE, /* Something went wrong or we've received a halt command: */ diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h index eb7474df..9fe78979 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h @@ -88,7 +88,6 @@ typedef enum { ISO7816_WRAPPED_CMD_TYPE_STANDARD = 1, ISO7816_WRAPPED_CMD_TYPE_PM3RAW = 2, ISO7816_WRAPPED_CMD_TYPE_PM3_ADDITIONAL_FRAME = 3, - /* TODO -- Others ??? */ } Iso7816WrappedCommandType_t; extern Iso7816WrappedCommandType_t Iso7816CmdType; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index 09774cb7..68c261c8 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -100,9 +100,6 @@ static uint16_t EV0CmdAbortTransaction(uint8_t *Buffer, uint16_t ByteCount); static uint16_t ISO7816CmdSelect(uint8_t *Buffer, uint16_t ByteCount); static uint16_t ISO7816CmdSelectEF(uint8_t *Buffer, uint16_t ByteCount); static uint16_t ISO7816CmdSelectDF(uint8_t *Buffer, uint16_t ByteCount); -static uint16_t ISO7816CmdGetChallenge(uint8_t *Buffer, uint16_t ByteCount); -static uint16_t ISO7816CmdExternalAuthenticate(uint8_t *Buffer, uint16_t ByteCount); -static uint16_t ISO7816CmdInternalAuthenticate(uint8_t *Buffer, uint16_t ByteCount); static uint16_t ISO7816CmdReadBinary(uint8_t *Buffer, uint16_t ByteCount); static uint16_t ISO7816CmdUpdateBinary(uint8_t *Buffer, uint16_t ByteCount); static uint16_t ISO7816CmdReadRecords(uint8_t *Buffer, uint16_t ByteCount); @@ -442,7 +439,7 @@ uint16_t DesfireCmdFreeMemory(uint8_t *Buffer, uint16_t ByteCount) { */ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { - BYTE KeyId, Status; + BYTE KeyId; BYTE keySize; BYTE *Key; @@ -480,10 +477,10 @@ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { } else { ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); } - LogEntry(LOG_APP_AUTH_KEY, (const void *) Key, keySize); + DesfireLogEntry(LOG_APP_AUTH_KEY, (const void *) Key, keySize); /* Generate the nonce B (RndB / Challenge response) */ - if (LocalTestingMode == 0) { + if (DesfireDebuggingOn) { RandomGetBuffer(DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); } else { /* Fixed nonce for testing */ @@ -504,7 +501,7 @@ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { DesfireCommandState.RndB[14] = 0x22; DesfireCommandState.RndB[15] = 0x33; } - LogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); + DesfireLogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); /* Encrypt RndB with the selected key and transfer it back to the PCD */ Encrypt2K3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, DesfireCommandState.RndB, @@ -635,15 +632,13 @@ uint16_t EV0CmdChangeKey(uint8_t *Buffer, uint16_t ByteCount) { /* Figure out the key size, and the crypto type from it: */ uint8_t keySize = ByteCount - 2; - uint8_t cryptoCommsTypeFromKey, cryptoType; + uint8_t cryptoType; if ((keySize != CRYPTO_3KTDEA_KEY_SIZE) && (keySize != CRYPTO_AES_KEY_SIZE)) { Buffer[0] = STATUS_NO_SUCH_KEY; return DESFIRE_STATUS_RESPONSE_SIZE; } else if (keySize == CRYPTO_3KTDEA_KEY_SIZE) { - cryptoCommsTypeFromKey = DESFIRE_COMMS_CIPHERTEXT_DES; cryptoType = CRYPTO_TYPE_3K3DES; } else { - cryptoCommsTypeFromKey = DESFIRE_COMMS_CIPHERTEXT_AES128; cryptoType = CRYPTO_TYPE_AES128; } uint8_t nextKeyVersion = ReadKeyVersion(SelectedApp.Slot, KeyId) + 1; @@ -844,7 +839,6 @@ uint16_t EV0CmdDeleteApplication(uint8_t *Buffer, uint16_t ByteCount) { return DESFIRE_STATUS_RESPONSE_SIZE; } PiccKeySettings = GetPiccKeySettings(); - const char *logMsg = PSTR("PICC key settings -- %02x"); /* Check the PICC key settings whether it is OK to delete using app master key */ if ((PiccKeySettings & DESFIRE_FREE_CREATE_DELETE) == 0x00) { Status = STATUS_AUTHENTICATION_ERROR; @@ -860,8 +854,9 @@ uint16_t EV0CmdDeleteApplication(uint8_t *Buffer, uint16_t ByteCount) { uint16_t EV0CmdSelectApplication(uint8_t *Buffer, uint16_t ByteCount) { InvalidateAuthState(0x00); - // handle a special case with EV1: - // https://stackoverflow.com/questions/38232695/m4m-mifare-desfire-ev1-which-mifare-aid-needs-to-be-added-to-nfc-routing-table + /* Handle a special case with EV1: + * See https://stackoverflow.com/questions/38232695/m4m-mifare-desfire-ev1-which-mifare-aid-needs-to-be-added-to-nfc-routing-table + */ if (ByteCount == 8) { const uint8_t DesfireEV1SelectPICCAid[] = { 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x00 }; if (!memcmp(&Buffer[1], DesfireEV1SelectPICCAid, sizeof(DesfireEV1SelectPICCAid))) { @@ -1148,7 +1143,7 @@ uint16_t EV0CmdGetFileSettings(uint8_t *Buffer, uint16_t ByteCount) { appendedFileDataSize = 1 + 1 + 2 + 3 + 3 + 3; } else { Buffer[0] = STATUS_PICC_INTEGRITY_ERROR; - return ; + return DESFIRE_STATUS_RESPONSE_SIZE; } Buffer[0] = STATUS_OPERATION_OK; return DESFIRE_STATUS_RESPONSE_SIZE + appendedFileDataSize; @@ -1299,9 +1294,7 @@ uint16_t EV0CmdWriteData(uint8_t *Buffer, uint16_t ByteCount) { uint16_t EV0CmdGetValue(uint8_t *Buffer, uint16_t ByteCount) { uint8_t Status; uint8_t FileNum; - uint8_t CommSettings; uint16_t AccessRights; - TransferStatus XferStatus; /* Validate command length */ if (ByteCount != 1 + 1) { Status = STATUS_LENGTH_ERROR; @@ -1314,14 +1307,12 @@ uint16_t EV0CmdGetValue(uint8_t *Buffer, uint16_t ByteCount) { return ExitWithStatus(Buffer, Status, DESFIRE_STATUS_RESPONSE_SIZE); } AccessRights = ReadFileAccessRights(SelectedApp.Slot, fileIndex); - CommSettings = ReadFileCommSettings(SelectedApp.Slot, fileIndex); /* Verify authentication: read or read&write required */ switch (ValidateAuthentication(AccessRights, VALIDATE_ACCESS_READWRITE | VALIDATE_ACCESS_READ)) { case VALIDATED_ACCESS_DENIED: Status = STATUS_AUTHENTICATION_ERROR; return ExitWithStatus(Buffer, Status, DESFIRE_STATUS_RESPONSE_SIZE); case VALIDATED_ACCESS_GRANTED_PLAINTEXT: - CommSettings = DESFIRE_COMMS_PLAINTEXT; case VALIDATED_ACCESS_GRANTED: break; } @@ -1358,14 +1349,13 @@ uint16_t EV0CmdCredit(uint8_t *Buffer, uint16_t ByteCount) { return ExitWithStatus(Buffer, Status, DESFIRE_STATUS_RESPONSE_SIZE); } uint16_t AccessRights = ReadFileAccessRights(SelectedApp.Slot, fileIndex); - uint8_t CommSettings = ReadFileCommSettings(SelectedApp.Slot, fileIndex); + //uint8_t CommSettings = ReadFileCommSettings(SelectedApp.Slot, fileIndex); /* Verify authentication: read or read&write required */ switch (ValidateAuthentication(AccessRights, VALIDATE_ACCESS_READWRITE)) { case VALIDATED_ACCESS_DENIED: Status = STATUS_AUTHENTICATION_ERROR; return ExitWithStatus(Buffer, Status, DESFIRE_STATUS_RESPONSE_SIZE); case VALIDATED_ACCESS_GRANTED_PLAINTEXT: - CommSettings = DESFIRE_COMMS_PLAINTEXT; case VALIDATED_ACCESS_GRANTED: break; } @@ -1410,7 +1400,6 @@ uint16_t EV0CmdDebit(uint8_t *Buffer, uint16_t ByteCount) { return ExitWithStatus(Buffer, Status, DESFIRE_STATUS_RESPONSE_SIZE); } uint16_t AccessRights = ReadFileAccessRights(SelectedApp.Slot, fileIndex); - uint8_t CommSettings = ReadFileCommSettings(SelectedApp.Slot, fileIndex); /* Verify authentication: read or read&write required */ switch (ValidateAuthentication(AccessRights, VALIDATE_ACCESS_READWRITE | VALIDATE_ACCESS_READ | VALIDATE_ACCESS_WRITE)) { @@ -1418,7 +1407,6 @@ uint16_t EV0CmdDebit(uint8_t *Buffer, uint16_t ByteCount) { Status = STATUS_AUTHENTICATION_ERROR; return ExitWithStatus(Buffer, Status, DESFIRE_STATUS_RESPONSE_SIZE); case VALIDATED_ACCESS_GRANTED_PLAINTEXT: - CommSettings = DESFIRE_COMMS_PLAINTEXT; case VALIDATED_ACCESS_GRANTED: break; } @@ -1463,8 +1451,8 @@ uint16_t EV0CmdLimitedCredit(uint8_t *Buffer, uint16_t ByteCount) { Status = STATUS_PARAMETER_ERROR; return ExitWithStatus(Buffer, Status, DESFIRE_STATUS_RESPONSE_SIZE); } - uint16_t AccessRights = ReadFileAccessRights(SelectedApp.Slot, fileIndex); - uint8_t CommSettings = ReadFileCommSettings(SelectedApp.Slot, fileIndex); + //uint16_t AccessRights = ReadFileAccessRights(SelectedApp.Slot, fileIndex); + //uint8_t CommSettings = ReadFileCommSettings(SelectedApp.Slot, fileIndex); /* Validate the file type */ uint8_t fileType = ReadFileType(SelectedApp.Slot, fileIndex); if (fileType != DESFIRE_FILE_VALUE_DATA) { @@ -1547,6 +1535,7 @@ uint16_t EV0CmdReadRecords(uint8_t *Buffer, uint16_t ByteCount) { uint16_t EV0CmdWriteRecord(uint8_t *Buffer, uint16_t ByteCount) { uint8_t Status; + uint16_t AccessRights; if (ByteCount < 1 + 1 + 3 + 3) { Status = STATUS_LENGTH_ERROR; return ExitWithStatus(Buffer, Status, DESFIRE_STATUS_RESPONSE_SIZE); @@ -1559,15 +1548,13 @@ uint16_t EV0CmdWriteRecord(uint8_t *Buffer, uint16_t ByteCount) { } __uint24 Offset = GET_LE24(&Buffer[2]); __uint24 Length = GET_LE24(&Buffer[5]); - uint16_t AccessRights = ReadFileAccessRights(SelectedApp.Slot, fileIndex); - uint8_t CommSettings = ReadFileCommSettings(SelectedApp.Slot, fileIndex); + AccessRights = ReadFileAccessRights(SelectedApp.Slot, fileIndex); /* Verify authentication: read or read&write required */ switch (ValidateAuthentication(AccessRights, VALIDATE_ACCESS_READWRITE | VALIDATE_ACCESS_WRITE)) { case VALIDATED_ACCESS_DENIED: Status = STATUS_AUTHENTICATION_ERROR; return ExitWithStatus(Buffer, Status, DESFIRE_STATUS_RESPONSE_SIZE); case VALIDATED_ACCESS_GRANTED_PLAINTEXT: - CommSettings = DESFIRE_COMMS_PLAINTEXT; case VALIDATED_ACCESS_GRANTED: break; } @@ -1766,10 +1753,10 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { memcpy(&Key[CRYPTO_DES_BLOCK_SIZE], &Key[0], CRYPTO_DES_BLOCK_SIZE); memcpy(&Key[2 * CRYPTO_DES_BLOCK_SIZE], &Key[0], CRYPTO_DES_BLOCK_SIZE); } - LogEntry(LOG_APP_AUTH_KEY, (const void *) Key, keySize); + DesfireLogEntry(LOG_APP_AUTH_KEY, (const void *) Key, keySize); /* Generate the nonce B (RndB / Challenge response) */ - if (LocalTestingMode == 0) { + if (DesfireDebuggingOn) { RandomGetBuffer(DesfireCommandState.RndB, CryptoChallengeResponseBytesSize); } else { /* Fixed nonce for testing */ @@ -1790,7 +1777,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { DesfireCommandState.RndB[14] = 0x22; DesfireCommandState.RndB[15] = 0x33; } - LogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CryptoChallengeResponseBytesSize); + DesfireLogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CryptoChallengeResponseBytesSize); /* Encrypt RndB with the selected key and transfer it back to the PCD */ if (cryptoKeyType == CRYPTO_TYPE_DES || cryptoKeyType == CRYPTO_TYPE_3K3DES || cryptoKeyType == CRYPTO_TYPE_ANY) { @@ -1830,7 +1817,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { DesfireState = DESFIRE_IDLE; /* Validate command length */ if (ByteCount != 2 * CryptoChallengeResponseBytesSize + 1) { - LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ByteCount); + DesfireLogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ByteCount); Buffer[0] = STATUS_LENGTH_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; } @@ -1864,8 +1851,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { /* Check that the returned RndB matches what we sent in the previous round */ if (memcmp(DesfireCommandState.RndB, challengeRndB, CryptoChallengeResponseBytesSize)) { - LogEntry(LOG_ERR_DESFIRE_GENERIC_ERROR, (const void *) challengeRndB, - CryptoChallengeResponseBytesSize); + DesfireLogEntry(LOG_ERR_DESFIRE_GENERIC_ERROR, (const void *) challengeRndB, CryptoChallengeResponseBytesSize); Buffer[0] = STATUS_AUTHENTICATION_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; } @@ -1900,9 +1886,10 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { uint16_t DesfireCmdAuthenticateAES1(uint8_t *Buffer, uint16_t ByteCount) { - BYTE KeyId, Status; + BYTE KeyId; BYTE keySize; BYTE *Key, *IVBuffer; + BYTE Status; /* Validate command length */ if (ByteCount != 2) { @@ -1952,12 +1939,12 @@ uint16_t DesfireCmdAuthenticateAES1(uint8_t *Buffer, uint16_t ByteCount) { /* Fetch the key */ ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); - LogEntry(LOG_APP_AUTH_KEY, (const void *) Key, keySize); + DesfireLogEntry(LOG_APP_AUTH_KEY, (const void *) Key, keySize); CryptoAESGetConfigDefaults(&AESCryptoContext); CryptoAESInitContext(&AESCryptoContext); /* Generate the nonce B (RndB / Challenge response) */ - if (LocalTestingMode == 0) { + if (DesfireDebuggingOn) { RandomGetBuffer(&(DesfireCommandState.RndB[0]), CRYPTO_CHALLENGE_RESPONSE_BYTES); } else { /* Fixed nonce for testing */ @@ -1978,7 +1965,7 @@ uint16_t DesfireCmdAuthenticateAES1(uint8_t *Buffer, uint16_t ByteCount) { DesfireCommandState.RndB[14] = 0x22; DesfireCommandState.RndB[15] = 0x33; } - LogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); + DesfireLogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); /* Encrypt RndB with the selected key and transfer it back to the PCD */ Status = CryptoAESEncryptBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, DesfireCommandState.RndB, @@ -2137,7 +2124,7 @@ uint16_t ISO7816CmdGetChallenge(uint8_t *Buffer, uint16_t ByteCount) { } const uint8_t challengeRespDefaultBytes = 8; RandomGetBuffer(&Buffer[2], challengeRespDefaultBytes); - // TODO: Should store this value somewhere for the next commands / auth routines ... + /* TODO: Should store this value somewhere for the next commands / auth routines ... */ Buffer[0] = ISO7816_CMD_NO_ERROR; Buffer[1] = ISO7816_CMD_NO_ERROR; return ISO7816_STATUS_RESPONSE_SIZE + challengeRespDefaultBytes; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h index 4dfe556c..228114cf 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h @@ -116,20 +116,22 @@ typedef struct { /* Helper and batch process functions */ uint16_t CallInstructionHandler(uint8_t *Buffer, uint16_t ByteCount); -/* - * The following section implements: - * DESFire EV0 / D40 specific commands - */ - +/* DESFire EV0 / D40 specific commands: */ uint16_t EV0CmdGetVersion1(uint8_t *Buffer, uint16_t ByteCount); uint16_t EV0CmdGetVersion2(uint8_t *Buffer, uint16_t ByteCount); uint16_t EV0CmdGetVersion3(uint8_t *Buffer, uint16_t ByteCount); uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount); uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount); +/* Other authenticate commands: */ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount); uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount); uint16_t DesfireCmdAuthenticateAES1(uint8_t *Buffer, uint16_t ByteCount); uint16_t DesfireCmdAuthenticateAES2(uint8_t *Buffer, uint16_t ByteCount); +/* ISO7816 authenticate commands: */ +uint16_t ISO7816CmdGetChallenge(uint8_t *Buffer, uint16_t ByteCount); +uint16_t ISO7816CmdExternalAuthenticate(uint8_t *Buffer, uint16_t ByteCount); +uint16_t ISO7816CmdInternalAuthenticate(uint8_t *Buffer, uint16_t ByteCount); + #endif diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.c index 1285797e..f84426ab 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.c @@ -31,19 +31,7 @@ This notice must be retained at the top of all source files where indicated. #include "DESFireISO14443Support.h" #include "DESFireLogging.h" -#ifdef DESFIRE_DEFAULT_DEBUGGING_MODE -DESFireLoggingMode LocalLoggingMode = DESFIRE_DEFAULT_LOGGING_MODE; -#else -DESFireLoggingMode LocalLoggingMode = DEBUGGING; -#endif - -#ifdef DESFIRE_DEFAULT_TESTING_MODE -BYTE LocalTestingMode = DESFIRE_DEFAULT_TESTING_MODE; -#else -BYTE LocalTestingMode = 0x00; -#endif - -#ifdef DESFIRE_DEBUGGING && DESFIRE_DEBUGGING != 0 +#ifdef DESFIRE_DEBUGGING void DesfireLogEntry(LogEntryEnum LogCode, void *LogDataBuffer, uint16_t BufSize) { if (BufSize >= DESFIRE_MIN_OUTGOING_LOGSIZE) { LogEntry(LogCode, (void *) LogDataBuffer, BufSize); @@ -53,12 +41,12 @@ void DesfireLogEntry(LogEntryEnum LogCode, void *LogDataBuffer, uint16_t BufSize void DesfireLogEntry(LogEntryEnum LogCode, void *LogDataBuffer, uint16_t BufSize) {} #endif -#ifdef DESFIRE_DEBUGGING && DESFIRE_DEBUGGING != 0 +#ifdef DESFIRE_DEBUGGING void DesfireLogISOStateChange(int state, int logCode) { const char *statePrintName; int logLength = 0; do { - switch (logCode) { + switch (state) { case ISO14443_4_STATE_EXPECT_RATS: statePrintName = PSTR("ISO14443_4_STATE_EXPECT_RATS"); break; @@ -71,11 +59,17 @@ void DesfireLogISOStateChange(int state, int logCode) { case ISO14443_3A_STATE_IDLE: statePrintName = PSTR("ISO14443_3A_STATE_IDLE"); break; - case ISO14443_3A_STATE_READY1: - statePrintName = PSTR("ISO14443_3A_STATE_READY1"); + case ISO14443_3A_STATE_READY_CL1: + statePrintName = PSTR("ISO14443_3A_STATE_READY_CL1"); + break; + case ISO14443_3A_STATE_READY_CL1_NVB_END: + statePrintName = PSTR("ISO14443_3A_STATE_READY_CL1_NVB_END"); + break; + case ISO14443_3A_STATE_READY_CL2: + statePrintName = PSTR("ISO14443_3A_STATE_READY_CL2"); break; - case ISO14443_3A_STATE_READY2: - statePrintName = PSTR("ISO14443_3A_STATE_READY2"); + case ISO14443_3A_STATE_READY_CL2_NVB_END: + statePrintName = PSTR("ISO14443_3A_STATE_READY_CL2_NVB_END"); break; case ISO14443_3A_STATE_ACTIVE: statePrintName = PSTR("ISO14443_3A_STATE_ACTIVE"); @@ -88,12 +82,11 @@ void DesfireLogISOStateChange(int state, int logCode) { break; } } while (0); - snprintf_P(STRING_BUFFER_SIZE, (char *) __InternalStringBuffer, - PSTR("State CHG -- %s"), statePrintName); + snprintf_P((char *) __InternalStringBuffer, STRING_BUFFER_SIZE, PSTR("")); + strcat_P((char *) __InternalStringBuffer, statePrintName); logLength = StringLength((char *) __InternalStringBuffer, STRING_BUFFER_SIZE); - DesfireLogEntry(LOG_ERR_DESFIRE_GENERIC_ERROR, - (char *) __InternalStringBuffer, logLength); + DesfireLogEntry(logCode, (char *) __InternalStringBuffer, logLength); } #else void DesfireLogISOStateChange(int state, int logCode) {} diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h index 87c94192..fc45993a 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h @@ -39,40 +39,18 @@ This notice must be retained at the top of all source files where indicated. #define DESFIRE_MIN_OUTGOING_LOGSIZE (1) #endif -typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { - OFF = 0, - NORMAL = 1, - VERBOSE = 2, - DEBUGGING = 3, -} DESFireLoggingMode; - -#ifndef DESFIRE_DEFAULT_LOGGING_MODE -#define DESFIRE_DEFAULT_LOGGING_MODE (OFF) -#endif - -extern DESFireLoggingMode LocalLoggingMode; - -/* - * This variable can be toggled to indicated whether to employ - * testable pseudo-randomness in the encrypted transfers. - * When this value id non-zero, then any random session numbers - * (e.g., RndB) and IV salt vectors should default back to - * predictable constant values for testing purposes. - */ -extern BYTE LocalTestingMode; - void DesfireLogEntry(LogEntryEnum LogCode, void *LogDataBuffer, uint16_t BufSize); void DesfireLogISOStateChange(int state, int logCode); -#ifdef DESFIRE_DEBUGGING && DESFIRE_DEBUGGING != 0 +#ifdef DESFIRE_DEBUGGING #define DEBUG_PRINT_P(fmtStr, ...) ({ \ uint8_t logLength = 0; \ do { \ snprintf_P((char *) __InternalStringBuffer, STRING_BUFFER_SIZE, \ - fmtStr, ##__VA_ARGS__); \ + (const char *) fmtStr, ##__VA_ARGS__); \ logLength = StringLength((char *) __InternalStringBuffer, \ STRING_BUFFER_SIZE); \ - DesfireLogEntry(LOG_ERR_DESFIRE_GENERIC_ERROR, \ + DesfireLogEntry(LOG_INFO_DESFIRE_DEBUGGING_OUTPUT, \ (char *) __InternalStringBuffer, logLength); \ } while(0); \ }) @@ -80,19 +58,11 @@ void DesfireLogISOStateChange(int state, int logCode); #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 @@"), \ + PSTR("@@ LINE #%d in \"%s\" @@"), \ __LINE__, __FILE__); \ __InternalStringBuffer[STRING_BUFFER_SIZE - 1] = '\0'; \ } while(0); \ @@ -103,10 +73,10 @@ void DesfireLogISOStateChange(int state, int logCode); #define GetSymbolNameString(symbolName) ({ \ char *strBuffer; \ do { \ - strncpy_P(__InternalStringBuffer2, PSTR(#symbolName), \ - DATA_BUFFER_SIZE_SMALL); \ + strncpy_P(__InternalStringBuffer, PSTR(#symbolName), \ + STRING_BUFFER_SIZE); \ } while(0); \ - strBuffer = __InternalStringBuffer2; \ + strBuffer = __InternalStringBuffer; \ strBuffer; \ }) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.c index ddb0c8da..22d29e61 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.c @@ -37,7 +37,6 @@ This notice must be retained at the top of all source files where indicated. #define BLOCKWISE_IO_MULTIPLIER (DESFIRE_BLOCK_SIZE) volatile char __InternalStringBuffer[STRING_BUFFER_SIZE] = { 0 }; -char __InternalStringBuffer2[DATA_BUFFER_SIZE_SMALL] = { 0 }; void ReadBlockBytes(void *Buffer, SIZET StartBlock, SIZET Count) { if (StartBlock * BLOCKWISE_IO_MULTIPLIER >= MEMORY_SIZE_PER_SETTING) { diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.h index f4231604..714ee150 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.h @@ -33,10 +33,8 @@ This notice must be retained at the top of all source files where indicated. /* Reserve some space on the stack (text / data segment) for intermediate storage of strings and data we need to write so we do not have to rely on a bothersome heap-based scheme for passing pointers to functions: */ -#define DATA_BUFFER_SIZE_SMALL (16) -#define STRING_BUFFER_SIZE (32) +#define STRING_BUFFER_SIZE (48) extern volatile char __InternalStringBuffer[STRING_BUFFER_SIZE]; -extern char __InternalStringBuffer2[DATA_BUFFER_SIZE_SMALL]; /* * EEPROM and FRAM memory management routines: diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c index cf04ccf6..ab2b896c 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c @@ -213,7 +213,7 @@ void InitialisePiccBackendEV0(uint8_t StorageSize, bool formatPICC) { ReadBlockBytes(&Picc, DESFIRE_PICC_INFO_BLOCK_ID, sizeof(DESFirePICCInfoType)); if (formatPICC) { DEBUG_PRINT_P(PSTR("Factory reset -- EV0")); - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_PICC_RESET, (void *) NULL, 0)); + DesfireLogEntry(LOG_INFO_DESFIRE_PICC_RESET, (void *) NULL, 0); FactoryFormatPiccEV0(); } else { ReadBlockBytes(&AppDir, DESFIRE_APP_DIR_BLOCK_ID, sizeof(DESFireAppDirType)); @@ -232,7 +232,7 @@ void InitialisePiccBackendEV1(uint8_t StorageSize, bool formatPICC) { 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)); + DesfireLogEntry(LOG_INFO_DESFIRE_PICC_RESET, (void *) NULL, 0); FactoryFormatPiccEV1(StorageSize); } else { ReadBlockBytes(&AppDir, DESFIRE_APP_DIR_BLOCK_ID, sizeof(DESFireAppDirType)); @@ -251,7 +251,7 @@ void InitialisePiccBackendEV2(uint8_t StorageSize, bool formatPICC) { 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)); + DesfireLogEntry(LOG_INFO_DESFIRE_PICC_RESET, (void *) NULL, 0); FactoryFormatPiccEV2(StorageSize); } else { ReadBlockBytes(&AppDir, DESFIRE_APP_DIR_BLOCK_ID, sizeof(DESFireAppDirType)); @@ -278,7 +278,9 @@ void GetPiccHardwareVersionInfo(uint8_t *Buffer) { void GetPiccSoftwareVersionInfo(uint8_t *Buffer) { Buffer[0] = Picc.SwVersionMajor; Buffer[1] = Picc.SwVersionMinor; - Buffer[2] = Picc.StorageSize; + uint16_t cardCapacityBlocks = GetCardCapacityBlocks(); + uint8_t freeMemoryBytes = (uint8_t)(cardCapacityBlocks * DESFIRE_BLOCK_SIZE); + Buffer[2] = freeMemoryBytes; } void GetPiccManufactureInfo(uint8_t *Buffer) { @@ -302,9 +304,9 @@ void FormatPicc(void) { memset(&AppDir, 0x00, sizeof(DESFireAppDirType)); memset(&SelectedApp, 0x00, sizeof(SelectedAppCacheType)); /* Set a random new UID */ - BYTE uidData[DESFIRE_UID_SIZE]; - RandomGetBuffer(uidData, DESFIRE_UID_SIZE); - memcpy(&Picc.Uid[0], uidData, DESFIRE_UID_SIZE); + BYTE uidData[DESFIRE_UID_SIZE - 1]; + RandomGetBuffer(uidData, DESFIRE_UID_SIZE - 1); + memcpy(&Picc.Uid[1], uidData, DESFIRE_UID_SIZE - 1); /* Conform to NXP Application Note AN10927 about the first * byte of a randomly generated UID (refer to section 2.1.1). */ @@ -314,8 +316,8 @@ void FormatPicc(void) { RandomGetBuffer(batchNumberData, 5); memcpy(&Picc.BatchNumber[0], batchNumberData, 5); /* Default production date -- until the user changes them: */ - Picc.ProductionWeek = 0x00; - Picc.ProductionYear = 0x00; + Picc.ProductionWeek = 0x01; + Picc.ProductionYear = 0x01; /* Assign the default manufacturer ID: */ Picc.ManufacturerID = DESFIRE_MANUFACTURER_ID; /* Set the ATS bytes to defaults: */ @@ -338,13 +340,13 @@ void CreatePiccApp(void) { BYTE MasterAppAID[] = { 0x00, 0x00, 0x00 }; BYTE statusCode = CreateApp(MasterAppAID, DESFIRE_MAX_KEYS, 0x0f); if (statusCode != STATUS_OPERATION_OK) { - const char *loggingMsg = PSTR("CreateApp returned -- %d\n"); - DEBUG_PRINT_P(loggingMsg, statusCode); + DEBUG_PRINT_P(PSTR("CreateApp returned -- %d\n"), statusCode); } SelectPiccApp(); memset(&Key, 0x00, sizeof(CryptoKeyBufferType)); WriteAppKey(0x00, 0x00, Key, sizeof(CryptoKeyBufferType)); SynchronizeAppDir(); + SynchronizePICCInfo(); } void FactoryFormatPiccEV0(void) { diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h index c3866e20..c5168fab 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h @@ -115,7 +115,7 @@ extern uint16_t DesfireATQAValue; #define PICC_FORMAT_BYTE 0x00 #define PICC_EMPTY_BYTE 0x00 -typedef struct { +typedef struct DESFIRE_FIRMWARE_PACKING DESFIRE_FIRMWARE_ALIGNAT { /* Static data: does not change during the PICC's lifetime. * We will add Chameleon Mini terminal commands to enable * resetting this data so tags can be emulated authentically. @@ -136,9 +136,9 @@ typedef struct { /* Dynamic data: changes during the PICC's lifetime */ uint16_t FirstFreeBlock; uint8_t TransactionStarted; -} DESFirePICCInfoType DESFIRE_FIRMWARE_PACKING; +} DESFirePICCInfoType; -typedef struct { +typedef struct DESFIRE_FIRMWARE_PACKING DESFIRE_FIRMWARE_ALIGNAT { BYTE Slot; BYTE KeyCount; BYTE MaxKeyCount; @@ -152,7 +152,7 @@ typedef struct { SIZET KeyVersionsArray; /* Block offset in FRAM */ SIZET KeyTypesArray; /* Block offset in FRAM */ SIZET KeyAddress; /* Block offset in FRAM */ -} SelectedAppCacheType DESFIRE_FIRMWARE_PACKING; +} SelectedAppCacheType; extern BYTE SELECTED_APP_CACHE_TYPE_BLOCK_SIZE; extern BYTE APP_CACHE_KEY_SETTINGS_ARRAY_BLOCK_SIZE; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c index abce8a30..172870db 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c @@ -74,10 +74,10 @@ int32_t Int32FromByteBuffer(uint8_t *byteBuffer) { if (byteBuffer == NULL) { return 0; } - int32_t b0 = byteBuffer[0]; - int32_t b1 = (byteBuffer[1] << 8) & 0x0000ff00; - int32_t b2 = (byteBuffer[2] << 16) & 0x00ff0000; - int32_t b3 = (byteBuffer[3] << 24) & 0xff000000; + int32_t b0 = (int32_t) byteBuffer[0]; + int32_t b1 = ((int32_t) byteBuffer[1] << 8) & 0x0000ff00; + int32_t b2 = ((int32_t) byteBuffer[2] << 16) & 0x00ff0000; + int32_t b3 = ((int32_t) byteBuffer[3] << 24) & 0xff000000; return b0 | b1 | b2 | b3; } @@ -94,8 +94,7 @@ uint16_t DesfireAddParityBits(uint8_t *Buffer, uint16_t BitCount) { if (BitCount % 8) return BitCount; uint8_t *currByte, * tmpByte; - uint8_t *const lastByte = Buffer + BitCount / 8 + BitCount / 64; // starting address + number of bytes + - // number of parity bytes + uint8_t *const lastByte = Buffer + BitCount / 8 + BitCount / 64; // starting address + number of bytes + number of parity bytes currByte = Buffer + BitCount / 8 - 1; uint8_t parity; memset(currByte + 1, 0, lastByte - currByte); // zeroize all bytes used for parity bits @@ -116,7 +115,7 @@ uint16_t DesfireAddParityBits(uint8_t *Buffer, uint16_t BitCount) { } uint16_t DesfireRemoveParityBits(uint8_t *Buffer, uint16_t BitCount) { - // Short frame, no parity bit is added + /* Short frame, no parity bit is added: */ if (BitCount == 7) return 7; @@ -148,8 +147,8 @@ bool DesfireCheckParityBits(uint8_t *Buffer, uint16_t BitCount) { } uint16_t DesfirePreprocessAPDUWrapper(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize, bool TruncateChecksumBytes) { + uint16_t ChecksumBytes = 0; switch (CommMode) { - uint16_t ChecksumBytes = 0; case DESFIRE_COMMS_PLAINTEXT_MAC: { if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_DES || DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_2KTDEA) { ChecksumBytes = 4; @@ -205,7 +204,7 @@ uint16_t DesfirePostprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t Buff if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_DES || DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_2KTDEA) { return appendBufferMAC(SessionKey, Buffer, BufferSize); } else { - // AES-128 or 3DES: + /* AES-128 or 3DES: */ uint16_t MacedBytes = appendBufferCMAC(DesfireCommandState.CryptoMethodType, SessionKey, Buffer, BufferSize, SessionIV); memcpy(SessionIV, &Buffer[BufferSize], MacedBytes - BufferSize); return MacedBytes; @@ -213,7 +212,7 @@ uint16_t DesfirePostprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t Buff break; } case DESFIRE_COMMS_CIPHERTEXT_DES: { - // TripleDES: + /* TripleDES: */ uint16_t CryptoBlockSize = CRYPTO_3KTDEA_BLOCK_SIZE; uint16_t BlockPadding = 0; if ((BufferSize % CryptoBlockSize) != 0) { diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h index 25cc6f0e..d4dd0e86 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h @@ -60,6 +60,12 @@ uint16_t DesfireAddParityBits(uint8_t *Buffer, uint16_t bits); uint16_t DesfireRemoveParityBits(uint8_t *Buffer, uint16_t BitCount); bool DesfireCheckParityBits(uint8_t *Buffer, uint16_t BitCount); +#ifdef DESFIRE_DEBUGGING +#define DesfireDebuggingOn (DESFIRE_DEBUGGING != 0) +#else +#define DesfireDebuggingOn (false) +#endif + /* Add utility wrapper functions to perform pre and postprocessing on * the raw input APDU commands sent by the PCD depending on which * CommMode (PLAINTEXT|PLAINTEXT-MAC|ENCIPHERED-CMAC-3DES|ECIPHERED-CMAC-AES128) diff --git a/Firmware/Chameleon-Mini/Application/ISO14443-3A.c b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c index 067a04f6..32e71215 100644 --- a/Firmware/Chameleon-Mini/Application/ISO14443-3A.c +++ b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c @@ -14,20 +14,18 @@ bool ISO14443ASelectDesfire(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, ui uint8_t *DataPtr = (uint8_t *) Buffer; uint8_t NVB = DataPtr[1]; switch (NVB) { - case ISO14443A_NVB_AC_START: /* Start of anticollision procedure. - * Send whole UID CLn + BCC */ - DataPtr[0] = UidCL[0]; - DataPtr[1] = UidCL[1]; - DataPtr[2] = UidCL[2]; - DataPtr[3] = UidCL[3]; + * Send whole UID CLn + BCC + */ + memcpy(&DataPtr[0], &UidCL[0], 4); DataPtr[ISO14443A_CL_BCC_OFFSET] = ISO14443A_CALC_BCC(DataPtr); *BitCount = ISO14443A_CL_FRAME_SIZE; return false; case ISO14443A_NVB_AC_END: /* End of anticollision procedure. - * Send SAK CLn if we are selected. */ + * Send SAK CLn if we are selected. + */ if (!memcmp(&DataPtr[2], &UidCL[0], 4)) { DataPtr[0] = SAKValue; ISO14443AAppendCRCA(Buffer, 1); @@ -38,11 +36,28 @@ bool ISO14443ASelectDesfire(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, ui *BitCount = 0; return false; } - default: - /* No anticollision supported */ - *BitCount = 0; - return false; + default: { + uint8_t CollisionByteCount = ((NVB >> 4) & 0x0f) - 2; + uint8_t CollisionBitCount = (NVB >> 0) & 0x0f; + uint8_t mask = 0xFF >> (8 - CollisionBitCount); + // Since the UidCL does not contain the BCC, we have to distinguish here + if ( + ((CollisionByteCount == 5 || (CollisionByteCount == 4 && CollisionBitCount > 0)) && memcmp(UidCL, &DataPtr[2], 4) == 0 && (ISO14443A_CALC_BCC(UidCL) & mask) == (DataPtr[6] & mask)) + || + (CollisionByteCount == 4 && CollisionBitCount == 0 && memcmp(UidCL, &DataPtr[2], 4) == 0) + || + (CollisionByteCount < 4 && memcmp(UidCL, &DataPtr[2], CollisionByteCount) == 0 && (UidCL[CollisionByteCount] & mask) == (DataPtr[CollisionByteCount + 2] & mask)) + ) { + memcpy(&DataPtr[0], &UidCL[0], 4); + DataPtr[ISO14443A_CL_BCC_OFFSET] = ISO14443A_CALC_BCC(DataPtr); + *BitCount = ISO14443A_CL_FRAME_SIZE; + return false; + } + } } + /* No anticollision supported */ + *BitCount = 0; + return false; } #endif /* CONFIG_MF_DESFIRE_SUPPORT */ diff --git a/Firmware/Chameleon-Mini/Application/ISO14443-3A.h b/Firmware/Chameleon-Mini/Application/ISO14443-3A.h index 3faee877..d127b60b 100644 --- a/Firmware/Chameleon-Mini/Application/ISO14443-3A.h +++ b/Firmware/Chameleon-Mini/Application/ISO14443-3A.h @@ -11,7 +11,7 @@ #include "../Common.h" #include -#define ISO14443A_UID_SIZE_SINGLE 4 /* bytes */ +#define ISO14443A_UID_SIZE_SINGLE 4 #define ISO14443A_UID_SIZE_DOUBLE 7 #define ISO14443A_UID_SIZE_TRIPLE 10 @@ -28,8 +28,8 @@ #define ISO14443A_CL_UID_OFFSET 0 #define ISO14443A_CL_UID_SIZE 4 #define ISO14443A_CL_BCC_OFFSET 4 -#define ISO14443A_CL_BCC_SIZE 1 /* Byte */ -#define ISO14443A_CL_FRAME_SIZE ((ISO14443A_CL_UID_SIZE + ISO14443A_CL_BCC_SIZE) * 8) /* UID[N...N+3] || BCCN */ +#define ISO14443A_CL_BCC_SIZE 1 +#define ISO14443A_CL_FRAME_SIZE ((ISO14443A_CL_UID_SIZE + ISO14443A_CL_BCC_SIZE) * BITS_PER_BYTE) /* UID[N...N+3] || BCCN */ #define ISO14443A_SAK_INCOMPLETE 0x24 #define ISO14443A_SAK_INCOMPLETE_NOT_COMPLIANT 0x04 #define ISO14443A_SAK_COMPLETE_COMPLIANT 0x20 diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index 9941797a..6f5d8f74 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -43,11 +43,6 @@ This notice must be retained at the top of all source files where indicated. #include "DESFire/DESFireLogging.h" #include "DESFire/DESFireUtils.h" -#define IsControlCmd(Buffer, BitCount) \ - (BitCount > 0 && \ - ((Buffer[0] == ISO14443A_CMD_WUPA) || \ - (Buffer[0] == ISO14443A_CMD_REQA))) - DesfireStateType DesfireState = DESFIRE_HALT; DesfireStateType DesfirePreviousState = DESFIRE_IDLE; @@ -56,9 +51,18 @@ Iso7816WrappedCommandType_t Iso7816CmdType; bool DesfireFromHalt = false; BYTE DesfireCmdCLA = DESFIRE_NATIVE_CLA; +uint16_t ISO14443AStoreLastDataFrameAndReturn(const uint8_t *Buffer, uint16_t BufferBitCount) { + if (BufferBitCount > 0) { + uint16_t ISO14443ALastDataFrameBytes = MIN(ASBYTES(BufferBitCount), MAX_DATA_FRAME_XFER_SIZE); + memcpy(&ISO14443ALastDataFrame[0], &Buffer[0], ISO14443ALastDataFrameBytes); + ISO14443ALastDataFrameBits = BufferBitCount; + } + return BufferBitCount; +} + static void MifareDesfireAppInitLocal(uint8_t StorageSize, uint8_t Version, bool FormatPICC) { ResetLocalStructureData(); - DesfireState = DESFIRE_IDLE; + DesfireState = DESFIRE_HALT; DesfireFromHalt = false; switch (Version) { case MIFARE_DESFIRE_EV2: @@ -108,12 +112,14 @@ void MifareDesfire4kEV2AppInitRunOnce(void) { } void MifareDesfireAppReset(void) { - /* This is called repeatedly -- limit the amount of work done */ - MifareDesfireReset(); + /* EMPTY: This is called repeatedly -- limit the amount of work done */ } void MifareDesfireAppTick(void) { - /* EMPTY -- Do nothing. */ + if (!CheckStateRetryCount(false)) { + ResetISOState(); + MifareDesfireReset(); + } } void MifareDesfireAppTask(void) { @@ -122,22 +128,18 @@ void MifareDesfireAppTask(void) { 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])) { - LastReaderSentCmd = Buffer[0]; } else if (Buffer[0] != STATUS_ADDITIONAL_FRAME) { DesfireState = DESFIRE_IDLE; - LastReaderSentCmd = Buffer[0]; - uint16_t ReturnBytes = CallInstructionHandler(Buffer, ByteCount); - return ReturnBytes; - } else { - LastReaderSentCmd = Buffer[0]; } + LastReaderSentCmd = Buffer[0]; uint16_t ReturnBytes = 0; switch (DesfireState) { + case DESFIRE_IDLE: + ReturnBytes = CallInstructionHandler(Buffer, ByteCount); + break; case DESFIRE_GET_VERSION2: ReturnBytes = EV0CmdGetVersion2(Buffer, ByteCount); break; @@ -157,16 +159,13 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { ReturnBytes = DesfireCmdAuthenticateAES2(Buffer, ByteCount); break; case DESFIRE_ISO7816_EXT_AUTH: - DEBUG_PRINT_P(PSTR("Not Implemented -- ISO7816-ExtAuth")); - ReturnBytes = ISO14443A_APP_NO_RESPONSE; + ReturnBytes = ISO7816CmdExternalAuthenticate(Buffer, ByteCount); break; case DESFIRE_ISO7816_INT_AUTH: - DEBUG_PRINT_P(PSTR("Not Implemented -- ISO7816-IntAuth")); - ReturnBytes = ISO14443A_APP_NO_RESPONSE; + ReturnBytes = ISO7816CmdInternalAuthenticate(Buffer, ByteCount); break; case DESFIRE_ISO7816_GET_CHALLENGE: - DEBUG_PRINT_P(PSTR("Not Implemented -- ISO7816-GetChal")); - ReturnBytes = ISO14443A_APP_NO_RESPONSE; + ReturnBytes = ISO7816CmdExternalAuthenticate(Buffer, ByteCount); break; case DESFIRE_READ_DATA_FILE: ReturnBytes = ReadDataFileIterator(Buffer); @@ -175,10 +174,9 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { ReturnBytes = WriteDataFileInternal(&Buffer[1], ByteCount - 1); break; default: - /* Should not happen. */ - DEBUG_PRINT_P(PSTR("ERROR -- Unexpected state!")); Buffer[0] = STATUS_PICC_INTEGRITY_ERROR; - return DESFIRE_STATUS_RESPONSE_SIZE; + ReturnBytes = DESFIRE_STATUS_RESPONSE_SIZE; + break; } return ReturnBytes; @@ -187,8 +185,6 @@ 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); - 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])) { @@ -240,10 +236,10 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { } uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { - uint16_t ReturnedBytes = 0; + uint16_t ReturnBytes = 0; uint16_t ByteCount = ASBYTES(BitCount); - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount)); - if (ByteCount > 1 && !memcmp(&Buffer[0], &ISO14443ALastIncomingDataFrame[0], MIN(ASBYTES(ISO14443ALastIncomingDataFrameBits), ByteCount))) { + if (ByteCount >= 1 && BitCount == ISO14443ALastIncomingDataFrameBits && ISO14443ALastDataFrameBits > 0 && + !memcmp(&Buffer[0], &ISO14443ALastIncomingDataFrame[0], ByteCount)) { /* The PCD resent the same data frame (probably a synchronization issue): * Send out the same data as last time: */ @@ -270,7 +266,6 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { } memcpy(&Buffer[0], &ISO7816PrologueBytes[0], 2); ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount + 2); - 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 && @@ -295,7 +290,6 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { Buffer[ProcessedByteCount - 1] = 0x91; ++ProcessedByteCount; ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount + 2); - 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) { @@ -308,10 +302,11 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { return ISO14443A_APP_NO_RESPONSE; } ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, 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) { + } else if ((ByteCount >= 8 && DesfireCLA(Buffer[1]) && + Buffer[3] == 0x00 && Buffer[4] == 0x00 && Buffer[5] == ByteCount - 8) || + (ByteCount >= 9 && DesfireCLA(Buffer[1]) && + Buffer[3] == 0x00 && Buffer[4] == 0x00 && Buffer[5] == ByteCount - 9)) { uint16_t UnwrappedByteCount = DesfirePreprocessAPDUAndTruncate(ActiveCommMode, Buffer, ByteCount); if (UnwrappedByteCount == 0) { return ISO14443A_APP_NO_RESPONSE; @@ -328,7 +323,6 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { memmove(&Buffer[1], &Buffer[0], ProcessedByteCount); Buffer[0] = hf14AScanPrologue; ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount); - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount)); return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ProcessedByteCount)); } Iso7816CmdType = IsWrappedISO7816CommandType(Buffer, ByteCount); @@ -378,34 +372,45 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { } memcpy(&Buffer[0], &ISO7816PrologueBytes[0], 2); ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount + 2); - 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) { + } else if (ByteCount >= 5 && (Iso144433AState == ISO14443_3A_STATE_IDLE || Iso144433AState == ISO14443_3A_STATE_ACTIVE) && + Buffer[0] != ISO14443A_CMD_RATS && Buffer[0] != ISO14443A_CMD_REQA && + !ISO14443ACmdIsWUPA(Buffer[0]) && !ISO144433AIsHalt(Buffer, BitCount)) { + uint16_t IncomingByteCount = DesfirePreprocessAPDUAndTruncate(ActiveCommMode, Buffer, ByteCount); + if (IncomingByteCount > 2) { + IncomingByteCount -= 2; + ReturnBytes = CallInstructionHandler(&Buffer[2], IncomingByteCount); + if (ReturnBytes != ISO14443A_APP_NO_RESPONSE) { + uint16_t OutgoingByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ReturnBytes + 2); + return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(OutgoingByteCount)); + } + } + } else if (BitCount >= BITS_PER_BYTE && (Iso144433AState == ISO14443_3A_STATE_IDLE || Iso144433AState == ISO14443_3A_STATE_ACTIVE) && + Buffer[0] != ISO14443A_CMD_RATS && Buffer[0] != ISO14443A_CMD_REQA && + !ISO14443ACmdIsWUPA(Buffer[0]) && !ISO144433AIsHalt(Buffer, BitCount)) { /* This case should handle non-wrappped native commands. No pre/postprocessing afterwards: */ - 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); - uint16_t PiccProcessRespBytesCeil = ASBYTES(PiccProcessRespBits); - if (PiccProcessRespBits >= BITS_PER_BYTE) { - PiccProcessRespBits = ASBITS(PiccProcessRespBytesCeil); + ReturnBytes = CallInstructionHandler(Buffer, ByteCount); + if (ReturnBytes != ISO14443A_APP_NO_RESPONSE) { + uint16_t OutgoingByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ReturnBytes); + return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(OutgoingByteCount)); } - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, PiccProcessRespBytesCeil)); - return ISO14443AStoreLastDataFrameAndReturn(Buffer, PiccProcessRespBits); } - return ISO14443A_APP_NO_RESPONSE; + /* Default / Fall through -- No other cases matched -- Send it through the ISO14443A PICC handler: */ + uint16_t PiccProcessRespBits = ISO144433APiccProcess(Buffer, BitCount); + uint16_t PiccProcessRespBytesCeil = ASBYTES(PiccProcessRespBits); + if (PiccProcessRespBits >= BITS_PER_BYTE) { + PiccProcessRespBits = ASBITS(PiccProcessRespBytesCeil); + } + return ISO14443AStoreLastDataFrameAndReturn(Buffer, PiccProcessRespBits); } void MifareDesfireReset(void) { - ResetISOState(); DesfireState = DESFIRE_IDLE; } void ResetLocalStructureData(void) { - DesfirePreviousState = DESFIRE_IDLE; - DesfireState = DESFIRE_HALT; - InvalidateAuthState(0x00); + DesfireState = DesfirePreviousState = DESFIRE_IDLE; + InvalidateAuthState(0); memset(&Picc, PICC_FORMAT_BYTE, sizeof(Picc)); memset(&AppDir, 0x00, sizeof(AppDir)); memset(&SelectedApp, 0x00, sizeof(SelectedApp)); @@ -413,9 +418,10 @@ void ResetLocalStructureData(void) { memset(&TransferState, 0x00, sizeof(TransferState)); memset(&SessionKey, 0x00, sizeof(CryptoKeyBufferType)); memset(&SessionIV, 0x00, sizeof(CryptoIVBufferType)); - SessionIVByteSize = 0x00; + SessionIVByteSize = 0; SelectedApp.Slot = 0; SelectedFile.Num = -1; + ResetISOState(); MifareDesfireReset(); } diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.h b/Firmware/Chameleon-Mini/Application/MifareDESFire.h index c4c6a2cf..05a16706 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.h +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.h @@ -37,6 +37,9 @@ This notice must be retained at the top of all source files where indicated. #include "DESFire/DESFireISO7816Support.h" #include "DESFire/DESFireInstructions.h" +#define DesfireCLA(cmdCode) \ + ((cmdCode == DESFIRE_NATIVE_CLA) || Iso7816CLA(cmdCode)) + void MifareDesfireEV0AppInit(void); void MifareDesfireEV0AppInitRunOnce(void); void MifareDesfire2kEV1AppInit(void); @@ -64,7 +67,6 @@ void MifareDesfireSetUid(ConfigurationUidType Uid); typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { DESFIRE_HALT = ISO14443_3A_STATE_HALT + 1, DESFIRE_IDLE, - DESFIRE_IDLE2, DESFIRE_GET_VERSION2, DESFIRE_GET_VERSION3, DESFIRE_GET_APPLICATION_IDS2, @@ -81,17 +83,6 @@ 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) || \ @@ -107,4 +98,12 @@ extern BYTE DesfireCmdCLA; (cmdCode == CMD_ISO7816_INTERNAL_AUTHENTICATE) || \ (cmdCode == CMD_ISO7816_GET_CHALLENGE)) +extern DesfireStateType DesfireState; +extern DesfireStateType DesfirePreviousState; + +extern Iso7816WrappedCommandType_t Iso7816CmdType; + +extern bool DesfireFromHalt; +extern BYTE DesfireCmdCLA; + #endif /* MIFAREDESFIRE_H_ */ diff --git a/Firmware/Chameleon-Mini/Application/Reader14443A.c b/Firmware/Chameleon-Mini/Application/Reader14443A.c index 988c0566..4ff8f083 100644 --- a/Firmware/Chameleon-Mini/Application/Reader14443A.c +++ b/Firmware/Chameleon-Mini/Application/Reader14443A.c @@ -866,7 +866,7 @@ uint16_t Reader14443AAppProcess(uint8_t *Buffer, uint16_t BitCount) { cfgid = -1; } - if (cfgid > -1) { + if (cfgid > -1) { /* TODO: Consider wrapping strings with PSTR(...): */ CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, "Cloned OK!"); /* Notify LED. blink when clone is done - ToDo: maybe use other LEDHook */ LEDHook(LED_SETTING_CHANGE, LED_BLINK_2X); diff --git a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk index 17dcb327..7345bdab 100644 --- a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk +++ b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk @@ -73,8 +73,6 @@ desfire-dev: EXTRA_CONFIG_SETTINGS:=-DMEMORY_LIMITED_TESTING \ -finline-small-functions \ -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 \ -DDESFIRE_MIN_INCOMING_LOGSIZE=0 \ - -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING \ - -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) diff --git a/Firmware/Chameleon-Mini/Chameleon-Mini.c b/Firmware/Chameleon-Mini/Chameleon-Mini.c index 54d87ba8..54501d4d 100644 --- a/Firmware/Chameleon-Mini/Chameleon-Mini.c +++ b/Firmware/Chameleon-Mini/Chameleon-Mini.c @@ -17,8 +17,9 @@ int main(void) { while (1) { if (SystemTick100ms()) { - LEDTick(); // this has to be the first function called here, since it is time-critical - - // the functions below may have non-negligible runtimes! + LEDTick(); /* This has to be the first function called here, since it is time-critical - + * the functions below may have non-negligible runtimes! + */ PinTick(); RandomTick(); TerminalTick(); diff --git a/Firmware/Chameleon-Mini/Common.c b/Firmware/Chameleon-Mini/Common.c index 99066a6d..e333fb3b 100644 --- a/Firmware/Chameleon-Mini/Common.c +++ b/Firmware/Chameleon-Mini/Common.c @@ -81,4 +81,3 @@ uint16_t HexStringToBuffer(void *Buffer, uint16_t MaxBytes, const char *HexIn) { return ByteCount; } - diff --git a/Firmware/Chameleon-Mini/Common.h b/Firmware/Chameleon-Mini/Common.h index d9472807..74fff7e6 100644 --- a/Firmware/Chameleon-Mini/Common.h +++ b/Firmware/Chameleon-Mini/Common.h @@ -15,10 +15,11 @@ #include #include -#define ODD_PARITY(Value) OddParityBit(Value)//(parity_even_bit(Value) ? 0 : 1) +#define ODD_PARITY(Value) OddParityBit(Value) +/* This function type has to be used for all the interrupt handlers that have to be changed at runtime: */ #define ISR_SHARED \ - void __attribute__((signal)) // This function type has to be used for all the interrupt handlers that have to be changed at runtime + void __attribute__((signal)) #define INLINE \ static inline __attribute__((always_inline)) diff --git a/Firmware/Chameleon-Mini/LiveLogTick.h b/Firmware/Chameleon-Mini/LiveLogTick.h index 6076c7e2..743c3df6 100644 --- a/Firmware/Chameleon-Mini/LiveLogTick.h +++ b/Firmware/Chameleon-Mini/LiveLogTick.h @@ -23,7 +23,7 @@ #define sei_memory() __asm volatile( "sei" ::: "memory" ) #ifndef FLUSH_LOGS_ON_SPACE_ERROR -#define FLUSH_LOGS_ON_SPACE_ERROR (1) +#define FLUSH_LOGS_ON_SPACE_ERROR (1) #endif typedef struct LogBlockListNode { uint8_t *logBlockDataStart; @@ -36,7 +36,7 @@ extern LogBlockListNode *LogBlockListBegin; extern LogBlockListNode *LogBlockListEnd; extern uint8_t LogBlockListElementCount; -#define LIVE_LOGGER_POST_TICKS (6) +#define LIVE_LOGGER_POST_TICKS (7) extern uint8_t LiveLogModePostTickCount; INLINE bool AtomicAppendLogBlock(LogEntryEnum logCode, uint16_t sysTickTime, const uint8_t *logData, uint8_t logDataSize); @@ -46,6 +46,7 @@ INLINE bool LiveLogTick(void); INLINE bool AtomicAppendLogBlock(LogEntryEnum logCode, uint16_t sysTickTime, const uint8_t *logData, uint8_t logDataSize) { + cli_memory(); bool status = true; if ((logDataSize + 4 + 3 + LOG_BLOCK_LIST_NODE_SIZE > LogMemLeft) && (LogMemPtr != LogMem)) { if (FLUSH_LOGS_ON_SPACE_ERROR) { @@ -80,6 +81,7 @@ AtomicAppendLogBlock(LogEntryEnum logCode, uint16_t sysTickTime, const uint8_t * } else { status = false; } + sei_memory(); return status; } @@ -93,7 +95,10 @@ FreeLogBlocks(void) { INLINE bool AtomicLiveLogTick(void) { - return LiveLogTick(); + //cli_memory(); + bool opStatus = LiveLogTick(); + //sei_memory(); + return opStatus; } INLINE bool @@ -103,7 +108,6 @@ LiveLogTick(void) { while (LogBlockListElementCount > 0) { TerminalFlushBuffer(); TerminalSendBlock(logBlockCurrent.logBlockDataStart, logBlockCurrent.logBlockDataSize); - TerminalFlushBuffer(); tempBlockPtr = logBlockCurrent.nextBlock; if (tempBlockPtr != NULL) { memcpy(&logBlockCurrent, tempBlockPtr, sizeof(LogBlockListNode)); @@ -114,6 +118,7 @@ LiveLogTick(void) { } FreeLogBlocks(); LiveLogModePostTickCount = 0; + TerminalFlushBuffer(); return true; } diff --git a/Firmware/Chameleon-Mini/Log.c b/Firmware/Chameleon-Mini/Log.c index 5cec3e31..5635ce27 100644 --- a/Firmware/Chameleon-Mini/Log.c +++ b/Firmware/Chameleon-Mini/Log.c @@ -76,21 +76,23 @@ void LogInit(void) { result = true; WriteEEPBlock((uint16_t) &LogFRAMAddrValid, &result, 1); } - LogEntry(LOG_INFO_SYSTEM_BOOT, NULL, 0); } void LogTick(void) { - // The logging functionality slows down the timings of data exchanges between - // Chameleon emulated tags and readers, so schedule the logging writes to - // happen only on intervals that will be outside of timing windows for individual xfers - // initiated from PICC <--> PCD (e.g., currently approximately every 600ms): - if ((++LiveLogModePostTickCount % LIVE_LOGGER_POST_TICKS) == 0) { - if (GlobalSettings.ActiveSettingPtr->LogMode == LOG_MODE_LIVE) + /* + * The logging functionality slows down the timings of data exchanges between + * Chameleon emulated tags and readers, so schedule the logging writes to + * happen only on intervals that will be outside of timing windows for individual xfers + * initiated from PICC <--> PCD (e.g., currently approximately every 600ms): + */ + if (GlobalSettings.ActiveSettingPtr->LogMode == LOG_MODE_LIVE) { + if ((++LiveLogModePostTickCount % LIVE_LOGGER_POST_TICKS) == 0) { AtomicLiveLogTick(); - if (EnableLogSRAMtoFRAM) - LogSRAMToFRAM(); - LiveLogModePostTickCount = 0; + LiveLogModePostTickCount = 0; + } + } else if (EnableLogSRAMtoFRAM) { + LogSRAMToFRAM(); } } diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index d184bcb7..48bb86cc 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -101,14 +101,8 @@ SETTINGS += -DENABLE_EEPROM_SETTINGS #SETTINGS += -DDISABLE_PERMISSIVE_DESFIRE_SETTINGS #SETTINGS += -DDISABLE_DESFIRE_TERMINAL_COMMANDS -## : Set a default logging mode for debugging with the DESFire -## : emulation code: -#CONFIG_SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING -CONFIG_SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=OFF - -## : Set a default testing mode setting (0 = OFF, non-NULL = ON): -CONFIG_SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 -#CONFIG_SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=1 +## : Enable extra verbose logging messages for debugging: +#CONFIG_SETTINGS += -DDESFIRE_DEBUGGING=1 ## : Feature: Use randomized UIDs that mask the actual secret UID until ## : the tag has been issued a successful authentication sequence: