From 2a42b31b49f538be581cc49ce9ff08b25712d096 Mon Sep 17 00:00:00 2001 From: "Maxie D. Schmidt" Date: Sat, 23 Jul 2022 00:12:24 -0400 Subject: [PATCH 01/12] Update DESFireSupportReadme.md --- Doc/DESFireSupportReadme.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Doc/DESFireSupportReadme.md b/Doc/DESFireSupportReadme.md index d8a561df..46470f3a 100644 --- a/Doc/DESFireSupportReadme.md +++ b/Doc/DESFireSupportReadme.md @@ -209,6 +209,24 @@ fingerprint the DESFire tag subtype in the return NTAG413DNA; return DESFIRE_UNKNOWN; ``` +Table 2 in section 2.1 of [NXP AN10833](https://www.nxp.com/docs/en/application-note/AN10833.pdf) (page 5) lists +standard Mifare tag identifications for several tags. This byte is represented by setting +``Picc.HwType`` using the Chameleon terminal command ``DF_SETHDR=HwType xx``. The default setting for the +Chameleon DESFire tags is ``0x01`` (*MIFARE DESFire*). The table in the application note is reproduced +below for reference. The NXP documentation says: "*The upper nibble [X] defines if the +device is a native MIFARE IC (``0x0``), an implementation (``0x8``), an applet on a Java Card +(``0x9``) or MIFARE 2GO (``0xA``).*" + +| Second Byte of GetVersion Response (``Picc.HwType``) | NXP Type Tag | +| :---: | :-- | +| ``0xX1`` | *MIFARE DESFire* | +| ``0xX2`` | *MIFARE Plus* | +| ``0xX3`` | *MIFARE Ultralight* | +| ``0xX4`` | *NTAG* | +| ``0xX5`` | *RFU* | +| ``0xX6`` | *RFU* | +| ``0xX7`` | *NTAG I2C* | +| ``0xX8`` | *MIFARE DESFire Light* | #### DF_COMM_MODE -- Manually sets the communication mode of the current session From 15be871bb2339f1e6ce43023bace3f6286c5a1a5 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sat, 23 Jul 2022 00:16:22 -0400 Subject: [PATCH 02/12] Restore point for changes to the CL1/CL2 exchanges in the anticollision for DF ISO14443A-4 support --- .../DESFire/DESFireChameleonTerminal.c | 5 +- .../DESFire/DESFireISO14443Support.c | 198 ++++++++++-------- .../DESFire/DESFireISO14443Support.h | 36 +++- .../DESFire/DESFireISO7816Support.c | 7 + .../DESFire/DESFireISO7816Support.h | 11 +- .../Application/DESFire/DESFirePICCControl.c | 39 +++- .../DESFire/DESFirePICCHeaderLayout.h | 11 +- .../Chameleon-Mini/Application/ISO14443-3A.c | 41 ++-- .../Chameleon-Mini/Application/ISO14443-3A.h | 5 +- 9 files changed, 214 insertions(+), 139 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c index 2b337640..c8db3727 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c @@ -68,8 +68,9 @@ CommandStatusIdType CommandDESFireSetHeaderProperty(char *OutParam, const char * if (dataByteCount != 2) { StatusError = 1; } else { - DesfireATQAValue = ((propSpecBytes[0] << 8) & 0xFF00) | (propSpecBytes[1] & 0x00FF); - memcpy(&Picc.ATSBytes[0], propSpecBytes, dataByteCount); + Picc.ATQA[0] = propSpecBytes[0]; + Picc.ATQA[1] = propSpecBytes[1]; + DesfireATQAReset = true; } } else if (!strcasecmp_P(hdrPropSpecStr, PSTR("ManuID"))) { if (dataByteCount != 1) { diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c index 88c8886d..ca4fbe06 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c @@ -79,6 +79,16 @@ void ISO144434Reset(void) { ISO14443ALastIncomingDataFrame[0] = 0x00; } +static uint16_t GetNAKCommandData(uint8_t *Buffer, bool ResetToHaltState); +static uint16_t GetNAKCommandData(uint8_t *Buffer, bool ResetToHaltState) { + if (ResetToHaltState) { + ISO144433AHalt(); + StateRetryCount = 0; + } + Buffer[0] = ISO14443A_NAK; + return ASBITS(1); +} + uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t BitCount) { uint8_t PCB = Buffer[0]; @@ -87,19 +97,21 @@ uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t Bit uint8_t HaveCID = 0, HaveNAD = 0; /* Verify the block's length: at the very least PCB + CRCA */ - if (ByteCount < (1 + ISO14443A_CRCA_SIZE)) { - /* Broken frame -- Respond error by returning an empty frame */ - DEBUG_PRINT_P(PSTR("ISO14443-4: length fail")); - return ISO14443A_APP_NO_RESPONSE; + if (ByteCount < 1 + ISO14443A_CRCA_SIZE) { + /* Broken frame -- Respond with error by returning an empty frame */ + //return ISO14443A_APP_NO_RESPONSE; + } else { + ByteCount -= 2; } - ByteCount -= 2; /* Verify the checksum; fail if doesn't match */ - if (!ISO14443ACheckCRCA(Buffer, ByteCount)) { + if (ByteCount >= 1 + ISO14443A_CRCA_SIZE && !ISO14443ACheckCRCA(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")); - return ISO14443A_APP_NO_RESPONSE; + DEBUG_PRINT_P(PSTR("ISO14443-4: CRC fail")); + /* Invalid data received -- Respond with NAK */ + return GetNAKCommandData(Buffer, false); + //return ISO14443A_APP_NO_RESPONSE; } switch (Iso144434State) { @@ -108,14 +120,14 @@ uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t Bit /* See: ISO/IEC 14443-4, clause 5.6.1.2 */ if (Buffer[0] != ISO14443A_CMD_RATS) { /* Ignore blocks other than RATS and HLTA */ - DEBUG_PRINT_P(PSTR("ISO14443-4: NOT RATS")); - return ISO14443A_APP_NO_RESPONSE; + DEBUG_PRINT_P(PSTR("ISO14443-4: NOT-RATS")); + return GetNAKCommandData(Buffer, false); + //return ISO14443A_APP_NO_RESPONSE; } /* Process RATS. * 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); @@ -142,13 +154,15 @@ uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t Bit if ((Buffer[1] & 0xF) != Iso144434CardID) { /* Different card ID -- the frame is ignored */ DEBUG_PRINT_P(PSTR("ISO14443-4: NEW CARD ID %02d"), Iso144434CardID); - return ISO14443A_APP_NO_RESPONSE; + return GetNAKCommandData(Buffer, false); + //return ISO14443A_APP_NO_RESPONSE; } } break; } case ISO14443_4_STATE_LAST: { - return ISO14443A_APP_NO_RESPONSE; + return GetNAKCommandData(Buffer, false); + //return ISO14443A_APP_NO_RESPONSE; } default: break; @@ -168,7 +182,8 @@ uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t Bit if (PCB & ISO14443_PCB_I_BLOCK_CHAINING_MASK) { /* Currently not supported -- the frame is ignored */ DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_I_BLOCK")); - return ISO14443A_APP_NO_RESPONSE; + return GetNAKCommandData(Buffer, false); + //return ISO14443A_APP_NO_RESPONSE; } /* Build the prologue for the response */ @@ -183,8 +198,8 @@ uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t Bit ByteCount = MifareDesfireProcessCommand(&Buffer[PrologueLength], ByteCount - PrologueLength); /* Short-circuit in case the app decides not to respond at all */ if (ByteCount == 0) { - DEBUG_PRINT_P(PSTR("ISO14443-4: APP_NO_RESP")); - return ISO14443A_APP_NO_RESPONSE; + return GetNAKCommandData(Buffer, false); + //return ISO14443A_APP_NO_RESPONSE; } ByteCount += PrologueLength; DEBUG_PRINT_P(PSTR("ISO14443-4: I-BLK")); @@ -195,7 +210,8 @@ uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t Bit /* 7.5.4.3, rule 11 */ if ((PCB & ISO14443_PCB_BLOCK_NUMBER_MASK) == MyBlockNumber) { DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_R_BLOCK")); - return ISO14443A_APP_NO_RESPONSE; + return GetNAKCommandData(Buffer, false); + //return ISO14443A_APP_NO_RESPONSE; } if (PCB & ISO14443_PCB_R_BLOCK_ACKNAK_MASK) { /* 7.5.4.3, rule 12 */ @@ -212,7 +228,8 @@ uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t Bit memcpy(&Buffer[0], &ISO14443ALastIncomingDataFrame[0], ASBYTES(ISO14443ALastIncomingDataFrameBits)); return ISO14443ALastIncomingDataFrameBits; } else { - return ISO14443A_APP_NO_RESPONSE; + return GetNAKCommandData(Buffer, false); + //return ISO14443A_APP_NO_RESPONSE; } } DEBUG_PRINT_P(PSTR("ISO14443-4: R-BLK")); @@ -231,8 +248,9 @@ uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t Bit DEBUG_PRINT_P(PSTR("ISO14443-4: S-BLK")); return GetAndSetBufferCRCA(Buffer, ByteCount); } - DEBUG_PRINT_P(PSTR("ISO14443-4: PCB_S_BLK NO_RESP")); - return ISO14443A_APP_NO_RESPONSE; + DEBUG_PRINT_P(PSTR("ISO14443-4: PCB_S_BLK NAK")); + return GetNAKCommandData(Buffer, false); + //return ISO14443A_APP_NO_RESPONSE; } default: @@ -241,7 +259,8 @@ uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t Bit } /* Fall through: */ - return ISO14443A_APP_NO_RESPONSE; + return GetNAKCommandData(Buffer, false); + //return ISO14443A_APP_NO_RESPONSE; } @@ -280,9 +299,8 @@ void ISO144433AReset(void) { } void ISO144433AHalt(void) { - ISO144433ASwitchState(ISO14443_3A_STATE_HALT); - Iso144433AIdleState = ISO14443_3A_STATE_HALT; ISO144433AReset(); + ISO144433ASwitchState(ISO14443_3A_STATE_HALT); } bool ISO144433AIsHalt(const uint8_t *Buffer, uint16_t BitCount) { @@ -291,6 +309,17 @@ bool ISO144433AIsHalt(const uint8_t *Buffer, uint16_t BitCount) { Buffer[1] == 0x00 && ISO14443ACheckCRCA(Buffer, ASBYTES(ISO14443A_HLTA_FRAME_SIZE)); } +static uint16_t GetHLTACommandData(uint8_t *Buffer, bool ResetToHaltState); +static uint16_t GetHLTACommandData(uint8_t *Buffer, bool ResetToHaltState) { + if (ResetToHaltState) { + ISO144433AHalt(); + StateRetryCount = 0; + } + Buffer[0] == ISO14443A_CMD_HLTA; + Buffer[1] == 0x00; + ISO14443AAppendCRCA(Buffer, ASBYTES(ISO14443A_HLTA_FRAME_SIZE)); + return ISO14443A_HLTA_FRAME_SIZE + ASBITS(ISO14443A_CRCA_SIZE); +} uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { @@ -311,18 +340,30 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { StateRetryCount = 0; } else if (ISO144433AIsHalt(Buffer, BitCount)) { DesfireLogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0); - DEBUG_PRINT_P(PSTR("ISO14443-3: HALTING")); - ISO144433AHalt(); - return ISO14443A_APP_NO_RESPONSE; - } else if (CheckStateRetryCount(false)) { - /* ??? TODO: Is this the correct action ??? */ - DEBUG_PRINT_P(PSTR("ISO14443-3: RESETTING")); - ISO144433AHalt(); - Buffer[0] == ISO14443A_CMD_HLTA; - Buffer[1] == 0x00; - ISO14443AAppendCRCA(Buffer, ASBYTES(ISO14443A_HLTA_FRAME_SIZE)); - return ISO14443A_HLTA_FRAME_SIZE + ASBITS(ISO14443A_CRCA_SIZE); - //return ISO14443A_APP_NO_RESPONSE; + return GetHLTACommandData(Buffer, true); + } else if (IsDeselectCmd(Cmd)) { + return GetHLTACommandData(Buffer, true); + } else if (IsRIDCmd(Cmd)) { + Iso144433AState = ISO14443_3A_STATE_ACTIVE; + StateRetryCount = 0; + /* Response to RID command as specified in section 7.3.10 (page 139) of the + * NXP PN532 Manual (InDeselect command specification): + * https://www.nxp.com/docs/en/user-guide/141520.pdf + */ + uint16_t respDataSize = (uint16_t) sizeof(MIFARE_DESFIRE_TAG_AID); + memcpy(&Buffer[0], MIFARE_DESFIRE_TAG_AID, respDataSize); + /* ??? TODO: Do we append CRCA bytes ??? + * ISO14443AAppendCRCA(Buffer, respDataSize); + * respDataSize += 2; + */ + return ASBITS(respDataSize); + } else if (IsUnsupportedCmd(Cmd)) { + return GetNAKCommandData(Buffer, true); + } else if (CheckStateRetryCount(false)) { /* Increment the state retry count to keep track of when to timeout */ + DEBUG_PRINT_P(PSTR("ISO14443-3: SW-RESET")); + return GetHLTACommandData(Buffer, true); + } else if (BitCount <= BITS_PER_BYTE) { + return ISO144434ProcessBlock(Buffer, ASBYTES(BitCount), BitCount); } /* This implements ISO 14443-3A state machine */ @@ -331,7 +372,7 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { case ISO14443_3A_STATE_HALT: if (!ISO14443ACmdIsWUPA(Cmd)) { - DEBUG_PRINT_P(PSTR("ISO14443-4: HALT -- NOT WUPA")); + DEBUG_PRINT_P(PSTR("ISO14443-4: HLT-NOT-WUPA")); break; } else { ISO144433ASwitchState(ISO14443_3A_STATE_IDLE); @@ -340,93 +381,78 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { case ISO14443_3A_STATE_IDLE: Iso144433AIdleState = Iso144433AState; ISO144433ASwitchState(ISO14443_3A_STATE_READY_CL1); - Buffer[0] = DesfireATQAValue & 0x00FF; - Buffer[1] = (DesfireATQAValue >> 8) & 0x00FF; + /* The LSByte ordering of the ATQA value for ISO14443 tags is + * discussed in section 2.3 of NXP AN10833. + */ + Buffer[0] = Picc.ATQA[1]; + Buffer[1] = Picc.ATQA[0]; return ASBITS(ISO14443A_ATQA_FRAME_SIZE_BYTES); 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 anticollisio: */ + /* Load UID CL1 and perform anticollision: */ ConfigurationUidType Uid; - ApplicationGetUid(Uid); - if (ActiveConfiguration.UidSize >= ISO14443A_UID_SIZE_DOUBLE) { - Uid[0] = ISO14443A_UID0_CT; - } - 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[0], 4, cl1SAKValue) && BitCount > 0) { - //DEBUG_PRINT_P(PSTR("ISO14443-4: Select CL1 NVB START -- OK")); + ApplicationGetUid(&Uid[1]); + Uid[0] = ISO14443A_UID0_CT; + /* NXP AN10927 (section 2, figure 1, page 3) shows the expected + * data flow to exchange the 7-byte UID for DESFire tags: + * http://www.nxp.com/docs/en/application-note/AN10927.pdf + */ + uint8_t cl1SAKValue = SAK_CL1_VALUE; + if (Buffer[1] == ISO14443A_NVB_AC_START && ISO14443ASelectDesfire(&Buffer[0], 0, &BitCount, &Uid[0], 4, cl1SAKValue)) { ISO144433ASwitchState(ISO14443_3A_STATE_READY_CL1_NVB_END); return BitCount; - } else if (Buffer[1] == ISO14443A_NVB_AC_END && ISO14443ASelectDesfire(Buffer, &BitCount, &Uid[0], 4, cl1SAKValue)) { - //DEBUG_PRINT_P(PSTR("ISO14443-4: Select CL1 NVB END -- OK")); + } else if (Buffer[1] == ISO14443A_NVB_AC_END && ISO14443ASelectDesfire(&Buffer[0], 0, &BitCount, &Uid[0], 4, cl1SAKValue)) { ISO144433ASwitchState(ISO14443_3A_STATE_READY_CL2); return BitCount; } else { - DEBUG_PRINT_P(PSTR("ISO14443-4: Select CL1 NOT OK")); + DEBUG_PRINT_P(PSTR("ISO14443-4: Select CL1-NOT-OK")); } } else { - DEBUG_PRINT_P(PSTR("ISO14443-4: RDY1 -- NOT SLCT CMD")); + DEBUG_PRINT_P(PSTR("ISO14443-4: RDY1 -- NOT-SLCT-CMD")); } CheckStateRetryCount(false); - return ISO14443A_APP_NO_RESPONSE; + return GetNAKCommandData(Buffer, false); + //return ISO14443A_APP_NO_RESPONSE; 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: */ ConfigurationUidType Uid; - ApplicationGetUid(Uid); - 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], 3, cl2SAKValue) && BitCount > 0) { - //DEBUG_PRINT_P(PSTR("ISO14443-4: Select CL2 NVB START -- OK")); + ApplicationGetUid(&Uid[0]); + uint8_t cl2SAKValue = SAK_CL2_VALUE; + if (Buffer[1] == ISO14443A_NVB_AC_START && ISO14443ASelectDesfire(&Buffer[0], 0, &BitCount, &Uid[4], 4, cl2SAKValue)) { ISO144433ASwitchState(ISO14443_3A_STATE_READY_CL2_NVB_END); return BitCount; - } else if (Buffer[1] == ISO14443A_NVB_AC_END && ISO14443ASelectDesfire(Buffer, &BitCount, &Uid[4], 3, cl2SAKValue)) { - //DEBUG_PRINT_P(PSTR("ISO14443-4: Select CL2 NVB END -- OK")); + } else if (Buffer[1] == ISO14443A_NVB_AC_END && ISO14443ASelectDesfire(&Buffer[0], 0, &BitCount, &Uid[4], 4, cl2SAKValue)) { ISO144433ASwitchState(ISO14443_3A_STATE_ACTIVE); return BitCount; } else { - DEBUG_PRINT_P(PSTR("ISO14443-4: Select CL2 NOT OK")); + DEBUG_PRINT_P(PSTR("ISO14443-4: Select CL2-NOT-OK")); } } else { - DEBUG_PRINT_P(PSTR("ISO14443-4: RDY2 -- NOT SLCT CMD")); + DEBUG_PRINT_P(PSTR("ISO14443-4: RDY2 -- NOT-SLCT-CMD")); } CheckStateRetryCount(false); - return ISO14443A_APP_NO_RESPONSE; + return GetNAKCommandData(Buffer, false); + //return ISO14443A_APP_NO_RESPONSE; case ISO14443_3A_STATE_ACTIVE: StateRetryCount = MAX_STATE_RETRY_COUNT; - if (ISO144433AIsHalt(Buffer, BitCount)) { - /* Recognise the HLTA command: */ - DesfireLogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0); - ISO144433AHalt(); - return ISO14443A_APP_NO_RESPONSE; - } else if (Cmd == ISO14443A_CMD_RATS) { - //DEBUG_PRINT_P(PSTR("ISO14443-3/4: Expecting RATS")); + if (Cmd == ISO14443A_CMD_RATS) { ISO144434SwitchState(ISO14443_4_STATE_EXPECT_RATS); } else if (Cmd == ISO14443A_CMD_SELECT_CL3) { - /* DESFire UID size is of insufficient size to support this: */ + /* DESFire UID size is of insufficient size to support this request: */ Buffer[0] = ISO14443A_SAK_COMPLETE_NOT_COMPLIANT; ISO14443AAppendCRCA(&Buffer[0], 1); return ISO14443A_SAK_FRAME_SIZE; - } else if (Cmd == ISO14443A_CMD_DESELECT) { - /* This has been observed to happen at this stage when swiping the - * Chameleon running CONFIG=MF_DESFIRE on an ACR122 USB external reader. - * ??? TODO: What are we supposed to return in this case ??? - */ - DesfireLogEntry(LOG_INFO_APP_CMD_DESELECT, NULL, 0); - //return ISO14443A_APP_NO_RESPONSE; - return BitCount; } - /* 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); + /* Forward to ISO/IEC 14443-4 block processing code */ + uint16_t ReturnBits = ISO144434ProcessBlock(Buffer, ASBYTES(BitCount), BitCount); return ReturnBits; default: @@ -436,12 +462,10 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { /* Fallthrough: Unknown command. Reset back to idle/halt state. */ if (!CheckStateRetryCount(false)) { - 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; + DEBUG_PRINT_P(PSTR("ISO14443-3: RST-TO-IDLE 0x%02x"), Cmd); } + return GetNAKCommandData(Buffer, false); + //return ISO14443A_APP_NO_RESPONSE; } diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h index 5f390910..4f926e8a 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h @@ -29,6 +29,7 @@ This notice must be retained at the top of all source files where indicated. #include "DESFireFirmwareSettings.h" #include "DESFireUtils.h" +#include "DESFireISO7816Support.h" #include "../ISO14443-3A.h" @@ -40,15 +41,40 @@ This notice must be retained at the top of all source files where indicated. * CRC-16 */ +/* Refer to Table 10 in section 9.3 (page 15) of the NXP Mifare Classic EV1 1K data sheet: + * https://www/nxp.com/docs/en/data-sheet/MF1S50YYX_V1.pdf + */ +#define ISO14443A_ACK 0xA0 +#define ISO14443A_NAK 0x00 // 0x04 + +/* See Table 13 in section 7.1 (page 67) of the NXP PN532 User Manual (error Handling / status codes): + * https://www.nxp.com/docs/en/user-guide/141520.pdf + */ +#define ISO14443A_CRCA_ERROR 0x02 +#define ISO14443A_CRC_FRAME_SIZE ASBITS(ISO14443A_CRCA_SIZE) + #define ISO14443A_CMD_RATS 0xE0 #define ISO14443A_RATS_FRAME_SIZE ASBITS(6) -#define ISO14443A_CMD_RNAK 0xB2 -#define ISO14443A_CRC_FRAME_SIZE ASBITS(ISO14443A_CRCA_SIZE) -#define ISO14443A_CMD_DESELECT 0xC2 + +#define NXP_PN532_CMD_INDESELECT 0x44 +#define IsDeselectCmd(cmdCode) (cmdCode == NXP_PN532_CMD_INDESELECT) #define ISO14443A_DESELECT_FRAME_SIZE (ISO14443A_HLTA_FRAME_SIZE + ASBITS(ISO14443A_CRCA_SIZE)) -#define ISO14443ACmdIsPM3WUPA(cmd) ((cmd & 0x54) == 0x54) -#define ISO14443ACmdIsWUPA(cmd) ((cmd == ISO14443A_CMD_WUPA) || ISO14443ACmdIsPM3WUPA(cmd)) +#define NXP_PN532_INSELECT_CMD 0x54 +#define ISO14443ACmdIsPM3WUPA(cmdCode) (cmdCode == NXP_PN532_INSELECT_CMD) +#define ISO14443ACmdIsWUPA(cmdCode) ((cmdCode == ISO14443A_CMD_WUPA) || ISO14443ACmdIsPM3WUPA(cmdCode)) + +#define IsRIDCmd(cmdCode) (cmdCode == ISO7816_RID_CMD) + +/* A quick way to catch and handle the bytes the Hid Omnikey 5022CL and ACR-122 USB readers + * will throw out to identify NFC tags in a promiscuous blanket enumeration of possibilities + * while running 'pcsc_spy -v'. The strategy is to respond with a NAK and continue to ignore + * these incoming commands. + */ +#define MIFARE_RESTORE_CMD 0xC2 +#define NFCTAG_TYPE12_TERMINATOR_TLV 0xFE +#define NXP_PN532_CMD_TGGETINITIATOR 0x88 +#define IsUnsupportedCmd(cmdCode) ((cmdCode == MIFARE_RESTORE_CMD) || (cmdCode == NFCTAG_TYPE12_TERMINATOR_TLV) || (cmdCode == NXP_PN532_CMD_TGGETINITIATOR)) #define ISO14443_PCB_BLOCK_TYPE_MASK 0xC0 #define ISO14443_PCB_I_BLOCK 0x00 diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c index b3a196e9..4a61ed6c 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c @@ -29,6 +29,13 @@ This notice must be retained at the top of all source files where indicated. #include "DESFireStatusCodes.h" #include "../ISO14443-3A.h" +/* Data for the NDEF Tag Application / Mifare DESFire Tag Application in the table: + * https://www.eftlab.com/knowledge-base/211-emv-aid-rid-pix/ + */ +const uint8_t MIFARE_DESFIRE_TAG_AID[9] = { + 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x00 +}; + Iso7816WrappedParams_t Iso7816P1Data = ISO7816_NO_DATA; Iso7816WrappedParams_t Iso7816P2Data = ISO7816_NO_DATA; bool Iso7816FileSelected = false; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h index 9fe78979..cb62cd6e 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h @@ -27,8 +27,12 @@ This notice must be retained at the top of all source files where indicated. #include #include -#define Iso7816CLA(cmdCode) \ - (cmdCode == DESFIRE_ISO7816_CLA) +#define Iso7816CLA(cmdCode) (cmdCode == DESFIRE_ISO7816_CLA) + +#define ISO7816_RID_CMD 0x78 +#define IsRIDCmd(cmdCode) (cmdCode == ISO7816_RID_CMD) + +extern const uint8_t MIFARE_DESFIRE_TAG_AID[9]; #define ISO7816_PROLOGUE_SIZE (2) #define ISO7816_STATUS_RESPONSE_SIZE (0x02) @@ -56,8 +60,7 @@ This notice must be retained at the top of all source files where indicated. #define ISO7816_ERROR_SW2_WRONG_FSPARAMS (0x00) #define ISO7816_ERROR_SW2_EOF (0x82) -#define AppendSW12Bytes(sw1, sw2) \ - ((uint16_t) ((sw1 << 8) | (sw2 & 0xff))) +#define AppendSW12Bytes(sw1, sw2) ((uint16_t) ((sw1 << 8) | (sw2 & 0xff))) /* Some of the wrapped ISO7816 commands have extra meaning * packed into the P1-P2 bytes of the APDU byte array. diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c index 3d55dd84..fabd1ab9 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c @@ -59,7 +59,7 @@ 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; +bool DesfireATQAReset = false; void InitBlockSizes(void) { DESFIRE_PICC_INFO_BLOCK_ID = 0; @@ -174,6 +174,7 @@ void InitialisePiccBackendEV0(uint8_t StorageSize, bool formatPICC) { } else { MemoryRestoreDesfireHeaderBytes(false); ReadBlockBytes(&AppDir, DESFIRE_APP_DIR_BLOCK_ID, sizeof(DESFireAppDirType)); + DesfireATQAReset = true; SelectPiccApp(); } } @@ -193,6 +194,7 @@ void InitialisePiccBackendEV1(uint8_t StorageSize, bool formatPICC) { } else { MemoryRestoreDesfireHeaderBytes(false); ReadBlockBytes(&AppDir, DESFIRE_APP_DIR_BLOCK_ID, sizeof(DESFireAppDirType)); + DesfireATQAReset = true; SelectPiccApp(); } } @@ -212,6 +214,7 @@ void InitialisePiccBackendEV2(uint8_t StorageSize, bool formatPICC) { } else { MemoryRestoreDesfireHeaderBytes(false); ReadBlockBytes(&AppDir, DESFIRE_APP_DIR_BLOCK_ID, sizeof(DESFireAppDirType)); + DesfireATQAReset = true; SelectPiccApp(); } @@ -255,13 +258,26 @@ void FormatPicc(void) { memset(&AppDir, 0x00, sizeof(DESFireAppDirType)); memset(&SelectedApp, 0x00, sizeof(SelectedAppCacheType)); /* Set a random new UID */ - 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). + BYTE uidData[DESFIRE_UID_SIZE]; + RandomGetBuffer(uidData, DESFIRE_UID_SIZE); + memcpy(&Picc.Uid[0], uidData, DESFIRE_UID_SIZE); + if (Picc.Uid[0] == ISO14443A_UID0_RANDOM) { + Picc.Uid[0] != 0x30; + } + /* OLD: Conform to NXP Application Note AN10927 about the first + * byte of a randomly generated UID (refer to section 2.1.1). + */ + //Picc.Uid[0] = ISO14443A_UID0_RANDOM; + //uint16_t ATQAValue = DESFIRE_ATQA_RANDOM_UID; + /* NEW: NXP AN10927 (section 2.1.1, page 5) states that a random + * UID (RID) is always limited to 4 bytes. This limitation + * is avoided by just setting the whole buffer to a random + * value whose first byte is not 0x08. */ - Picc.Uid[0] = ISO14443A_UID0_RANDOM; + uint16_t ATQAValue = DESFIRE_ATQA_DEFAULT; + Picc.ATQA[0] = (uint8_t)((ATQAValue >> 8) & 0x00FF); + Picc.ATQA[1] = (uint8_t)(ATQAValue & 0x00FF); + DesfireATQAReset = false; /* Randomize the initial batch number data: */ BYTE batchNumberData[5]; RandomGetBuffer(batchNumberData, 5); @@ -354,11 +370,18 @@ void FactoryFormatPiccEV2(uint8_t StorageSize) { } void GetPiccUid(ConfigurationUidType Uid) { - memcpy(Uid, Picc.Uid, DESFIRE_UID_SIZE + 1); + memcpy(Uid, &Picc.Uid[0], DESFIRE_UID_SIZE); } void SetPiccUid(ConfigurationUidType Uid) { memcpy(&Picc.Uid[0], Uid, DESFIRE_UID_SIZE); + DesfireATQAReset = true; + //if (!DesfireATQAReset) { + // uint16_t ATQAValue = DESFIRE_ATQA_DEFAULT; + // Picc.ATQA[0] = (uint8_t)((ATQAValue >> 8) & 0x00FF); + // Picc.ATQA[1] = (uint8_t)(ATQAValue & 0x00FF); + // DesfireATQAReset = true; + //} SynchronizePICCInfo(); } diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h index 704471f8..ec324b42 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h @@ -48,16 +48,12 @@ This notice must be retained at the top of all source files where indicated. */ /* Anticollision parameters */ -#define DESFIRE_DEFAULT_ATQA_VALUE 0x0344 -extern uint16_t DesfireATQAValue; +#define DESFIRE_ATQA_DEFAULT 0x0344 +#define DESFIRE_ATQA_RANDOM_UID 0x0304 +extern bool DesfireATQAReset; -#ifndef FORCE_SAK_NOT_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) -#endif #define STATUS_FRAME_SIZE (1 * 8) /* Bits */ @@ -138,6 +134,7 @@ typedef struct DESFIRE_FIRMWARE_PACKING DESFIRE_FIRMWARE_ALIGNAT { uint8_t BatchNumber[5] DESFIRE_FIRMWARE_ALIGNAT; uint8_t ProductionWeek; uint8_t ProductionYear; + uint8_t ATQA[2]; uint8_t ATSBytes[5]; /* Dynamic data: changes during the PICC's lifetime */ uint16_t FirstFreeBlock; diff --git a/Firmware/Chameleon-Mini/Application/ISO14443-3A.c b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c index 2df53589..b453dc94 100644 --- a/Firmware/Chameleon-Mini/Application/ISO14443-3A.c +++ b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c @@ -10,25 +10,36 @@ #ifdef CONFIG_MF_DESFIRE_SUPPORT #include "DESFire/DESFireISO14443Support.h" -bool ISO14443ASelectDesfire(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, uint8_t UidByteCount, uint8_t SAKValue) { +bool ISO14443ASelectDesfire(void *Buffer, uint16_t Offset, uint16_t *BitCount, uint8_t *UidCL, uint8_t UidByteCount, uint8_t SAKValue) { + if (BitCount == NULL || ASBYTES(*BitCount) < Offset + 1) { + *BitCount = 0; + return false; + } uint8_t *DataPtr = (uint8_t *) Buffer; uint8_t NVB = DataPtr[1]; + /* According to the NXP Application Note AN10833, bit 6 of the SAK + * (mask of 0x20) indicates whether the PICC is compliant with the + * ISO/IEC14443-4 standard. The Mifare DESFire tags set this bit to one. + * Reference (section 2.2, page 7): + * https://www.nxp.com/docs/en/application-note/AN10833.pdf + */ + SAKValue = MAKE_ISO14443A_4_COMPLIANT(SAKValue); switch (NVB) { case ISO14443A_NVB_AC_START: /* Start of anticollision procedure. * Send whole UID CLn + BCC */ - memcpy(&DataPtr[0], &UidCL[0], UidByteCount); + memcpy(&DataPtr[Offset], &UidCL[0], UidByteCount); DataPtr[ISO14443A_CL_BCC_OFFSET] = ISO14443A_CALC_BCC(DataPtr); *BitCount = ISO14443A_CL_FRAME_SIZE; - return false; + return true; case ISO14443A_NVB_AC_END: /* End of anticollision procedure. * Send SAK CLn if we are selected. */ if (!memcmp(&DataPtr[2], &UidCL[0], UidByteCount)) { - DataPtr[0] = SAKValue; - ISO14443AAppendCRCA(Buffer, 1); + DataPtr[Offset] = SAKValue; + ISO14443AAppendCRCA(Buffer, Offset + 1); *BitCount = ISO14443A_SAK_FRAME_SIZE; return true; } else { @@ -36,24 +47,8 @@ bool ISO14443ASelectDesfire(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, ui *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], UidByteCount); - DataPtr[ISO14443A_CL_BCC_OFFSET] = ISO14443A_CALC_BCC(DataPtr); - *BitCount = ISO14443A_CL_FRAME_SIZE; - return false; - } - } + default: + break; } /* No anticollision supported */ *BitCount = 0; diff --git a/Firmware/Chameleon-Mini/Application/ISO14443-3A.h b/Firmware/Chameleon-Mini/Application/ISO14443-3A.h index dab8fd9d..261ace28 100644 --- a/Firmware/Chameleon-Mini/Application/ISO14443-3A.h +++ b/Firmware/Chameleon-Mini/Application/ISO14443-3A.h @@ -45,8 +45,7 @@ #define CRC_INIT 0x6363 #define CRC_INIT_R 0xC6C6 /* Bit reversed */ -#define ISO14443A_CALC_BCC(ByteBuffer) \ - ( ByteBuffer[0] ^ ByteBuffer[1] ^ ByteBuffer[2] ^ ByteBuffer[3] ) +#define ISO14443A_CALC_BCC(ByteBuffer) (ByteBuffer[0] ^ ByteBuffer[1] ^ ByteBuffer[2] ^ ByteBuffer[3]) uint16_t ISO14443AAppendCRCA(void *Buffer, uint16_t ByteCount); bool ISO14443ACheckCRCA(const void *Buffer, uint16_t ByteCount); @@ -121,7 +120,7 @@ bool ISO14443ASelect(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, uint8_t S } #ifdef CONFIG_MF_DESFIRE_SUPPORT -bool ISO14443ASelectDesfire(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, uint8_t UidByteCount, uint8_t SAKValue); +bool ISO14443ASelectDesfire(void *Buffer, uint16_t Offset, uint16_t *BitCount, uint8_t *UidCL, uint8_t UidByteCount, uint8_t SAKValue); #endif INLINE From 8fe0e66867ca615d33e682380c41fa022fe40635 Mon Sep 17 00:00:00 2001 From: "Maxie D. Schmidt" Date: Mon, 25 Jul 2022 18:40:06 -0400 Subject: [PATCH 03/12] Update DESFireSupportReadme.md --- Doc/DESFireSupportReadme.md | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/Doc/DESFireSupportReadme.md b/Doc/DESFireSupportReadme.md index 46470f3a..0935e6c7 100644 --- a/Doc/DESFireSupportReadme.md +++ b/Doc/DESFireSupportReadme.md @@ -347,23 +347,24 @@ data setdebugmode -2 ```bash [usb] pm3 --> hf mfdes list [=] downloading tracelog data from device -[+] Recorded activity (trace len = 146 bytes) +[+] Recorded activity (trace len = 158 bytes) [=] start = start of start frame end = end of frame. src = source of transfer [=] ISO14443A - all times are in carrier periods (1/13.56MHz) Start | End | Src | Data (! denotes parity error) | CRC | Annotation ------------+------------+-----+-------------------------------------------------------------------------+-----+-------------------- 0 | 992 | Rdr |52 | | WUPA - 2116 | 4484 | Tag |44 03 | | + 2244 | 4612 | Tag |04 03 | | 7040 | 9504 | Rdr |93 20 | | ANTICOLL - 10820 | 16708 | Tag |88 41 92 a0 fb | | - 19328 | 29856 | Rdr |93 70 88 41 92 a0 fb 87 d9 | ok | SELECT_UID - 30916 | 34436 | Tag |24 d8 36 | | - 35840 | 38304 | Rdr |95 20 | | ANTICOLL-2 - 39364 | 45188 | Tag |b2 59 78 41 d2 | | - 47872 | 58336 | Rdr |95 70 b2 59 78 41 d2 13 09 | ok | SELECT_UID-2 - 59844 | 63428 | Tag |20 fc 70 | | - 65152 | 69920 | Rdr |e0 80 31 73 | ok | RATS + 10564 | 16388 | Tag |88 08 49 4d 84 | | + 19072 | 29536 | Rdr |93 70 88 08 49 4d 84 6b 42 | ok | SELECT_UID + 30788 | 34308 | Tag |24 d8 36 | | + 35712 | 38176 | Rdr |95 20 | | ANTICOLL-2 + 39236 | 45124 | Tag |73 49 ee 75 a1 | | + 47744 | 58272 | Rdr |95 70 73 49 ee 75 a1 ff 45 | ok | SELECT_UID-2 + 59332 | 62916 | Tag |20 fc 70 | | + 64640 | 69408 | Rdr |e0 80 31 73 | ok | RATS + 70468 | 74052 | Tag |06 c8 34 | | ``` #### Getting a summary of tag information @@ -380,18 +381,17 @@ DESFire configuration is used: [#] [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 -[#] halt warning. response len: 4 -[#] Halt error -[#] switch_off [=] ---------------------------------- Tag Information ---------------------------------- -[+] UID: B9 38 A2 A0 B5 1A B9 -[+] Batch number: B9 09 58 8B EA +[+] UID: 08 49 4D 73 49 EE 75 +[+] Batch number: D5 D7 EB 88 47 [+] Production date: week 01 / 2005 [=] --- Hardware Information [=] raw: 04010100011A05 [=] Vendor Id: NXP Semiconductors Germany +[#] halt warning. response len: 4 +[#] Halt error [=] Type: 0x01 [=] Subtype: 0x01 [=] Version: 0.1 ( DESFire MF3ICD40 ) @@ -408,6 +408,7 @@ DESFire configuration is used: [=] Protocol: 0x05 ( ISO 14443-3, 14443-4 ) [=] --------------------------------- Card capabilities --------------------------------- +[#] switch_off [#] error DESFIRESendRaw Current configuration/status does not allow the requested command [#] error DESFIRESendRaw Unknown error [#] error DESFIRESendRaw Current configuration/status does not allow the requested command From f9e9018199de471316eef1236b096f22ee92896d Mon Sep 17 00:00:00 2001 From: "Maxie D. Schmidt" Date: Mon, 25 Jul 2022 18:42:50 -0400 Subject: [PATCH 04/12] Update DESFireSupportReadme.md --- Doc/DESFireSupportReadme.md | 91 +++++++------------------------------ 1 file changed, 16 insertions(+), 75 deletions(-) diff --git a/Doc/DESFireSupportReadme.md b/Doc/DESFireSupportReadme.md index 0935e6c7..ffa5e5a6 100644 --- a/Doc/DESFireSupportReadme.md +++ b/Doc/DESFireSupportReadme.md @@ -269,66 +269,6 @@ DF_ENCMODE=AES:CBC ## Supported functionality -### Tables of tested support for active commands - -#### Native DESFire command support (mixed EV0/EV1/EV2 instruction sets) - -| Instruction | Cmd Byte | Description | Testing Status | Implementation Notes | -| :--- | :----: | :----: | :----: | :-- | -| CMD_AUTHENTICATE | 0x0A | Authenticate legacy | :ballot_box_with_check: | | -| CMD_AUTHENTICATE_ISO | 0x1A | ISO / 3DES auth | :ballot_box_with_check: | | -| CMD_AUTHENTICATE_AES | 0xAA | Standard AES auth | :ballot_box_with_check: | | -| CMD_AUTHENTICATE_EV2_FIRST | 0x71 | Newer spec auth variant | :x: | | -| CMD_AUTHENTICATE_EV2_NONFIRST | 0x77 | Newer spec auth variant | :x: | See page 32 of AN12343.pdf | -| CMD_CHANGE_KEY_SETTINGS | 0x54 | | :ballot_box_with_check: | | -| CMD_SET_CONFIGURATION | 0x5C | | :x: | | -| CMD_CHANGE_KEY | 0xC4 | | :ballot_box_with_check: | | -| CMD_GET_KEY_VERSION | 0x64 | | :ballot_box_with_check: | | -| CMD_CREATE_APPLICATION | 0xCA | | :ballot_box_with_check: | | -| CMD_DELETE_APPLICATION | 0xDA | | :ballot_box_with_check: | | -| CMD_GET_APPLICATION_IDS | 0x6A | | :ballot_box_with_check: | | -| CMD_FREE_MEMORY | 0x6E | | :ballot_box_with_check: | | -| CMD_GET_DF_NAMES | 0x6D | | :x: | =Need docs for what this command does! | -| CMD_GET_KEY_SETTINGS | 0x45 | | :ballot_box_with_check: | | -| CMD_SELECT_APPLICATION | 0x5A | | :ballot_box_with_check: | | -| CMD_FORMAT_PICC | 0xFC | | :ballot_box_with_check: | | -| CMD_GET_VERSION | 0x60 | | :ballot_box_with_check: | | -| CMD_GET_CARD_UID | 0x51 | | :ballot_box_with_check: | | -| CMD_GET_FILE_IDS | 0x6F | | :ballot_box_with_check: | | -| CMD_GET_FILE_SETTINGS | 0xF5 | | :ballot_box_with_check: | | -| CMD_CHANGE_FILE_SETTINGS | 0x5F | | :x: | | -| CMD_CREATE_STDDATA_FILE | 0xCD | | :ballot_box_with_check: | | -| CMD_CREATE_BACKUPDATA_FILE | 0xCB | | :ballot_box_with_check: | | -| CMD_CREATE_VALUE_FILE | 0xCC | | :ballot_box_with_check: | | -| CMD_CREATE_LINEAR_RECORD_FILE | 0xC1 | | :wavy_dash: | GetFileSettings still not returning correct data | -| CMD_CREATE_CYCLIC_RECORD_FILE | 0xC0 | | :wavy_dash: | GetFileSettings still not returning correct data | -| CMD_DELETE_FILE | 0xDF | | :ballot_box_with_check: | | -| CMD_GET_ISO_FILE_IDS | 0x61 | | :x: | | -| CMD_READ_DATA | 0xBD | | :ballot_box_with_check: | The data for std/backup files is uninitialized (any bits) until the user sets the data with WriteData | -| CMD_WRITE_DATA | 0x3D | | :ballot_box_with_check: | Only supports write command operations with <= 52 bytes of data at a time. Offset parameters can be used to write lengthier files. | -| CMD_GET_VALUE | 0x6C | | :ballot_box_with_check: | | -| CMD_CREDIT | 0x0C | | :ballot_box_with_check: | | -| CMD_DEBIT | 0xDC | | :ballot_box_with_check: | | -| CMD_LIMITED_CREDIT | 0x1C | | :ballot_box_with_check: | | -| CMD_WRITE_RECORD | 0x3B | | :question: | | -| CMD_READ_RECORDS | 0xBB | | :ballot_box_with_check: :wavy_dash: | | -| CMD_CLEAR_RECORD_FILE | 0xEB | | :question: | | -| CMD_COMMIT_TRANSACTION | 0xC7 | | :ballot_box_with_check: | | -| CMD_ABORT_TRANSACTION | 0xA7 | | :ballot_box_with_check: | | | - -#### ISO7816 command support - -| Instruction | Cmd Byte | Description | Testing Status | Implementation Notes | -| :--- | :----: | :----: | :----: | :-- | -| CMD_ISO7816_SELECT | 0xa4 | A more nuanced ISO7816 version of EF/DF selection. | :wavy_dash: :question: | See the implementation notes [in this spec](https://cardwerk.com/smart-card-standard-iso7816-4-section-6-basic-interindustry-commands/#chap6_11). We only support EF selection with ``P1=00000000|000000010`` and DF(AID) with ``P1=00000100``. | -| CMD_ISO7816_GET_CHALLENGE | 0x84 | | :wavy_dash: :question: | | -| CMD_ISO7816_EXTERNAL_AUTHENTICATE | 0x82 | | :x: | | -| CMD_ISO7816_INTERNAL_AUTHENTICATE | 0x88 | | :x: | | -| CMD_ISO7816_READ_BINARY | 0xb0 | | :wavy_dash: :question: | Needs testing. | -| CMD_ISO7816_UPDATE_BINARY | 0xd6 | | :wavy_dash: :question: | Needs testing. | -| CMD_ISO7816_READ_RECORDS | 0xb2 | | :wavy_dash: :question: | Needs testing. | -| CMD_ISO7816_APPEND_RECORD | 0xe2 | | :wavy_dash: :question: | Especially needs testing for corner case checks. | - ### Proxmark3 (PM3) compatibility and support The next PM3 commands are known to work with the Chameleon DESFire tag emulation (using both the RDV4 and Easy device types). @@ -498,21 +438,6 @@ The DESFire support for the Chameleon Mini is tested with the LibNFC-based sourc [developed in this directory](https://github.com/emsec/ChameleonMini/tree/master/Software/DESFireLibNFCTesting) with [sample dumps and output here](https://github.com/emsec/ChameleonMini/tree/master/Software/DESFireLibNFCTesting/SampleOutputDumps). -### Links to public datasheets and online specs - -The following links are the original online resource links are -archived here for documentation on how this firmware operates: -* [ISO/IEC 7816-4 Standard](http://www.unsads.com/specs/ISO/7816/ISO7816-4.pdf) -* [PublicDESFireEV0DatasheetSpecs -- April2004 (M075031_desfire.pdf)](https://web.archive.org/web/20170201031920/http://neteril.org/files/M075031_desfire.pdf) -* [NXP Application Note AN12343](https://www.nxp.com/docs/en/application-note/AN12343.pdf) -* [TI DESFire EV1 Tag AES Auth Specs (sloa213.pdf)](https://www.ti.com/lit/an/sloa213/sloa213.pdf) -* [NXP Application Note AN10833](https://www.nxp.com/docs/en/application-note/AN10833.pdf) -* My favorite conference submission in grad school is (by far) about this project -- even though I did not present my talk that year. - In rare form, the [presentation slides (tentative; see uploads)](https://archive.org/details/@maxiedschmidt) and the - [accepted manuscript](https://archive.org/download/ftc2021-presentation-slides-with-notes/schmidt-ftc2021-submission.pdf) (published in print form by Springer) - effectively document the scarce details of the DESFire spec and command sets gleaned while working on this project as a conference proceedings article. - Grace Hopper would have approved :) - ## Credits ### Direct funding sources for this project @@ -555,6 +480,22 @@ repositories and code bases: * [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) +### Links to public datasheets and online specs + +The following links are the original online resource links are +archived here for documentation on how this firmware operates: +* [ISO/IEC 7816-4 Standard](http://www.unsads.com/specs/ISO/7816/ISO7816-4.pdf) +* [PublicDESFireEV0DatasheetSpecs -- April2004 (M075031_desfire.pdf)](https://web.archive.org/web/20170201031920/http://neteril.org/files/M075031_desfire.pdf) +* [NXP Application Note AN12343](https://www.nxp.com/docs/en/application-note/AN12343.pdf) +* [TI DESFire EV1 Tag AES Auth Specs (sloa213.pdf)](https://www.ti.com/lit/an/sloa213/sloa213.pdf) +* [NXP Application Note AN10833](https://www.nxp.com/docs/en/application-note/AN10833.pdf) +* My favorite conference submission in grad school is (by far) about this project -- even though I did not present my talk that year. + In rare form, the [presentation slides (tentative; see uploads)](https://archive.org/details/@maxiedschmidt) and the + [accepted manuscript](https://archive.org/download/ftc2021-presentation-slides-with-notes/schmidt-ftc2021-submission.pdf) + (published in print form by Springer) document the scarce details of the DESFire spec and command sets gleaned while working + on this project as a conference proceedings article. + Grace Hopper would have approved :) + ## New development sources of DESFire support for the Chameleon Mini David Oswald has added a [DESFire emulation project](https://github.com/orgs/emsec/projects?type=classic) to organize tasks in From 32277f06e85d2279a0a8d4fe006e8e7c2c33c688 Mon Sep 17 00:00:00 2001 From: "Maxie D. Schmidt" Date: Mon, 25 Jul 2022 19:15:46 -0400 Subject: [PATCH 05/12] Update DESFireSupportReadme.md --- Doc/DESFireSupportReadme.md | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/Doc/DESFireSupportReadme.md b/Doc/DESFireSupportReadme.md index ffa5e5a6..45dd8d51 100644 --- a/Doc/DESFireSupportReadme.md +++ b/Doc/DESFireSupportReadme.md @@ -287,24 +287,23 @@ data setdebugmode -2 ```bash [usb] pm3 --> hf mfdes list [=] downloading tracelog data from device -[+] Recorded activity (trace len = 158 bytes) +[+] Recorded activity (trace len = 146 bytes) [=] start = start of start frame end = end of frame. src = source of transfer [=] ISO14443A - all times are in carrier periods (1/13.56MHz) Start | End | Src | Data (! denotes parity error) | CRC | Annotation ------------+------------+-----+-------------------------------------------------------------------------+-----+-------------------- 0 | 992 | Rdr |52 | | WUPA - 2244 | 4612 | Tag |04 03 | | + 2116 | 4484 | Tag |04 03 | | 7040 | 9504 | Rdr |93 20 | | ANTICOLL - 10564 | 16388 | Tag |88 08 49 4d 84 | | - 19072 | 29536 | Rdr |93 70 88 08 49 4d 84 6b 42 | ok | SELECT_UID - 30788 | 34308 | Tag |24 d8 36 | | - 35712 | 38176 | Rdr |95 20 | | ANTICOLL-2 - 39236 | 45124 | Tag |73 49 ee 75 a1 | | - 47744 | 58272 | Rdr |95 70 73 49 ee 75 a1 ff 45 | ok | SELECT_UID-2 - 59332 | 62916 | Tag |20 fc 70 | | - 64640 | 69408 | Rdr |e0 80 31 73 | ok | RATS - 70468 | 74052 | Tag |06 c8 34 | | + 10580 | 16404 | Tag |88 08 e2 38 5a | | + 19072 | 29600 | Rdr |93 70 88 08 e2 38 5a 95 d5 | ok | SELECT_UID + 30660 | 34180 | Tag |24 d8 36 | | + 35584 | 38048 | Rdr |95 20 | | ANTICOLL-2 + 39124 | 44948 | Tag |f6 12 53 42 f5 | | + 47616 | 58080 | Rdr |95 70 f6 12 53 42 f5 cb 66 | ok | SELECT_UID-2 + 59220 | 62804 | Tag |20 fc 70 | | + 64512 | 69280 | Rdr |e0 80 31 73 | ok | RATS ``` #### Getting a summary of tag information @@ -315,23 +314,30 @@ The tag type reported will also vary depending on which EV0/EV1/EV2 generation o DESFire configuration is used: ```bash [usb] pm3 --> hf mfdes info +[#] BCC2 incorrect, got 0xf5, expected 0x12 +[#] Aborting +[#] Can't select card +[#] switch_off +[!] ⚠️ Can't select card +[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 +[#] halt warning. response len: 4 +[#] Halt error +[#] switch_off [=] ---------------------------------- Tag Information ---------------------------------- -[+] UID: 08 49 4D 73 49 EE 75 -[+] Batch number: D5 D7 EB 88 47 +[+] UID: 08 E2 38 F6 12 53 42 +[+] Batch number: BB 27 CB 35 08 [+] Production date: week 01 / 2005 [=] --- Hardware Information [=] raw: 04010100011A05 [=] Vendor Id: NXP Semiconductors Germany -[#] halt warning. response len: 4 -[#] Halt error [=] Type: 0x01 [=] Subtype: 0x01 [=] Version: 0.1 ( DESFire MF3ICD40 ) @@ -348,7 +354,6 @@ DESFire configuration is used: [=] Protocol: 0x05 ( ISO 14443-3, 14443-4 ) [=] --------------------------------- Card capabilities --------------------------------- -[#] switch_off [#] error DESFIRESendRaw Current configuration/status does not allow the requested command [#] error DESFIRESendRaw Unknown error [#] error DESFIRESendRaw Current configuration/status does not allow the requested command From 63e74f99149e77e11f79818ae08d5b4f732adfeb Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Mon, 25 Jul 2022 19:42:29 -0400 Subject: [PATCH 06/12] Changes to ISO14443A-4 handlers confirmed to work with the ACS ACR-122U external USB reader ; Updated docs and source code --- Doc/DESFireSupportReadme.md | 93 ++++++++++++++++++- .../DESFire/DESFireISO14443Support.c | 73 ++++++++------- .../Application/DESFire/DESFirePICCControl.c | 29 ++---- 3 files changed, 138 insertions(+), 57 deletions(-) diff --git a/Doc/DESFireSupportReadme.md b/Doc/DESFireSupportReadme.md index 45dd8d51..40f1d9cc 100644 --- a/Doc/DESFireSupportReadme.md +++ b/Doc/DESFireSupportReadme.md @@ -434,14 +434,97 @@ DESFire configuration is used: ### Compatibility with external USB readers and LibNFC The DESFire configurations are known to work with the anticollision and RATS handshaking utility ``nfc-anticol`` -from [LibNFC](https://github.com/nfc-tools/libnfc). -The Mifare DESFire commands installed by [LibFreefare](https://github.com/nfc-tools/libfreefare) -have not been tested nor confirmed to work with the Chameleon Mini. -The developers are actively working to ensure compatibility of the Chameleon DESFire emulation with external USB readers used -running ``pcscd`` and ``pcsc_spy``. This support is not yet functional with tests using ACR-122 and HID Omnikey 5022CL readers. +from [LibNFC](https://github.com/nfc-tools/libnfc). The following is the output of this utility using the +ACS ACR-122U reader over USB (with the ``pcscd`` dameon not running): +```bash +$ sudo nfc-anticol -f +NFC reader: ACS / ACR122U PICC Interface opened + +Sent bits: 26 (7 bits) +Received bits: 04 03 +Sent bits: 93 20 +Received bits: 88 08 c7 df 98 +Sent bits: 93 70 88 08 c7 df 98 9c ae +Received bits: 24 d8 36 +Sent bits: 95 20 +Received bits: f1 02 fc 6c 63 +Sent bits: 95 70 f1 02 fc 6c 63 3a 98 +Received bits: 20 fc 70 +Sent bits: e0 50 bc a5 +Received bits: 06 75 00 81 02 80 66 fd +Sent bits: 50 00 57 cd +Received bits: 50 00 57 cd + +Found tag with + UID: 08c7dff102fc6c +ATQA: 0304 + SAK: 20 + ATS: 06 75 00 81 02 80 66 fd +``` The DESFire support for the Chameleon Mini is tested with the LibNFC-based source code [developed in this directory](https://github.com/emsec/ChameleonMini/tree/master/Software/DESFireLibNFCTesting) with [sample dumps and output here](https://github.com/emsec/ChameleonMini/tree/master/Software/DESFireLibNFCTesting/SampleOutputDumps). +The Mifare DESFire commands installed by [LibFreefare](https://github.com/nfc-tools/libfreefare) +do not work with the Chameleon Mini. + +The developers are actively working to ensure compatibility of the Chameleon DESFire emulation with external USB readers used +running ``pcscd`` and ``pcsc_spy``. This support does not work with the HID Omnikey 5022CL reader. +The ACS ACR-122U reader recognizes the Chameleon running the vanilla ``CONFIG=MF_DESFIRE`` over PCSC (driver ``pcscd``) +as shown in the output of the ``pcsc_spy -v`` command: +```bash + sudo pcsc_scan -v +Using reader plug'n play mechanism +Scanning present readers... +Waiting for the first reader...found one +Scanning present readers... +0: ACS ACR122U PICC Interface 00 00 + +Mon Jul 25 19:26:28 2022 + Reader 0: ACS ACR122U PICC Interface 00 00 + Event number: 3 + Card state: Card removed, + +Mon Jul 25 19:26:37 2022 + Reader 0: ACS ACR122U PICC Interface 00 00 + Event number: 4 + Card state: Card inserted, + ATR: 3B 81 80 01 80 80 + +ATR: 3B 81 80 01 80 80 ++ TS = 3B --> Direct Convention ++ T0 = 81, Y(1): 1000, K: 1 (historical bytes) + TD(1) = 80 --> Y(i+1) = 1000, Protocol T = 0 +----- + TD(2) = 01 --> Y(i+1) = 0000, Protocol T = 1 +----- ++ Historical bytes: 80 + Category indicator byte: 80 (compact TLV data object) ++ TCK = 80 (correct checksum) + +Possibly identified card (using /usr/share/pcsc/smartcard_list.txt): +3B 81 80 01 80 80 + RFID - ISO 14443 Type A - NXP DESFire or DESFire EV1 or EV2 + "Reiner LoginCard" (or "OWOK", how they name it) - they have been distributed by a german computer magazine ("Computer BILD") + https://cardlogin.reiner-sct.com/ + Belgium A-kaart (Antwerp citycard) + Oyster card - Transport for London (second-gen "D") + https://en.wikipedia.org/wiki/Oyster_card + Kaba Legic Advant 4k + Sydney Opal card public transport ticket (Transport) + https://www.opal.com.au + TH Köln (University of Applied Sciences Cologne) - Student Identity Card + https://www.th-koeln.de/en/academics/multica_5893.php + German red cross blood donation service + http://www.blutspende-nordost.de/ + Greater Toronto/Hamilton/Ottawa PRESTO contactless fare card + http://en.wikipedia.org/wiki/Presto_card + Electic vehicle charging card of the EMSP EnBW Energie Baden-Württemberg AG, Tarif ADAC e-Charge, Germany + +Mon Jul 25 19:26:37 2022 + Reader 0: ACS ACR122U PICC Interface 00 00 + Event number: 5 + Card state: Card removed, +``` ## Credits diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c index ca4fbe06..3d6485cf 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c @@ -79,6 +79,12 @@ void ISO144434Reset(void) { ISO14443ALastIncomingDataFrame[0] = 0x00; } +static uint16_t GetACKCommandData(uint8_t *Buffer); +static uint16_t GetACKCommandData(uint8_t *Buffer) { + Buffer[0] = ISO14443A_ACK; + return ASBITS(1); +} + static uint16_t GetNAKCommandData(uint8_t *Buffer, bool ResetToHaltState); static uint16_t GetNAKCommandData(uint8_t *Buffer, bool ResetToHaltState) { if (ResetToHaltState) { @@ -124,17 +130,17 @@ uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t Bit return GetNAKCommandData(Buffer, false); //return ISO14443A_APP_NO_RESPONSE; } - /* Process RATS. + /* Process RATS: * 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. */ 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 */ + Buffer[5] = 0x80; /* T1: dummy value for historical bytes */ + ByteCount = 6; ISO144434SwitchState(ISO14443_4_STATE_ACTIVE); - return ASBITS(ByteCount); /* PM3 expects no CRCA bytes */ + return GetAndSetBufferCRCA(Buffer, ByteCount); /* PM3 'hf mfdes list' expects CRCA bytes on the RATS data */ } case ISO14443_4_STATE_ACTIVE: { /* See: ISO/IEC 14443-4; 7.1 Block format */ @@ -341,8 +347,16 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { } else if (ISO144433AIsHalt(Buffer, BitCount)) { DesfireLogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0); return GetHLTACommandData(Buffer, true); + } else if (Cmd == ISO14443A_CMD_RATS) { + ISO144434SwitchState(ISO14443_4_STATE_EXPECT_RATS); + uint16_t ReturnBits = ISO144434ProcessBlock(Buffer, ASBYTES(BitCount), BitCount); + Iso144433AState = ISO14443_3A_STATE_ACTIVE; + StateRetryCount = 0; + return ReturnBits; } else if (IsDeselectCmd(Cmd)) { - return GetHLTACommandData(Buffer, true); + ISO144433AHalt(); + return GetACKCommandData(Buffer); + //return GetHLTACommandData(Buffer, true); } else if (IsRIDCmd(Cmd)) { Iso144433AState = ISO14443_3A_STATE_ACTIVE; StateRetryCount = 0; @@ -352,14 +366,11 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { */ uint16_t respDataSize = (uint16_t) sizeof(MIFARE_DESFIRE_TAG_AID); memcpy(&Buffer[0], MIFARE_DESFIRE_TAG_AID, respDataSize); - /* ??? TODO: Do we append CRCA bytes ??? - * ISO14443AAppendCRCA(Buffer, respDataSize); - * respDataSize += 2; - */ + /* ??? TODO: Do we append CRCA bytes ??? */ return ASBITS(respDataSize); } else if (IsUnsupportedCmd(Cmd)) { return GetNAKCommandData(Buffer, true); - } else if (CheckStateRetryCount(false)) { /* Increment the state retry count to keep track of when to timeout */ + } else if (CheckStateRetryCount(false)) { DEBUG_PRINT_P(PSTR("ISO14443-3: SW-RESET")); return GetHLTACommandData(Buffer, true); } else if (BitCount <= BITS_PER_BYTE) { @@ -382,23 +393,23 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { Iso144433AIdleState = Iso144433AState; ISO144433ASwitchState(ISO14443_3A_STATE_READY_CL1); /* The LSByte ordering of the ATQA value for ISO14443 tags is - * discussed in section 2.3 of NXP AN10833. - */ + * discussed in section 2.3 of NXP AN10833. + */ Buffer[0] = Picc.ATQA[1]; Buffer[1] = Picc.ATQA[0]; return ASBITS(ISO14443A_ATQA_FRAME_SIZE_BYTES); case ISO14443_3A_STATE_READY_CL1: - case ISO14443_3A_STATE_READY_CL1_NVB_END: + case ISO14443_3A_STATE_READY_CL1_NVB_END: { if (Cmd == ISO14443A_CMD_SELECT_CL1) { - /* Load UID CL1 and perform anticollision: */ + /* NXP AN10927 (section 2, figure 1, page 3) shows the expected + * data flow to exchange the 7-byte UID for DESFire tags: + * http://www.nxp.com/docs/en/application-note/AN10927.pdf + */ ConfigurationUidType Uid; ApplicationGetUid(&Uid[1]); Uid[0] = ISO14443A_UID0_CT; - /* NXP AN10927 (section 2, figure 1, page 3) shows the expected - * data flow to exchange the 7-byte UID for DESFire tags: - * http://www.nxp.com/docs/en/application-note/AN10927.pdf - */ + /* Load UID CL1 and perform anticollision: */ uint8_t cl1SAKValue = SAK_CL1_VALUE; if (Buffer[1] == ISO14443A_NVB_AC_START && ISO14443ASelectDesfire(&Buffer[0], 0, &BitCount, &Uid[0], 4, cl1SAKValue)) { ISO144433ASwitchState(ISO14443_3A_STATE_READY_CL1_NVB_END); @@ -406,7 +417,6 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { } else if (Buffer[1] == ISO14443A_NVB_AC_END && ISO14443ASelectDesfire(&Buffer[0], 0, &BitCount, &Uid[0], 4, cl1SAKValue)) { ISO144433ASwitchState(ISO14443_3A_STATE_READY_CL2); return BitCount; - } else { DEBUG_PRINT_P(PSTR("ISO14443-4: Select CL1-NOT-OK")); } @@ -415,19 +425,19 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { } CheckStateRetryCount(false); return GetNAKCommandData(Buffer, false); - //return ISO14443A_APP_NO_RESPONSE; - + //return ISO14443A_APP_NO_RESPONSE; + } case ISO14443_3A_STATE_READY_CL2: - case ISO14443_3A_STATE_READY_CL2_NVB_END: + 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: */ ConfigurationUidType Uid; ApplicationGetUid(&Uid[0]); uint8_t cl2SAKValue = SAK_CL2_VALUE; - if (Buffer[1] == ISO14443A_NVB_AC_START && ISO14443ASelectDesfire(&Buffer[0], 0, &BitCount, &Uid[4], 4, cl2SAKValue)) { + if (Buffer[1] == ISO14443A_NVB_AC_START && ISO14443ASelectDesfire(&Buffer[0], 0, &BitCount, &Uid[3], 4, cl2SAKValue)) { ISO144433ASwitchState(ISO14443_3A_STATE_READY_CL2_NVB_END); return BitCount; - } else if (Buffer[1] == ISO14443A_NVB_AC_END && ISO14443ASelectDesfire(&Buffer[0], 0, &BitCount, &Uid[4], 4, cl2SAKValue)) { + } else if (Buffer[1] == ISO14443A_NVB_AC_END && ISO14443ASelectDesfire(&Buffer[0], 0, &BitCount, &Uid[3], 4, cl2SAKValue)) { ISO144433ASwitchState(ISO14443_3A_STATE_ACTIVE); return BitCount; @@ -439,22 +449,19 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { } CheckStateRetryCount(false); return GetNAKCommandData(Buffer, false); - //return ISO14443A_APP_NO_RESPONSE; - - case ISO14443_3A_STATE_ACTIVE: + //return ISO14443A_APP_NO_RESPONSE; + } + case ISO14443_3A_STATE_ACTIVE: { StateRetryCount = MAX_STATE_RETRY_COUNT; if (Cmd == ISO14443A_CMD_RATS) { ISO144434SwitchState(ISO14443_4_STATE_EXPECT_RATS); } else if (Cmd == ISO14443A_CMD_SELECT_CL3) { /* DESFire UID size is of insufficient size to support this request: */ - Buffer[0] = ISO14443A_SAK_COMPLETE_NOT_COMPLIANT; - ISO14443AAppendCRCA(&Buffer[0], 1); - return ISO14443A_SAK_FRAME_SIZE; + return GetNAKCommandData(Buffer, false); } /* Forward to ISO/IEC 14443-4 block processing code */ - uint16_t ReturnBits = ISO144434ProcessBlock(Buffer, ASBYTES(BitCount), BitCount); - return ReturnBits; - + return ISO144434ProcessBlock(Buffer, ASBYTES(BitCount), BitCount); + } default: break; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c index fabd1ab9..03e37a4d 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c @@ -261,20 +261,11 @@ void FormatPicc(void) { BYTE uidData[DESFIRE_UID_SIZE]; RandomGetBuffer(uidData, DESFIRE_UID_SIZE); memcpy(&Picc.Uid[0], uidData, DESFIRE_UID_SIZE); - if (Picc.Uid[0] == ISO14443A_UID0_RANDOM) { - Picc.Uid[0] != 0x30; - } - /* OLD: Conform to NXP Application Note AN10927 about the first - * byte of a randomly generated UID (refer to section 2.1.1). - */ - //Picc.Uid[0] = ISO14443A_UID0_RANDOM; - //uint16_t ATQAValue = DESFIRE_ATQA_RANDOM_UID; - /* NEW: NXP AN10927 (section 2.1.1, page 5) states that a random - * UID (RID) is always limited to 4 bytes. This limitation - * is avoided by just setting the whole buffer to a random - * value whose first byte is not 0x08. + /* Conform to NXP Application Note AN10927 about the first + * byte of a randomly generated UID (refer to section 2.1.1). */ - uint16_t ATQAValue = DESFIRE_ATQA_DEFAULT; + Picc.Uid[0] = ISO14443A_UID0_RANDOM; + uint16_t ATQAValue = DESFIRE_ATQA_RANDOM_UID; Picc.ATQA[0] = (uint8_t)((ATQAValue >> 8) & 0x00FF); Picc.ATQA[1] = (uint8_t)(ATQAValue & 0x00FF); DesfireATQAReset = false; @@ -376,12 +367,12 @@ void GetPiccUid(ConfigurationUidType Uid) { void SetPiccUid(ConfigurationUidType Uid) { memcpy(&Picc.Uid[0], Uid, DESFIRE_UID_SIZE); DesfireATQAReset = true; - //if (!DesfireATQAReset) { - // uint16_t ATQAValue = DESFIRE_ATQA_DEFAULT; - // Picc.ATQA[0] = (uint8_t)((ATQAValue >> 8) & 0x00FF); - // Picc.ATQA[1] = (uint8_t)(ATQAValue & 0x00FF); - // DesfireATQAReset = true; - //} + if (!DesfireATQAReset) { + uint16_t ATQAValue = DESFIRE_ATQA_DEFAULT; + Picc.ATQA[0] = (uint8_t)((ATQAValue >> 8) & 0x00FF); + Picc.ATQA[1] = (uint8_t)(ATQAValue & 0x00FF); + DesfireATQAReset = true; + } SynchronizePICCInfo(); } From cddb9bdbf8b84be1efab2192c19159639b8368b2 Mon Sep 17 00:00:00 2001 From: "Maxie D. Schmidt" Date: Mon, 25 Jul 2022 19:41:50 -0400 Subject: [PATCH 07/12] Update DESFireSupportReadme.md --- Doc/DESFireSupportReadme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/DESFireSupportReadme.md b/Doc/DESFireSupportReadme.md index 40f1d9cc..e82c8a77 100644 --- a/Doc/DESFireSupportReadme.md +++ b/Doc/DESFireSupportReadme.md @@ -472,7 +472,7 @@ running ``pcscd`` and ``pcsc_spy``. This support does not work with the HID Omni The ACS ACR-122U reader recognizes the Chameleon running the vanilla ``CONFIG=MF_DESFIRE`` over PCSC (driver ``pcscd``) as shown in the output of the ``pcsc_spy -v`` command: ```bash - sudo pcsc_scan -v +$ sudo pcsc_scan -v Using reader plug'n play mechanism Scanning present readers... Waiting for the first reader...found one From 2257c4226272f9936b549129bc6b7e9c994bfe3c Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Mon, 25 Jul 2022 20:31:29 -0400 Subject: [PATCH 08/12] Cleaning up modifications used to test the development code --- .../Application/DESFire/DESFireISO14443Support.c | 11 +++++------ Firmware/Chameleon-Mini/Application/ISO14443-3A.c | 10 +++++----- Firmware/Chameleon-Mini/Application/ISO14443-3A.h | 2 +- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c index 3d6485cf..e5def663 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c @@ -366,8 +366,7 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { */ uint16_t respDataSize = (uint16_t) sizeof(MIFARE_DESFIRE_TAG_AID); memcpy(&Buffer[0], MIFARE_DESFIRE_TAG_AID, respDataSize); - /* ??? TODO: Do we append CRCA bytes ??? */ - return ASBITS(respDataSize); + return GetAndSetBufferCRCA(Buffer, respDataSize); } else if (IsUnsupportedCmd(Cmd)) { return GetNAKCommandData(Buffer, true); } else if (CheckStateRetryCount(false)) { @@ -411,10 +410,10 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { Uid[0] = ISO14443A_UID0_CT; /* Load UID CL1 and perform anticollision: */ uint8_t cl1SAKValue = SAK_CL1_VALUE; - if (Buffer[1] == ISO14443A_NVB_AC_START && ISO14443ASelectDesfire(&Buffer[0], 0, &BitCount, &Uid[0], 4, cl1SAKValue)) { + if (Buffer[1] == ISO14443A_NVB_AC_START && ISO14443ASelectDesfire(&Buffer[0], &BitCount, &Uid[0], 4, cl1SAKValue)) { ISO144433ASwitchState(ISO14443_3A_STATE_READY_CL1_NVB_END); return BitCount; - } else if (Buffer[1] == ISO14443A_NVB_AC_END && ISO14443ASelectDesfire(&Buffer[0], 0, &BitCount, &Uid[0], 4, cl1SAKValue)) { + } else if (Buffer[1] == ISO14443A_NVB_AC_END && ISO14443ASelectDesfire(&Buffer[0], &BitCount, &Uid[0], 4, cl1SAKValue)) { ISO144433ASwitchState(ISO14443_3A_STATE_READY_CL2); return BitCount; } else { @@ -434,10 +433,10 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { ConfigurationUidType Uid; ApplicationGetUid(&Uid[0]); uint8_t cl2SAKValue = SAK_CL2_VALUE; - if (Buffer[1] == ISO14443A_NVB_AC_START && ISO14443ASelectDesfire(&Buffer[0], 0, &BitCount, &Uid[3], 4, cl2SAKValue)) { + if (Buffer[1] == ISO14443A_NVB_AC_START && ISO14443ASelectDesfire(&Buffer[0], &BitCount, &Uid[3], 4, cl2SAKValue)) { ISO144433ASwitchState(ISO14443_3A_STATE_READY_CL2_NVB_END); return BitCount; - } else if (Buffer[1] == ISO14443A_NVB_AC_END && ISO14443ASelectDesfire(&Buffer[0], 0, &BitCount, &Uid[3], 4, cl2SAKValue)) { + } else if (Buffer[1] == ISO14443A_NVB_AC_END && ISO14443ASelectDesfire(&Buffer[0], &BitCount, &Uid[3], 4, cl2SAKValue)) { ISO144433ASwitchState(ISO14443_3A_STATE_ACTIVE); return BitCount; diff --git a/Firmware/Chameleon-Mini/Application/ISO14443-3A.c b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c index b453dc94..54ef7c09 100644 --- a/Firmware/Chameleon-Mini/Application/ISO14443-3A.c +++ b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c @@ -10,8 +10,8 @@ #ifdef CONFIG_MF_DESFIRE_SUPPORT #include "DESFire/DESFireISO14443Support.h" -bool ISO14443ASelectDesfire(void *Buffer, uint16_t Offset, uint16_t *BitCount, uint8_t *UidCL, uint8_t UidByteCount, uint8_t SAKValue) { - if (BitCount == NULL || ASBYTES(*BitCount) < Offset + 1) { +bool ISO14443ASelectDesfire(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, uint8_t UidByteCount, uint8_t SAKValue) { + if (BitCount == NULL || ASBYTES(*BitCount) < 2) { *BitCount = 0; return false; } @@ -29,7 +29,7 @@ bool ISO14443ASelectDesfire(void *Buffer, uint16_t Offset, uint16_t *BitCount, u /* Start of anticollision procedure. * Send whole UID CLn + BCC */ - memcpy(&DataPtr[Offset], &UidCL[0], UidByteCount); + memcpy(&DataPtr[0], &UidCL[0], UidByteCount); DataPtr[ISO14443A_CL_BCC_OFFSET] = ISO14443A_CALC_BCC(DataPtr); *BitCount = ISO14443A_CL_FRAME_SIZE; return true; @@ -38,8 +38,8 @@ bool ISO14443ASelectDesfire(void *Buffer, uint16_t Offset, uint16_t *BitCount, u * Send SAK CLn if we are selected. */ if (!memcmp(&DataPtr[2], &UidCL[0], UidByteCount)) { - DataPtr[Offset] = SAKValue; - ISO14443AAppendCRCA(Buffer, Offset + 1); + DataPtr[0] = SAKValue; + ISO14443AAppendCRCA(Buffer, 1); *BitCount = ISO14443A_SAK_FRAME_SIZE; return true; } else { diff --git a/Firmware/Chameleon-Mini/Application/ISO14443-3A.h b/Firmware/Chameleon-Mini/Application/ISO14443-3A.h index 261ace28..28fe8696 100644 --- a/Firmware/Chameleon-Mini/Application/ISO14443-3A.h +++ b/Firmware/Chameleon-Mini/Application/ISO14443-3A.h @@ -120,7 +120,7 @@ bool ISO14443ASelect(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, uint8_t S } #ifdef CONFIG_MF_DESFIRE_SUPPORT -bool ISO14443ASelectDesfire(void *Buffer, uint16_t Offset, uint16_t *BitCount, uint8_t *UidCL, uint8_t UidByteCount, uint8_t SAKValue); +bool ISO14443ASelectDesfire(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, uint8_t UidByteCount, uint8_t SAKValue); #endif INLINE From 3a91394f12280c0ee80373502182f6bef3e12379 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Mon, 25 Jul 2022 20:39:50 -0400 Subject: [PATCH 09/12] One more small change to resetting the ATQA value automatically depending on whether the UID is known to be randomly generated --- .../Application/DESFire/DESFirePICCControl.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c index 03e37a4d..84934b42 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c @@ -366,12 +366,16 @@ void GetPiccUid(ConfigurationUidType Uid) { void SetPiccUid(ConfigurationUidType Uid) { memcpy(&Picc.Uid[0], Uid, DESFIRE_UID_SIZE); - DesfireATQAReset = true; - if (!DesfireATQAReset) { + if (!DesfireATQAReset && Uid[0] != ISO14443A_UID0_RANDOM) { uint16_t ATQAValue = DESFIRE_ATQA_DEFAULT; Picc.ATQA[0] = (uint8_t)((ATQAValue >> 8) & 0x00FF); Picc.ATQA[1] = (uint8_t)(ATQAValue & 0x00FF); DesfireATQAReset = true; + } else if (!DesfireATQAReset && Uid[0] == ISO14443A_UID0_RANDOM) { + uint16_t ATQAValue = DESFIRE_ATQA_RANDOM_UID; + Picc.ATQA[0] = (uint8_t)((ATQAValue >> 8) & 0x00FF); + Picc.ATQA[1] = (uint8_t)(ATQAValue & 0x00FF); + DesfireATQAReset = false; } SynchronizePICCInfo(); } From eb0d5fd8a771d76a0569e8eb6cada164e5e8331f Mon Sep 17 00:00:00 2001 From: "Maxie D. Schmidt" Date: Tue, 26 Jul 2022 00:02:15 -0400 Subject: [PATCH 10/12] Update DESFireSupportReadme.md --- Doc/DESFireSupportReadme.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/DESFireSupportReadme.md b/Doc/DESFireSupportReadme.md index e82c8a77..26fa845b 100644 --- a/Doc/DESFireSupportReadme.md +++ b/Doc/DESFireSupportReadme.md @@ -573,7 +573,8 @@ repositories and code bases: The following links are the original online resource links are archived here for documentation on how this firmware operates: * [ISO/IEC 7816-4 Standard](http://www.unsads.com/specs/ISO/7816/ISO7816-4.pdf) -* [PublicDESFireEV0DatasheetSpecs -- April2004 (M075031_desfire.pdf)](https://web.archive.org/web/20170201031920/http://neteril.org/files/M075031_desfire.pdf) +* [DESFire Functional specification (MF3ICD81, November 2008)](https://web.archive.org/web/20201115030854/https://marvin.blogreen.org/~romain/nfc/MF3ICD81%20-%20MIFARE%20DESFire%20-%20Functional%20specification%20-%20Rev.%203.5%20-%2028%20November%202008.pdf) +* [DESFire EV0 Datasheet (M075031, April 2004)](https://web.archive.org/web/20170201031920/http://neteril.org/files/M075031_desfire.pdf) * [NXP Application Note AN12343](https://www.nxp.com/docs/en/application-note/AN12343.pdf) * [TI DESFire EV1 Tag AES Auth Specs (sloa213.pdf)](https://www.ti.com/lit/an/sloa213/sloa213.pdf) * [NXP Application Note AN10833](https://www.nxp.com/docs/en/application-note/AN10833.pdf) From 46a3cc8f8dabe42ab798df58b5d61022ea27f8e7 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Tue, 26 Jul 2022 01:40:27 -0400 Subject: [PATCH 11/12] Small changes to the NAK/ACK return size (4 bits versus 1 byte) --- .../DESFire/DESFireISO14443Support.c | 30 +++++++++++++------ .../DESFire/DESFireISO14443Support.h | 5 ++-- .../Application/DESFire/DESFirePICCControl.c | 2 +- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c index e5def663..1bbc701d 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c @@ -73,8 +73,10 @@ void ISO144434SwitchState(Iso144434StateType NewState) { void ISO144434Reset(void) { /* No logging here -- spams the log and slows things way down! */ + ISO144433AReset(); Iso144434State = ISO14443_4_STATE_EXPECT_RATS; Iso144434BlockNumber = 1; + Iso144434CardID = 1; ISO14443ALastIncomingDataFrameBits = 0; ISO14443ALastIncomingDataFrame[0] = 0x00; } @@ -82,7 +84,7 @@ void ISO144434Reset(void) { static uint16_t GetACKCommandData(uint8_t *Buffer); static uint16_t GetACKCommandData(uint8_t *Buffer) { Buffer[0] = ISO14443A_ACK; - return ASBITS(1); + return 4; } static uint16_t GetNAKCommandData(uint8_t *Buffer, bool ResetToHaltState); @@ -92,7 +94,17 @@ static uint16_t GetNAKCommandData(uint8_t *Buffer, bool ResetToHaltState) { StateRetryCount = 0; } Buffer[0] = ISO14443A_NAK; - return ASBITS(1); + return 4; +} + +static uint16_t GetNAKParityErrorCommandData(uint8_t *Buffer, bool ResetToHaltState); +static uint16_t GetNAKParityErrorCommandData(uint8_t *Buffer, bool ResetToHaltState) { + if (ResetToHaltState) { + ISO144433AHalt(); + StateRetryCount = 0; + } + Buffer[0] = ISO14443A_NAK_PARITY_ERROR; + return 4; } uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t BitCount) { @@ -116,7 +128,7 @@ uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t Bit /* ISO/IEC 14443-4, clause 7.5.5. The PICC does not attempt any error recovery. */ DEBUG_PRINT_P(PSTR("ISO14443-4: CRC fail")); /* Invalid data received -- Respond with NAK */ - return GetNAKCommandData(Buffer, false); + return GetNAKParityErrorCommandData(Buffer, false); //return ISO14443A_APP_NO_RESPONSE; } @@ -157,9 +169,9 @@ uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t Bit if (HaveCID) { PrologueLength++; /* Verify the card ID */ - if ((Buffer[1] & 0xF) != Iso144434CardID) { + if (ByteCount > 1 && (Buffer[1] & 0xF) != Iso144434CardID) { /* Different card ID -- the frame is ignored */ - DEBUG_PRINT_P(PSTR("ISO14443-4: NEW CARD ID %02d"), Iso144434CardID); + DEBUG_PRINT_P(PSTR("ISO14443-4: NEW-CARD-ID %02x != %02x"), (Buffer[1] & 0xF), Iso144434CardID); return GetNAKCommandData(Buffer, false); //return ISO14443A_APP_NO_RESPONSE; } @@ -181,13 +193,13 @@ uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t Bit if (HaveNAD) { PrologueLength++; /* Not currently supported -- the frame is ignored */ - DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_I_BLOCK")); + DEBUG_PRINT_P(PSTR("ISO144434-4: 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")); + DEBUG_PRINT_P(PSTR("ISO14443-4: ISO14443_PCB_I_BLOCK")); return GetNAKCommandData(Buffer, false); //return ISO14443A_APP_NO_RESPONSE; } @@ -215,7 +227,7 @@ uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t Bit 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")); + DEBUG_PRINT_P(PSTR("ISO144434-4: ISO14443_PCB_R_BLOCK")); return GetNAKCommandData(Buffer, false); //return ISO14443A_APP_NO_RESPONSE; } @@ -228,7 +240,7 @@ uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t Bit } else { /* This is an ACK: */ /* NOTE: Chaining is not supported yet. */ - DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_R_BLOCK")); + DEBUG_PRINT_P(PSTR("ISO144434-4: ISO14443_PCB_R_BLOCK")); // Resend the data from the last frame: if (ISO14443ALastIncomingDataFrameBits > 0) { memcpy(&Buffer[0], &ISO14443ALastIncomingDataFrame[0], ASBYTES(ISO14443ALastIncomingDataFrameBits)); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h index 4f926e8a..a31b49de 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h @@ -44,8 +44,9 @@ This notice must be retained at the top of all source files where indicated. /* Refer to Table 10 in section 9.3 (page 15) of the NXP Mifare Classic EV1 1K data sheet: * https://www/nxp.com/docs/en/data-sheet/MF1S50YYX_V1.pdf */ -#define ISO14443A_ACK 0xA0 -#define ISO14443A_NAK 0x00 // 0x04 +#define ISO14443A_ACK 0xA +#define ISO14443A_NAK 0x0 +#define ISO14443A_NAK_PARITY_ERROR 0x1 /* See Table 13 in section 7.1 (page 67) of the NXP PN532 User Manual (error Handling / status codes): * https://www.nxp.com/docs/en/user-guide/141520.pdf diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c index 84934b42..1082c229 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c @@ -375,9 +375,9 @@ void SetPiccUid(ConfigurationUidType Uid) { uint16_t ATQAValue = DESFIRE_ATQA_RANDOM_UID; Picc.ATQA[0] = (uint8_t)((ATQAValue >> 8) & 0x00FF); Picc.ATQA[1] = (uint8_t)(ATQAValue & 0x00FF); - DesfireATQAReset = false; } SynchronizePICCInfo(); + MemoryStoreDesfireHeaderBytes(); } #endif /* CONFIG_MF_DESFIRE_SUPPORT */ From d5d36fe61d2d36699a724c043a7fe60be5c868d4 Mon Sep 17 00:00:00 2001 From: "Maxie D. Schmidt" Date: Wed, 3 Aug 2022 18:03:28 -0500 Subject: [PATCH 12/12] Update BuilingFirmwareBinariesFromSource.md --- Doc/BuilingFirmwareBinariesFromSource.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/BuilingFirmwareBinariesFromSource.md b/Doc/BuilingFirmwareBinariesFromSource.md index 127082c3..7faedf93 100644 --- a/Doc/BuilingFirmwareBinariesFromSource.md +++ b/Doc/BuilingFirmwareBinariesFromSource.md @@ -61,7 +61,7 @@ The per-build configuration lists are currently as follows: Latest builds supporting ISO14443, ISO1593 and DESFire (non development) are generated automatically on the main Chameleon Mini firmware repository -(see [this listing](https://github.com/emsec/ChameleonMini/actions)). +(see [this listing](https://github.com/emsec/ChameleonMini/actions) and the [active latest firmware builds here](https://github.com/emsec/ChameleonMini/releases)). ### More customized builds