Implement ISO14443-4 block numbers.

This feature was not used by the cards I initially used when coding the
, but is required for (at least some) Mifare DESFire EV1 to work.

IMPORTANT NOTE: The cards needing this block-number management to work out
break-down when mifare_desfire_format_picc() is performed on them.  The ATR
change from 0x7577810280 to 0x757781028f and further communication alway result
in a timeout.  At the time of committing, the reason is still unknown (bogus
cards, missed "Remarks" in the documentation, ...).  Other commands seems to
not expose additional problems.
This commit is contained in:
Romain Tartiere 2010-09-28 16:37:25 +00:00
parent cdac2ea340
commit 91d3ff9cc4
2 changed files with 28 additions and 0 deletions

View file

@ -185,6 +185,7 @@ struct mifare_desfire_tag {
uint8_t authenticated_key_no;
uint8_t *crypto_buffer;
size_t crypto_buffer_size;
uint8_t block_number;
};
MifareDESFireKey mifare_desfire_session_key_new (uint8_t rnda[8], uint8_t rndb[8], MifareDESFireKey authentication_key);

View file

@ -18,6 +18,16 @@
*/
/*
* This implementation was written based on information provided by the
* following documents:
*
* Draft ISO/IEC FCD 14443-4
* Identification cards
* - Contactless integrated circuit(s) cards
* - Proximity cards
* - Part 4: Transmission protocol
* Final Committee Draft - 2000-03-10
*
* http://ridrix.wordpress.com/2009/09/19/mifare-desfire-communication-example/
*/
@ -139,6 +149,20 @@ static ssize_t read_data (MifareTag tag, uint8_t command, uint8_t file_no, off_
uint8_t *buffer_name = &(__##buffer_name[1]); \
size_t __##buffer_name##_n = 0
/*
* Conditionnaly toogles tag->block_number depending on the last received
* block. This is described in section "7.4.4 Block numbering rules" of
* ISO/IEC 14443-4.
*/
#define ISO144443_CHAIN_BLOCK_NUMBER(tag, block) \
do { \
if (((__##res[0] & 0xc0) == 0x00) || (((__##res[0] & 0xa0) == 0xa0) && ((__##res[0] & 0x50) == 0x00))) { \
if (MIFARE_DESFIRE (tag)->block_number == (block & 0x01)) { \
MIFARE_DESFIRE (tag)->block_number ^= 0x01; \
} \
} \
} while (0)
/*
* Transmit the message msg to the NFC tag and receive the response res. The
* response buffer's size is set according to the quantity of data received.
@ -149,11 +173,13 @@ static ssize_t read_data (MifareTag tag, uint8_t command, uint8_t file_no, off_
#define DESFIRE_TRANSCEIVE(tag, msg, res) \
do { \
errno = 0; \
__##msg[0] = 0x02 | (MIFARE_DESFIRE (tag)->block_number & 0x01); \
MIFARE_DESFIRE (tag)->last_picc_error = OPERATION_OK; \
DEBUG_XFER (__##msg, __##msg##_n+1, "===> "); \
if (!(nfc_initiator_transceive_bytes (tag->device, __##msg, __##msg##_n+1, __##res, &__##res##_n))) { \
return errno = EIO, -1; \
} \
ISO144443_CHAIN_BLOCK_NUMBER (tag, __##res[0]); \
DEBUG_XFER (__##res, __##res##_n, "<=== "); \
__##res##_n -= 1; \
while (__##res[0] == 0xf2) { \
@ -282,6 +308,7 @@ mifare_desfire_connect (MifareTag tag)
MIFARE_DESFIRE (tag)->last_picc_error = OPERATION_OK;
MIFARE_DESFIRE (tag)->last_pcd_error = NULL;
MIFARE_DESFIRE (tag)->authenticated_key_no = NOT_YET_AUTHENTICATED;
MIFARE_DESFIRE (tag)->block_number = 0;
} else {
errno = EIO;
return -1;