Skip to content

Commit 15be871

Browse files
committed
Restore point for changes to the CL1/CL2 exchanges in the anticollision for DF ISO14443A-4 support
1 parent 2a42b31 commit 15be871

9 files changed

+214
-139
lines changed

Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,9 @@ CommandStatusIdType CommandDESFireSetHeaderProperty(char *OutParam, const char *
6868
if (dataByteCount != 2) {
6969
StatusError = 1;
7070
} else {
71-
DesfireATQAValue = ((propSpecBytes[0] << 8) & 0xFF00) | (propSpecBytes[1] & 0x00FF);
72-
memcpy(&Picc.ATSBytes[0], propSpecBytes, dataByteCount);
71+
Picc.ATQA[0] = propSpecBytes[0];
72+
Picc.ATQA[1] = propSpecBytes[1];
73+
DesfireATQAReset = true;
7374
}
7475
} else if (!strcasecmp_P(hdrPropSpecStr, PSTR("ManuID"))) {
7576
if (dataByteCount != 1) {

Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c

+111-87
Large diffs are not rendered by default.

Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h

+31-5
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ This notice must be retained at the top of all source files where indicated.
2929

3030
#include "DESFireFirmwareSettings.h"
3131
#include "DESFireUtils.h"
32+
#include "DESFireISO7816Support.h"
3233

3334
#include "../ISO14443-3A.h"
3435

@@ -40,15 +41,40 @@ This notice must be retained at the top of all source files where indicated.
4041
* CRC-16
4142
*/
4243

44+
/* Refer to Table 10 in section 9.3 (page 15) of the NXP Mifare Classic EV1 1K data sheet:
45+
* https://www/nxp.com/docs/en/data-sheet/MF1S50YYX_V1.pdf
46+
*/
47+
#define ISO14443A_ACK 0xA0
48+
#define ISO14443A_NAK 0x00 // 0x04
49+
50+
/* See Table 13 in section 7.1 (page 67) of the NXP PN532 User Manual (error Handling / status codes):
51+
* https://www.nxp.com/docs/en/user-guide/141520.pdf
52+
*/
53+
#define ISO14443A_CRCA_ERROR 0x02
54+
#define ISO14443A_CRC_FRAME_SIZE ASBITS(ISO14443A_CRCA_SIZE)
55+
4356
#define ISO14443A_CMD_RATS 0xE0
4457
#define ISO14443A_RATS_FRAME_SIZE ASBITS(6)
45-
#define ISO14443A_CMD_RNAK 0xB2
46-
#define ISO14443A_CRC_FRAME_SIZE ASBITS(ISO14443A_CRCA_SIZE)
47-
#define ISO14443A_CMD_DESELECT 0xC2
58+
59+
#define NXP_PN532_CMD_INDESELECT 0x44
60+
#define IsDeselectCmd(cmdCode) (cmdCode == NXP_PN532_CMD_INDESELECT)
4861
#define ISO14443A_DESELECT_FRAME_SIZE (ISO14443A_HLTA_FRAME_SIZE + ASBITS(ISO14443A_CRCA_SIZE))
4962

50-
#define ISO14443ACmdIsPM3WUPA(cmd) ((cmd & 0x54) == 0x54)
51-
#define ISO14443ACmdIsWUPA(cmd) ((cmd == ISO14443A_CMD_WUPA) || ISO14443ACmdIsPM3WUPA(cmd))
63+
#define NXP_PN532_INSELECT_CMD 0x54
64+
#define ISO14443ACmdIsPM3WUPA(cmdCode) (cmdCode == NXP_PN532_INSELECT_CMD)
65+
#define ISO14443ACmdIsWUPA(cmdCode) ((cmdCode == ISO14443A_CMD_WUPA) || ISO14443ACmdIsPM3WUPA(cmdCode))
66+
67+
#define IsRIDCmd(cmdCode) (cmdCode == ISO7816_RID_CMD)
68+
69+
/* A quick way to catch and handle the bytes the Hid Omnikey 5022CL and ACR-122 USB readers
70+
* will throw out to identify NFC tags in a promiscuous blanket enumeration of possibilities
71+
* while running 'pcsc_spy -v'. The strategy is to respond with a NAK and continue to ignore
72+
* these incoming commands.
73+
*/
74+
#define MIFARE_RESTORE_CMD 0xC2
75+
#define NFCTAG_TYPE12_TERMINATOR_TLV 0xFE
76+
#define NXP_PN532_CMD_TGGETINITIATOR 0x88
77+
#define IsUnsupportedCmd(cmdCode) ((cmdCode == MIFARE_RESTORE_CMD) || (cmdCode == NFCTAG_TYPE12_TERMINATOR_TLV) || (cmdCode == NXP_PN532_CMD_TGGETINITIATOR))
5278

5379
#define ISO14443_PCB_BLOCK_TYPE_MASK 0xC0
5480
#define ISO14443_PCB_I_BLOCK 0x00

Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c

+7
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ This notice must be retained at the top of all source files where indicated.
2929
#include "DESFireStatusCodes.h"
3030
#include "../ISO14443-3A.h"
3131

32+
/* Data for the NDEF Tag Application / Mifare DESFire Tag Application in the table:
33+
* https://www.eftlab.com/knowledge-base/211-emv-aid-rid-pix/
34+
*/
35+
const uint8_t MIFARE_DESFIRE_TAG_AID[9] = {
36+
0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x00
37+
};
38+
3239
Iso7816WrappedParams_t Iso7816P1Data = ISO7816_NO_DATA;
3340
Iso7816WrappedParams_t Iso7816P2Data = ISO7816_NO_DATA;
3441
bool Iso7816FileSelected = false;

Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h

+7-4
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,12 @@ This notice must be retained at the top of all source files where indicated.
2727
#include <inttypes.h>
2828
#include <stdbool.h>
2929

30-
#define Iso7816CLA(cmdCode) \
31-
(cmdCode == DESFIRE_ISO7816_CLA)
30+
#define Iso7816CLA(cmdCode) (cmdCode == DESFIRE_ISO7816_CLA)
31+
32+
#define ISO7816_RID_CMD 0x78
33+
#define IsRIDCmd(cmdCode) (cmdCode == ISO7816_RID_CMD)
34+
35+
extern const uint8_t MIFARE_DESFIRE_TAG_AID[9];
3236

3337
#define ISO7816_PROLOGUE_SIZE (2)
3438
#define ISO7816_STATUS_RESPONSE_SIZE (0x02)
@@ -56,8 +60,7 @@ This notice must be retained at the top of all source files where indicated.
5660
#define ISO7816_ERROR_SW2_WRONG_FSPARAMS (0x00)
5761
#define ISO7816_ERROR_SW2_EOF (0x82)
5862

59-
#define AppendSW12Bytes(sw1, sw2) \
60-
((uint16_t) ((sw1 << 8) | (sw2 & 0xff)))
63+
#define AppendSW12Bytes(sw1, sw2) ((uint16_t) ((sw1 << 8) | (sw2 & 0xff)))
6164

6265
/* Some of the wrapped ISO7816 commands have extra meaning
6366
* packed into the P1-P2 bytes of the APDU byte array.

Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c

+31-8
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ SIZET DESFIRE_INITIAL_FIRST_FREE_BLOCK_ID = 0;
5959
SIZET DESFIRE_FIRST_FREE_BLOCK_ID = 0;
6060
SIZET CardCapacityBlocks = 0;
6161

62-
uint16_t DesfireATQAValue = DESFIRE_DEFAULT_ATQA_VALUE;
62+
bool DesfireATQAReset = false;
6363

6464
void InitBlockSizes(void) {
6565
DESFIRE_PICC_INFO_BLOCK_ID = 0;
@@ -174,6 +174,7 @@ void InitialisePiccBackendEV0(uint8_t StorageSize, bool formatPICC) {
174174
} else {
175175
MemoryRestoreDesfireHeaderBytes(false);
176176
ReadBlockBytes(&AppDir, DESFIRE_APP_DIR_BLOCK_ID, sizeof(DESFireAppDirType));
177+
DesfireATQAReset = true;
177178
SelectPiccApp();
178179
}
179180
}
@@ -193,6 +194,7 @@ void InitialisePiccBackendEV1(uint8_t StorageSize, bool formatPICC) {
193194
} else {
194195
MemoryRestoreDesfireHeaderBytes(false);
195196
ReadBlockBytes(&AppDir, DESFIRE_APP_DIR_BLOCK_ID, sizeof(DESFireAppDirType));
197+
DesfireATQAReset = true;
196198
SelectPiccApp();
197199
}
198200
}
@@ -212,6 +214,7 @@ void InitialisePiccBackendEV2(uint8_t StorageSize, bool formatPICC) {
212214
} else {
213215
MemoryRestoreDesfireHeaderBytes(false);
214216
ReadBlockBytes(&AppDir, DESFIRE_APP_DIR_BLOCK_ID, sizeof(DESFireAppDirType));
217+
DesfireATQAReset = true;
215218
SelectPiccApp();
216219
}
217220

@@ -255,13 +258,26 @@ void FormatPicc(void) {
255258
memset(&AppDir, 0x00, sizeof(DESFireAppDirType));
256259
memset(&SelectedApp, 0x00, sizeof(SelectedAppCacheType));
257260
/* Set a random new UID */
258-
BYTE uidData[DESFIRE_UID_SIZE - 1];
259-
RandomGetBuffer(uidData, DESFIRE_UID_SIZE - 1);
260-
memcpy(&Picc.Uid[1], uidData, DESFIRE_UID_SIZE - 1);
261-
/* Conform to NXP Application Note AN10927 about the first
262-
* byte of a randomly generated UID (refer to section 2.1.1).
261+
BYTE uidData[DESFIRE_UID_SIZE];
262+
RandomGetBuffer(uidData, DESFIRE_UID_SIZE);
263+
memcpy(&Picc.Uid[0], uidData, DESFIRE_UID_SIZE);
264+
if (Picc.Uid[0] == ISO14443A_UID0_RANDOM) {
265+
Picc.Uid[0] != 0x30;
266+
}
267+
/* OLD: Conform to NXP Application Note AN10927 about the first
268+
* byte of a randomly generated UID (refer to section 2.1.1).
269+
*/
270+
//Picc.Uid[0] = ISO14443A_UID0_RANDOM;
271+
//uint16_t ATQAValue = DESFIRE_ATQA_RANDOM_UID;
272+
/* NEW: NXP AN10927 (section 2.1.1, page 5) states that a random
273+
* UID (RID) is always limited to 4 bytes. This limitation
274+
* is avoided by just setting the whole buffer to a random
275+
* value whose first byte is not 0x08.
263276
*/
264-
Picc.Uid[0] = ISO14443A_UID0_RANDOM;
277+
uint16_t ATQAValue = DESFIRE_ATQA_DEFAULT;
278+
Picc.ATQA[0] = (uint8_t)((ATQAValue >> 8) & 0x00FF);
279+
Picc.ATQA[1] = (uint8_t)(ATQAValue & 0x00FF);
280+
DesfireATQAReset = false;
265281
/* Randomize the initial batch number data: */
266282
BYTE batchNumberData[5];
267283
RandomGetBuffer(batchNumberData, 5);
@@ -354,11 +370,18 @@ void FactoryFormatPiccEV2(uint8_t StorageSize) {
354370
}
355371

356372
void GetPiccUid(ConfigurationUidType Uid) {
357-
memcpy(Uid, Picc.Uid, DESFIRE_UID_SIZE + 1);
373+
memcpy(Uid, &Picc.Uid[0], DESFIRE_UID_SIZE);
358374
}
359375

360376
void SetPiccUid(ConfigurationUidType Uid) {
361377
memcpy(&Picc.Uid[0], Uid, DESFIRE_UID_SIZE);
378+
DesfireATQAReset = true;
379+
//if (!DesfireATQAReset) {
380+
// uint16_t ATQAValue = DESFIRE_ATQA_DEFAULT;
381+
// Picc.ATQA[0] = (uint8_t)((ATQAValue >> 8) & 0x00FF);
382+
// Picc.ATQA[1] = (uint8_t)(ATQAValue & 0x00FF);
383+
// DesfireATQAReset = true;
384+
//}
362385
SynchronizePICCInfo();
363386
}
364387

Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h

+4-7
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,12 @@ This notice must be retained at the top of all source files where indicated.
4848
*/
4949

5050
/* Anticollision parameters */
51-
#define DESFIRE_DEFAULT_ATQA_VALUE 0x0344
52-
extern uint16_t DesfireATQAValue;
51+
#define DESFIRE_ATQA_DEFAULT 0x0344
52+
#define DESFIRE_ATQA_RANDOM_UID 0x0304
53+
extern bool DesfireATQAReset;
5354

54-
#ifndef FORCE_SAK_NOT_COMPLIANT
55-
#define SAK_CL1_VALUE (ISO14443A_SAK_INCOMPLETE)
56-
#define SAK_CL2_VALUE (ISO14443A_SAK_COMPLETE_COMPLIANT)
57-
#else
5855
#define SAK_CL1_VALUE (ISO14443A_SAK_INCOMPLETE_NOT_COMPLIANT)
5956
#define SAK_CL2_VALUE (ISO14443A_SAK_COMPLETE_NOT_COMPLIANT)
60-
#endif
6157

6258
#define STATUS_FRAME_SIZE (1 * 8) /* Bits */
6359

@@ -138,6 +134,7 @@ typedef struct DESFIRE_FIRMWARE_PACKING DESFIRE_FIRMWARE_ALIGNAT {
138134
uint8_t BatchNumber[5] DESFIRE_FIRMWARE_ALIGNAT;
139135
uint8_t ProductionWeek;
140136
uint8_t ProductionYear;
137+
uint8_t ATQA[2];
141138
uint8_t ATSBytes[5];
142139
/* Dynamic data: changes during the PICC's lifetime */
143140
uint16_t FirstFreeBlock;

Firmware/Chameleon-Mini/Application/ISO14443-3A.c

+18-23
Original file line numberDiff line numberDiff line change
@@ -10,50 +10,45 @@
1010
#ifdef CONFIG_MF_DESFIRE_SUPPORT
1111
#include "DESFire/DESFireISO14443Support.h"
1212

13-
bool ISO14443ASelectDesfire(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, uint8_t UidByteCount, uint8_t SAKValue) {
13+
bool ISO14443ASelectDesfire(void *Buffer, uint16_t Offset, uint16_t *BitCount, uint8_t *UidCL, uint8_t UidByteCount, uint8_t SAKValue) {
14+
if (BitCount == NULL || ASBYTES(*BitCount) < Offset + 1) {
15+
*BitCount = 0;
16+
return false;
17+
}
1418
uint8_t *DataPtr = (uint8_t *) Buffer;
1519
uint8_t NVB = DataPtr[1];
20+
/* According to the NXP Application Note AN10833, bit 6 of the SAK
21+
* (mask of 0x20) indicates whether the PICC is compliant with the
22+
* ISO/IEC14443-4 standard. The Mifare DESFire tags set this bit to one.
23+
* Reference (section 2.2, page 7):
24+
* https://www.nxp.com/docs/en/application-note/AN10833.pdf
25+
*/
26+
SAKValue = MAKE_ISO14443A_4_COMPLIANT(SAKValue);
1627
switch (NVB) {
1728
case ISO14443A_NVB_AC_START:
1829
/* Start of anticollision procedure.
1930
* Send whole UID CLn + BCC
2031
*/
21-
memcpy(&DataPtr[0], &UidCL[0], UidByteCount);
32+
memcpy(&DataPtr[Offset], &UidCL[0], UidByteCount);
2233
DataPtr[ISO14443A_CL_BCC_OFFSET] = ISO14443A_CALC_BCC(DataPtr);
2334
*BitCount = ISO14443A_CL_FRAME_SIZE;
24-
return false;
35+
return true;
2536
case ISO14443A_NVB_AC_END:
2637
/* End of anticollision procedure.
2738
* Send SAK CLn if we are selected.
2839
*/
2940
if (!memcmp(&DataPtr[2], &UidCL[0], UidByteCount)) {
30-
DataPtr[0] = SAKValue;
31-
ISO14443AAppendCRCA(Buffer, 1);
41+
DataPtr[Offset] = SAKValue;
42+
ISO14443AAppendCRCA(Buffer, Offset + 1);
3243
*BitCount = ISO14443A_SAK_FRAME_SIZE;
3344
return true;
3445
} else {
3546
/* We have not been selected. Don't send anything. */
3647
*BitCount = 0;
3748
return false;
3849
}
39-
default: {
40-
uint8_t CollisionByteCount = ((NVB >> 4) & 0x0f) - 2;
41-
uint8_t CollisionBitCount = (NVB >> 0) & 0x0f;
42-
uint8_t mask = 0xFF >> (8 - CollisionBitCount);
43-
// Since the UidCL does not contain the BCC, we have to distinguish here
44-
if (
45-
((CollisionByteCount == 5 || (CollisionByteCount == 4 && CollisionBitCount > 0)) && memcmp(UidCL, &DataPtr[2], 4) == 0 && (ISO14443A_CALC_BCC(UidCL) & mask) == (DataPtr[6] & mask))
46-
||
47-
(CollisionByteCount == 4 && CollisionBitCount == 0 && memcmp(UidCL, &DataPtr[2], 4) == 0)
48-
||
49-
(CollisionByteCount < 4 && memcmp(UidCL, &DataPtr[2], CollisionByteCount) == 0 && (UidCL[CollisionByteCount] & mask) == (DataPtr[CollisionByteCount + 2] & mask))
50-
) {
51-
memcpy(&DataPtr[0], &UidCL[0], UidByteCount);
52-
DataPtr[ISO14443A_CL_BCC_OFFSET] = ISO14443A_CALC_BCC(DataPtr);
53-
*BitCount = ISO14443A_CL_FRAME_SIZE;
54-
return false;
55-
}
56-
}
50+
default:
51+
break;
5752
}
5853
/* No anticollision supported */
5954
*BitCount = 0;

Firmware/Chameleon-Mini/Application/ISO14443-3A.h

+2-3
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@
4545
#define CRC_INIT 0x6363
4646
#define CRC_INIT_R 0xC6C6 /* Bit reversed */
4747

48-
#define ISO14443A_CALC_BCC(ByteBuffer) \
49-
( ByteBuffer[0] ^ ByteBuffer[1] ^ ByteBuffer[2] ^ ByteBuffer[3] )
48+
#define ISO14443A_CALC_BCC(ByteBuffer) (ByteBuffer[0] ^ ByteBuffer[1] ^ ByteBuffer[2] ^ ByteBuffer[3])
5049

5150
uint16_t ISO14443AAppendCRCA(void *Buffer, uint16_t ByteCount);
5251
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
121120
}
122121

123122
#ifdef CONFIG_MF_DESFIRE_SUPPORT
124-
bool ISO14443ASelectDesfire(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, uint8_t UidByteCount, uint8_t SAKValue);
123+
bool ISO14443ASelectDesfire(void *Buffer, uint16_t Offset, uint16_t *BitCount, uint8_t *UidCL, uint8_t UidByteCount, uint8_t SAKValue);
125124
#endif
126125

127126
INLINE

0 commit comments

Comments
 (0)