Skip to content

Commit

Permalink
Restore point for changes to the CL1/CL2 exchanges in the anticollisi…
Browse files Browse the repository at this point in the history
…on for DF ISO14443A-4 support
  • Loading branch information
maxieds committed Jul 23, 2022
1 parent 2a42b31 commit 15be871
Show file tree
Hide file tree
Showing 9 changed files with 214 additions and 139 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
198 changes: 111 additions & 87 deletions Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,12 @@ This notice must be retained at the top of all source files where indicated.
#include <inttypes.h>
#include <stdbool.h>

#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)
Expand Down Expand Up @@ -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.
Expand Down
39 changes: 31 additions & 8 deletions Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
}
}
Expand All @@ -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();
}
}
Expand All @@ -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();
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down Expand Up @@ -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;
Expand Down
41 changes: 18 additions & 23 deletions Firmware/Chameleon-Mini/Application/ISO14443-3A.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,50 +10,45 @@
#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 {
/* We have not been selected. Don't send anything. */
*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;
Expand Down
5 changes: 2 additions & 3 deletions Firmware/Chameleon-Mini/Application/ISO14443-3A.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 15be871

Please sign in to comment.