Merge pull request #17 from nfc-tools/tag-detection

Get some flexibility in the tag type detection
This commit is contained in:
Philippe Teuwen 2016-01-19 23:08:43 +01:00
commit 48c9383ce1
11 changed files with 250 additions and 189 deletions

View file

@ -50,10 +50,27 @@ ssize_t felica_transceive (FreefareTag tag, uint8_t *data_in, uint8_t *data_out,
return res;
}
FreefareTag
felica_tag_new (void)
bool
felica_taste (nfc_device *device, nfc_target target)
{
return malloc (sizeof (struct felica_tag));
(void) device;
return target.nm.nmt == NMT_FELICA;
}
FreefareTag
felica_tag_new (nfc_device *device, nfc_target target)
{
FreefareTag tag;
if ((tag = malloc (sizeof (struct felica_tag)))) {
tag->type = FELICA;
tag->free_tag = felica_tag_free;
tag->device = device;
tag->info = target;
tag->active = 0;
}
return tag;
}
void
@ -67,8 +84,6 @@ felica_tag_free (FreefareTag tag)
ssize_t
felica_read_ex (FreefareTag tag, uint16_t service, uint8_t block_count, uint8_t blocks[], uint8_t *data, size_t length)
{
ASSERT_FELICA (tag);
assert (block_count <= MAX_BLOCK_COUNT);
assert (length == 16 * block_count);
@ -120,8 +135,6 @@ felica_read (FreefareTag tag, uint16_t service, uint8_t block, uint8_t *data, si
ssize_t
felica_write_ex (FreefareTag tag, uint16_t service, uint8_t block_count, uint8_t blocks[], uint8_t *data, size_t length)
{
ASSERT_FELICA (tag);
DEBUG_FUNCTION();
assert (block_count <= MAX_BLOCK_COUNT);

View file

@ -28,86 +28,27 @@
#define NXP_MANUFACTURER_CODE 0x04
struct supported_tag supported_tags[] = {
{ FELICA, "FeliCA", NMT_FELICA, 0x00, 0, 0, { 0x00 }, NULL },
{ MIFARE_CLASSIC_1K, "Mifare Classic 1k", NMT_ISO14443A, 0x08, 0, 0, { 0x00 }, NULL },
{ MIFARE_CLASSIC_1K, "Mifare Classic 1k (Emulated)", NMT_ISO14443A, 0x28, 0, 0, { 0x00 }, NULL },
{ MIFARE_CLASSIC_1K, "Mifare Classic 1k (Emulated)", NMT_ISO14443A, 0x68, 0, 0, { 0x00 }, NULL },
{ MIFARE_CLASSIC_1K, "Infineon Mifare Classic 1k", NMT_ISO14443A, 0x88, 0, 0, { 0x00 }, NULL },
{ MIFARE_CLASSIC_4K, "Mifare Classic 4k", NMT_ISO14443A, 0x18, 0, 0, { 0x00 }, NULL },
{ MIFARE_CLASSIC_4K, "Mifare Classic 4k (Emulated)", NMT_ISO14443A, 0x38, 0, 0, { 0x00 }, NULL },
{ MIFARE_DESFIRE, "Mifare DESFire", NMT_ISO14443A, 0x20, 5, 4, { 0x75, 0x77, 0x81, 0x02 /*, 0xXX */ }, NULL},
{ MIFARE_DESFIRE, "Cyanogenmod card emulation", NMT_ISO14443A, 0x60, 4, 3, { 0x78, 0x33, 0x88 /*, 0xXX */ }, NULL},
{ MIFARE_DESFIRE, "Android HCE", NMT_ISO14443A, 0x60, 4, 3, { 0x78, 0x80, 0x70 /*, 0xXX */ }, NULL},
{ MIFARE_ULTRALIGHT_C, "Mifare UltraLightC", NMT_ISO14443A, 0x00, 0, 0, { 0x00 }, is_mifare_ultralightc_on_reader },
{ MIFARE_ULTRALIGHT, "Mifare UltraLight", NMT_ISO14443A, 0x00, 0, 0, { 0x00 }, NULL },
};
/*
* Automagically allocate a FreefareTag given a device and target info.
*/
FreefareTag
freefare_tag_new (nfc_device *device, nfc_target target)
{
bool found = false;
struct supported_tag *tag_info;
FreefareTag tag;
FreefareTag tag = NULL;
/* Ensure the target is supported */
for (size_t i = 0; i < sizeof (supported_tags) / sizeof (struct supported_tag); i++) {
if (target.nm.nmt != supported_tags[i].modulation_type)
continue;
if (target.nm.nmt == NMT_FELICA) {
tag_info = &(supported_tags[i]);
found = true;
break;
if (felica_taste (device, target)) {
tag = felica_tag_new (device, target);
} else if (mifare_classic1k_taste (device, target)) {
tag = mifare_classic1k_tag_new (device, target);
} else if (mifare_classic4k_taste (device, target)) {
tag = mifare_classic4k_tag_new (device, target);
} else if (mifare_desfire_taste (device, target)) {
tag = mifare_desfire_tag_new (device, target);
} else if (mifare_ultralightc_taste (device, target)) {
tag = mifare_ultralightc_tag_new (device, target);
} else if (mifare_ultralight_taste (device, target)) {
tag = mifare_ultralight_tag_new (device, target);
}
if ((target.nm.nmt == NMT_ISO14443A) && ((target.nti.nai.szUidLen == 4) || (target.nti.nai.abtUid[0] == NXP_MANUFACTURER_CODE)) &&
(target.nti.nai.btSak == supported_tags[i].SAK) &&
(!supported_tags[i].ATS_min_length || ((target.nti.nai.szAtsLen >= supported_tags[i].ATS_min_length) &&
(0 == memcmp (target.nti.nai.abtAts, supported_tags[i].ATS, supported_tags[i].ATS_compare_length)))) &&
((supported_tags[i].check_tag_on_reader == NULL) ||
supported_tags[i].check_tag_on_reader(device, target.nti.nai))) {
tag_info = &(supported_tags[i]);
found = true;
break;
}
}
if (!found)
return NULL;
/* Allocate memory for the found MIFARE target */
switch (tag_info->type) {
case FELICA:
tag = felica_tag_new ();
break;
case MIFARE_CLASSIC_1K:
case MIFARE_CLASSIC_4K:
tag = mifare_classic_tag_new ();
break;
case MIFARE_DESFIRE:
tag = mifare_desfire_tag_new ();
break;
case MIFARE_ULTRALIGHT:
case MIFARE_ULTRALIGHT_C:
tag = mifare_ultralight_tag_new ();
break;
}
if (!tag)
return NULL;
/*
* Initialize common fields
* (Target specific fields are initialized in mifare_*_tag_new())
*/
tag->device = device;
tag->info = target;
tag->active = 0;
tag->tag_info = tag_info;
return tag;
}
@ -202,7 +143,7 @@ freefare_get_tags (nfc_device *device)
enum freefare_tag_type
freefare_get_tag_type (FreefareTag tag)
{
return tag->tag_info->type;
return tag->type;
}
/*
@ -211,7 +152,22 @@ freefare_get_tag_type (FreefareTag tag)
const char *
freefare_get_tag_friendly_name (FreefareTag tag)
{
return tag->tag_info->friendly_name;
switch (tag->type) {
case FELICA:
return "FeliCA";
case MIFARE_CLASSIC_1K:
return "Mifare Classic 1k";
case MIFARE_CLASSIC_4K:
return "Mifare Classic 4k";
case MIFARE_DESFIRE:
return "Mifare DESFire";
case MIFARE_ULTRALIGHT_C:
return "Mifare UltraLightC";
case MIFARE_ULTRALIGHT:
return "Mifare UltraLight";
default:
return "UNKNOWN";
}
}
/*
@ -260,22 +216,7 @@ void
freefare_free_tag (FreefareTag tag)
{
if (tag) {
switch (tag->tag_info->type) {
case FELICA:
felica_tag_free (tag);
break;
case MIFARE_CLASSIC_1K:
case MIFARE_CLASSIC_4K:
mifare_classic_tag_free (tag);
break;
case MIFARE_DESFIRE:
mifare_desfire_tag_free (tag);
break;
case MIFARE_ULTRALIGHT:
case MIFARE_ULTRALIGHT_C:
mifare_ultralight_tag_free (tag);
break;
}
tag->free_tag (tag);
}
}
@ -286,7 +227,7 @@ freefare_strerror (FreefareTag tag)
if (nfc_device_get_last_error (tag->device) < 0) {
p = nfc_strerror (tag->device);
} else {
if (tag->tag_info->type == MIFARE_DESFIRE) {
if (tag->type == MIFARE_DESFIRE) {
if (MIFARE_DESFIRE (tag)->last_pcd_error) {
p = mifare_desfire_error_lookup (MIFARE_DESFIRE (tag)->last_pcd_error);
} else if (MIFARE_DESFIRE (tag)->last_picc_error) {

View file

@ -67,14 +67,30 @@ const char *freefare_strerror (FreefareTag tag);
int freefare_strerror_r (FreefareTag tag, char *buffer, size_t len);
void freefare_perror (FreefareTag tag, const char *string);
bool felica_taste (nfc_device *device, nfc_target target);
#define FELICA_SC_RW 0x0009
#define FELICA_SC_RO 0x000b
FreefareTag felica_tag_new (nfc_device *device, nfc_target target);
void felica_tag_free (FreefareTag tag);
ssize_t felica_read (FreefareTag tag, uint16_t service, uint8_t block, uint8_t *data, size_t length);
ssize_t felica_read_ex (FreefareTag tag, uint16_t service, uint8_t block_count, uint8_t blocks[], uint8_t *data, size_t length);
ssize_t felica_write (FreefareTag tag, uint16_t service, uint8_t block, uint8_t *data, size_t length);
ssize_t felica_write_ex (FreefareTag tag, uint16_t service, uint8_t block_count, uint8_t blocks[], uint8_t *data, size_t length);
bool mifare_ultralight_taste (nfc_device *device, nfc_target target);
bool mifare_ultralightc_taste (nfc_device *device, nfc_target target);
FreefareTag mifare_ultralight_tag_new (nfc_device *device, nfc_target target);
FreefareTag mifare_ultralightc_tag_new (nfc_device *device, nfc_target target);
void mifare_ultralight_tag_free (FreefareTag tag);
void mifare_ultralightc_tag_free (FreefareTag tag);
int mifare_ultralight_connect (FreefareTag tag);
int mifare_ultralight_disconnect (FreefareTag tag);
@ -82,8 +98,18 @@ int mifare_ultralight_read (FreefareTag tag, const MifareUltralightPageNumber
int mifare_ultralight_write (FreefareTag tag, const MifareUltralightPageNumber page, const MifareUltralightPage data);
int mifare_ultralightc_authenticate (FreefareTag tag, const MifareDESFireKey key);
bool is_mifare_ultralight (FreefareTag tag);
bool is_mifare_ultralightc (FreefareTag tag);
bool is_mifare_ultralightc_on_reader (nfc_device *device, nfc_iso14443a_info nai);
bool mifare_classic1k_taste (nfc_device *device, nfc_target target);
bool mifare_classic4k_taste (nfc_device *device, nfc_target target);
FreefareTag mifare_classic1k_tag_new (nfc_device *device, nfc_target target);
FreefareTag mifare_classic4k_tag_new (nfc_device *device, nfc_target target);
void mifare_classic_tag_free (FreefareTag tag);
typedef unsigned char MifareClassicBlock[16];
typedef uint8_t MifareClassicSectorNumber;
@ -185,6 +211,10 @@ int mifare_application_free (Mad mad, const MadAid aid);
MifareClassicSectorNumber *mifare_application_find (Mad mad, const MadAid aid);
bool mifare_desfire_taste (nfc_device *device, nfc_target target);
/* File types */
enum mifare_desfire_file_types {
@ -334,6 +364,9 @@ struct mifare_desfire_file_settings {
} settings;
};
FreefareTag mifare_desfire_tag_new (nfc_device *device, nfc_target target);
void mifare_desfire_tag_free (FreefareTag tags);
int mifare_desfire_connect (FreefareTag tag);
int mifare_desfire_disconnect (FreefareTag tag);

View file

@ -102,14 +102,6 @@ struct mad_sector_0x00;
struct mad_sector_0x10;
void nxp_crc (uint8_t *crc, const uint8_t value);
FreefareTag felica_tag_new (void);
void felica_tag_free (FreefareTag tag);
FreefareTag mifare_classic_tag_new (void);
void mifare_classic_tag_free (FreefareTag tag);
FreefareTag mifare_desfire_tag_new (void);
void mifare_desfire_tag_free (FreefareTag tags);
FreefareTag mifare_ultralight_tag_new (void);
void mifare_ultralight_tag_free (FreefareTag tag);
uint8_t sector_0x00_crc8 (Mad mad);
uint8_t sector_0x10_crc8 (Mad mad);
@ -165,17 +157,6 @@ void *assert_crypto_buffer_size (FreefareTag tag, size_t nbytes);
// Max PAGE_COUNT of the Ultralight Family:
#define MIFARE_ULTRALIGHT_MAX_PAGE_COUNT 0x30
struct supported_tag {
enum freefare_tag_type type;
const char *friendly_name;
uint8_t modulation_type;
uint8_t SAK;
uint8_t ATS_min_length;
uint8_t ATS_compare_length;
uint8_t ATS[5];
bool (*check_tag_on_reader) (nfc_device *, nfc_iso14443a_info);
};
/*
* This structure is common to all supported MIFARE targets but shall not be
* used directly (it's some kind of abstract class). All members in this
@ -187,8 +168,9 @@ struct supported_tag {
struct freefare_tag {
nfc_device *device;
nfc_target info;
const struct supported_tag *tag_info;
int type;
int active;
void (*free_tag) (FreefareTag tag);
};
struct felica_tag {
@ -268,13 +250,6 @@ struct mifare_ultralight_tag {
#define ASSERT_ACTIVE(tag) do { if (!tag->active) return errno = ENXIO, -1; } while (0)
#define ASSERT_INACTIVE(tag) do { if (tag->active) return errno = ENXIO, -1; } while (0)
#define ASSERT_FELICA(tag) do { if (tag->tag_info->type != FELICA) return errno = ENODEV, -1; } while (0)
#define ASSERT_MIFARE_CLASSIC(tag) do { if ((tag->tag_info->type != MIFARE_CLASSIC_1K) && (tag->tag_info->type != MIFARE_CLASSIC_4K)) return errno = ENODEV, -1; } while (0)
#define ASSERT_MIFARE_DESFIRE(tag) do { if (tag->tag_info->type != MIFARE_DESFIRE) return errno = ENODEV, -1; } while (0)
#define IS_MIFARE_ULTRALIGHT_C(tag) (tag->tag_info->type == MIFARE_ULTRALIGHT_C)
#define ASSERT_MIFARE_ULTRALIGHT(tag) do { if ((tag->tag_info->type != MIFARE_ULTRALIGHT) && (! IS_MIFARE_ULTRALIGHT_C(tag))) return errno = ENODEV, -1; } while (0)
#define ASSERT_MIFARE_ULTRALIGHT_C(tag) do { if (! IS_MIFARE_ULTRALIGHT_C(tag)) return errno = ENODEV, -1; } while (0)
/*
* FreefareTag cast macros
*

View file

@ -193,14 +193,60 @@ int get_block_access_bits (FreefareTag tag, const MifareClassicBlockNumber blo
* Memory management functions.
*/
bool
mifare_classic1k_taste (nfc_device *device, nfc_target target)
{
(void) device;
return target.nm.nmt == NMT_ISO14443A &&
(
target.nti.nai.btSak == 0x08 ||
target.nti.nai.btSak == 0x28 ||
target.nti.nai.btSak == 0x68 ||
target.nti.nai.btSak == 0x88
);
}
bool
mifare_classic4k_taste (nfc_device *device, nfc_target target)
{
(void) device;
return target.nm.nmt == NMT_ISO14443A &&
(
target.nti.nai.btSak == 0x18 ||
target.nti.nai.btSak == 0x38
);
}
/*
* Allocates and initialize a MIFARE Classic tag.
*/
FreefareTag
mifare_classic_tag_new (void)
static FreefareTag
_mifare_classic_tag_new (nfc_device *device, nfc_target target, int tag_type)
{
return malloc (sizeof (struct mifare_classic_tag));
FreefareTag tag;
if ((tag = malloc (sizeof (struct mifare_classic_tag)))) {
tag->type = tag_type;
tag->free_tag = mifare_classic_tag_free;
tag->device = device;
tag->info = target;
tag->active = 0;
}
return tag;
}
FreefareTag
mifare_classic1k_tag_new (nfc_device *device, nfc_target target)
{
return _mifare_classic_tag_new (device, target, MIFARE_CLASSIC_1K);
}
FreefareTag
mifare_classic4k_tag_new (nfc_device *device, nfc_target target)
{
return _mifare_classic_tag_new (device, target, MIFARE_CLASSIC_4K);
}
/*
@ -228,7 +274,6 @@ int
mifare_classic_connect (FreefareTag tag)
{
ASSERT_INACTIVE (tag);
ASSERT_MIFARE_CLASSIC (tag);
nfc_target pnti;
nfc_modulation modulation = {
@ -251,7 +296,6 @@ int
mifare_classic_disconnect (FreefareTag tag)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_CLASSIC (tag);
if (nfc_initiator_deselect_target (tag->device) >= 0) {
tag->active = 0;
@ -277,7 +321,6 @@ int
mifare_classic_authenticate (FreefareTag tag, const MifareClassicBlockNumber block, const MifareClassicKey key, const MifareClassicKeyType key_type)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_CLASSIC (tag);
BUFFER_INIT (cmd, 12);
BUFFER_INIT (res, 1);
@ -308,7 +351,6 @@ int
mifare_classic_read (FreefareTag tag, const MifareClassicBlockNumber block, MifareClassicBlock *data)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_CLASSIC (tag);
BUFFER_INIT (cmd, 2);
BUFFER_ALIAS (res, data, sizeof(MifareClassicBlock));
@ -377,7 +419,6 @@ int
mifare_classic_write (FreefareTag tag, const MifareClassicBlockNumber block, const MifareClassicBlock data)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_CLASSIC (tag);
BUFFER_INIT (cmd, 2 + sizeof (MifareClassicBlock));
BUFFER_INIT (res, 1);
@ -399,7 +440,6 @@ int
mifare_classic_increment (FreefareTag tag, const MifareClassicBlockNumber block, const uint32_t amount)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_CLASSIC (tag);
BUFFER_INIT (cmd, 6);
BUFFER_INIT (res, 1);
@ -421,7 +461,6 @@ int
mifare_classic_decrement (FreefareTag tag, const MifareClassicBlockNumber block, const uint32_t amount)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_CLASSIC (tag);
BUFFER_INIT (cmd, 6);
BUFFER_INIT (res, 1);
@ -442,7 +481,6 @@ int
mifare_classic_restore (FreefareTag tag, const MifareClassicBlockNumber block)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_CLASSIC (tag);
/*
* Same length as the increment and decrement commands but only the first
@ -471,7 +509,6 @@ int
mifare_classic_transfer (FreefareTag tag, const MifareClassicBlockNumber block)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_CLASSIC (tag);
BUFFER_INIT (cmd, 2);
BUFFER_INIT (res, 1);

View file

@ -239,6 +239,16 @@ le24toh (uint8_t data[3])
return (data[2] << 16) | (data[1] << 8) | data[0];
}
bool
mifare_desfire_taste (nfc_device *device, nfc_target target)
{
(void) device;
return target.nm.nmt == NMT_ISO14443A &&
target.nti.nai.btSak == 0x20 &&
target.nti.nai.szAtsLen >= 5 &&
memcmp (target.nti.nai.abtAts, "\x75\x77\x81\x02", 4) == 0;
}
/*
* Memory management functions.
@ -248,7 +258,7 @@ le24toh (uint8_t data[3])
* Allocates and initialize a MIFARE DESFire tag.
*/
FreefareTag
mifare_desfire_tag_new (void)
mifare_desfire_tag_new (nfc_device *device, nfc_target target)
{
FreefareTag tag;
if ((tag= malloc (sizeof (struct mifare_desfire_tag)))) {
@ -257,6 +267,11 @@ mifare_desfire_tag_new (void)
MIFARE_DESFIRE (tag)->session_key = NULL;
MIFARE_DESFIRE (tag)->crypto_buffer = NULL;
MIFARE_DESFIRE (tag)->crypto_buffer_size = 0;
tag->type = MIFARE_DESFIRE;
tag->free_tag = mifare_desfire_tag_free;
tag->device = device;
tag->info = target;
tag->active = 0;
}
return tag;
}
@ -288,7 +303,6 @@ int
mifare_desfire_connect (FreefareTag tag)
{
ASSERT_INACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
nfc_target pnti;
nfc_modulation modulation = {
@ -332,7 +346,6 @@ int
mifare_desfire_disconnect (FreefareTag tag)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
free (MIFARE_DESFIRE (tag)->session_key);
MIFARE_DESFIRE(tag)->session_key = NULL;
@ -353,7 +366,6 @@ static int
authenticate (FreefareTag tag, uint8_t cmd, uint8_t key_no, MifareDESFireKey key)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
memset (MIFARE_DESFIRE (tag)->ivect, 0, MAX_CRYPTO_BLOCK_SIZE);
@ -471,7 +483,6 @@ int
mifare_desfire_change_key_settings (FreefareTag tag, uint8_t settings)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
ASSERT_AUTHENTICATED (tag);
BUFFER_INIT (cmd, 9 + CMAC_LENGTH);
@ -497,7 +508,6 @@ int
mifare_desfire_get_key_settings (FreefareTag tag, uint8_t *settings, uint8_t *max_keys)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
BUFFER_INIT (cmd, 1);
BUFFER_INIT (res, 3 + CMAC_LENGTH);
@ -526,7 +536,6 @@ int
mifare_desfire_change_key (FreefareTag tag, uint8_t key_no, MifareDESFireKey new_key, MifareDESFireKey old_key)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
ASSERT_AUTHENTICATED (tag);
BUFFER_INIT (cmd, 42);
@ -640,7 +649,6 @@ int
mifare_desfire_get_key_version (FreefareTag tag, uint8_t key_no, uint8_t *version)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
ASSERT_NOT_NULL (version);
@ -671,7 +679,6 @@ static int
create_application (FreefareTag tag, MifareDESFireAID aid, uint8_t settings1, uint8_t settings2, int want_iso_application, int want_iso_file_identifiers, uint16_t iso_file_id, uint8_t *iso_file_name, size_t iso_file_name_len)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
BUFFER_INIT (cmd, 22);
BUFFER_INIT (res, 1 + CMAC_LENGTH);
@ -743,7 +750,6 @@ int
mifare_desfire_delete_application (FreefareTag tag, MifareDESFireAID aid)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
BUFFER_INIT (cmd, 4 + CMAC_LENGTH);
BUFFER_INIT (res, 1 + CMAC_LENGTH);
@ -778,7 +784,6 @@ int
mifare_desfire_get_application_ids (FreefareTag tag, MifareDESFireAID *aids[], size_t *count)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
BUFFER_INIT (cmd, 1);
BUFFER_INIT (res, MAX_RAPDU_SIZE);
@ -833,7 +838,6 @@ int
mifare_desfire_get_df_names (FreefareTag tag, MifareDESFireDF *dfs[], size_t *count)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
*count = 0;
*dfs = NULL;
@ -882,7 +886,6 @@ int
mifare_desfire_select_application (FreefareTag tag, MifareDESFireAID aid)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
struct mifare_desfire_aid null_aid = { .data = { 0x00, 0x00, 0x00 } };
@ -921,7 +924,6 @@ int
mifare_desfire_format_picc (FreefareTag tag)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
ASSERT_AUTHENTICATED (tag);
BUFFER_INIT (cmd, 1 + CMAC_LENGTH);
@ -953,7 +955,6 @@ int
mifare_desfire_get_version (FreefareTag tag, struct mifare_desfire_version_info *version_info)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
ASSERT_NOT_NULL (version_info);
@ -991,7 +992,6 @@ int
mifare_desfire_free_mem (FreefareTag tag, uint32_t *size)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
ASSERT_NOT_NULL (size);
@ -1019,7 +1019,6 @@ int
mifare_desfire_set_configuration (FreefareTag tag, bool disable_format, bool enable_random_uid)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
BUFFER_INIT (cmd, 10);
BUFFER_INIT (res, 1 + CMAC_LENGTH);
@ -1045,7 +1044,6 @@ int
mifare_desfire_set_default_key (FreefareTag tag, MifareDESFireKey key)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
BUFFER_INIT (cmd, 34);
BUFFER_INIT (res, 1 + CMAC_LENGTH);
@ -1085,7 +1083,6 @@ int
mifare_desfire_set_ats (FreefareTag tag, uint8_t *ats)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
BUFFER_INIT (cmd, 34);
BUFFER_INIT (res, 1 + CMAC_LENGTH);
@ -1122,7 +1119,6 @@ int
mifare_desfire_get_card_uid (FreefareTag tag, char **uid)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
ASSERT_NOT_NULL (uid);
@ -1160,7 +1156,6 @@ int
mifare_desfire_get_file_ids (FreefareTag tag, uint8_t **files, size_t *count)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
BUFFER_INIT (cmd, 1 + CMAC_LENGTH);
BUFFER_INIT (res, 16 + CMAC_LENGTH);
@ -1193,7 +1188,6 @@ int
mifare_desfire_get_iso_file_ids (FreefareTag tag, uint16_t **files, size_t *count)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
BUFFER_INIT (cmd, 1);
BUFFER_INIT (res, 2*27 + 1);
@ -1241,7 +1235,6 @@ int
mifare_desfire_get_file_settings (FreefareTag tag, uint8_t file_no, struct mifare_desfire_file_settings *settings)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
if (cached_file_settings_current[file_no]) {
*settings = cached_file_settings[file_no];
@ -1300,7 +1293,6 @@ int
mifare_desfire_change_file_settings (FreefareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
struct mifare_desfire_file_settings settings;
int res = mifare_desfire_get_file_settings (tag, file_no, &settings);
@ -1353,7 +1345,6 @@ static int
create_file1 (FreefareTag tag, uint8_t command, uint8_t file_no, int has_iso_file_id, uint16_t iso_file_id, uint8_t communication_settings, uint16_t access_rights, uint32_t file_size)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
BUFFER_INIT (cmd, 10 + CMAC_LENGTH);
BUFFER_INIT (res, 1 + CMAC_LENGTH);
@ -1409,7 +1400,6 @@ int
mifare_desfire_create_value_file (FreefareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, int32_t lower_limit, int32_t upper_limit, int32_t value, uint8_t limited_credit_enable)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
BUFFER_INIT (cmd, 18 + CMAC_LENGTH);
BUFFER_INIT (res, 1 + CMAC_LENGTH);
@ -1442,7 +1432,6 @@ static int
create_file2 (FreefareTag tag, uint8_t command, uint8_t file_no, int has_iso_file_id, uint16_t iso_file_id, uint8_t communication_settings, uint16_t access_rights, uint32_t record_size, uint32_t max_number_of_records)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
BUFFER_INIT (cmd, 11 + CMAC_LENGTH);
BUFFER_INIT (res, 1 + CMAC_LENGTH);
@ -1499,7 +1488,6 @@ int
mifare_desfire_delete_file (FreefareTag tag, uint8_t file_no)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
BUFFER_INIT (cmd, 2 + CMAC_LENGTH);
BUFFER_INIT (res, 1 + CMAC_LENGTH);
@ -1531,7 +1519,6 @@ read_data (FreefareTag tag, uint8_t command, uint8_t file_no, off_t offset, size
size_t bytes_received = 0;
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
ASSERT_CS (cs);
BUFFER_INIT (cmd, 8);
@ -1654,7 +1641,6 @@ write_data (FreefareTag tag, uint8_t command, uint8_t file_no, off_t offset, siz
size_t bytes_send = 0;
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
ASSERT_CS (cs);
BUFFER_INIT (cmd, 8 + length + CMAC_LENGTH);
@ -1734,7 +1720,6 @@ mifare_desfire_get_value_ex (FreefareTag tag, uint8_t file_no, int32_t *value, i
return errno = EINVAL, -1;
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
ASSERT_CS (cs);
BUFFER_INIT (cmd, 2 + CMAC_LENGTH);
@ -1768,7 +1753,6 @@ int
mifare_desfire_credit_ex (FreefareTag tag, uint8_t file_no, int32_t amount, int cs)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
ASSERT_CS (cs);
BUFFER_INIT (cmd, 10 + CMAC_LENGTH);
@ -1801,7 +1785,6 @@ int
mifare_desfire_debit_ex (FreefareTag tag, uint8_t file_no, int32_t amount, int cs)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
ASSERT_CS (cs);
BUFFER_INIT (cmd, 10 + CMAC_LENGTH);
@ -1834,7 +1817,6 @@ int
mifare_desfire_limited_credit_ex (FreefareTag tag, uint8_t file_no, int32_t amount, int cs)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
ASSERT_CS (cs);
BUFFER_INIT (cmd, 10 + CMAC_LENGTH);
@ -1885,7 +1867,6 @@ int
mifare_desfire_clear_record_file (FreefareTag tag, uint8_t file_no)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
BUFFER_INIT (cmd, 2 + CMAC_LENGTH);
BUFFER_INIT (res, 1 + CMAC_LENGTH);
@ -1912,7 +1893,6 @@ int
mifare_desfire_commit_transaction (FreefareTag tag)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
BUFFER_INIT (cmd, 1 + CMAC_LENGTH);
BUFFER_INIT (res, 1 + CMAC_LENGTH);
@ -1936,7 +1916,6 @@ int
mifare_desfire_abort_transaction (FreefareTag tag)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
BUFFER_INIT (cmd, 1 + CMAC_LENGTH);
BUFFER_INIT (res, 1 + CMAC_LENGTH);

View file

@ -72,7 +72,7 @@ mifare_desfire_error_lookup (uint8_t code)
uint8_t
mifare_desfire_last_pcd_error (FreefareTag tag)
{
if (tag->tag_info->type != MIFARE_DESFIRE)
if (tag->type != MIFARE_DESFIRE)
return 0;
return MIFARE_DESFIRE (tag)->last_pcd_error;
@ -81,7 +81,7 @@ mifare_desfire_last_pcd_error (FreefareTag tag)
uint8_t
mifare_desfire_last_picc_error (FreefareTag tag)
{
if (tag->tag_info->type != MIFARE_DESFIRE)
if (tag->type != MIFARE_DESFIRE)
return 0;
return MIFARE_DESFIRE (tag)->last_picc_error;

View file

@ -45,7 +45,7 @@
#define ASSERT_VALID_PAGE(tag, page, mode_write) \
do { \
if (IS_MIFARE_ULTRALIGHT_C(tag)) { \
if (is_mifare_ultralightc (tag)) { \
if (mode_write) { \
if (page >= MIFARE_ULTRALIGHT_C_PAGE_COUNT) return errno = EINVAL, -1; \
} else { \
@ -89,6 +89,24 @@
} \
} while (0)
static bool
taste (nfc_target target)
{
return target.nm.nmt == NMT_ISO14443A && target.nti.nai.btSak == 0x00;
}
bool
mifare_ultralight_taste (nfc_device *device, nfc_target target)
{
return taste (target) && !is_mifare_ultralightc_on_reader (device, target.nti.nai);
}
bool
mifare_ultralightc_taste (nfc_device *device, nfc_target target)
{
return taste (target) && is_mifare_ultralightc_on_reader (device, target.nti.nai);
}
/*
* Memory management functions.
@ -97,10 +115,32 @@
/*
* Allocates and initialize a MIFARE UltraLight tag.
*/
FreefareTag
mifare_ultralight_tag_new (void)
static FreefareTag
_mifare_ultralightc_tag_new (nfc_device *device, nfc_target target, bool is_ultralightc)
{
return malloc (sizeof (struct mifare_ultralight_tag));
FreefareTag tag;
if ((tag = malloc (sizeof (struct mifare_ultralight_tag)))) {
tag->type = (is_ultralightc) ? MIFARE_ULTRALIGHT_C : MIFARE_ULTRALIGHT;
tag->free_tag = mifare_ultralightc_tag_free;
tag->device = device;
tag->info = target;
tag->active = 0;
}
return tag;
}
FreefareTag
mifare_ultralight_tag_new (nfc_device *device, nfc_target target)
{
return _mifare_ultralightc_tag_new (device, target, false);
}
FreefareTag
mifare_ultralightc_tag_new (nfc_device *device, nfc_target target)
{
return _mifare_ultralightc_tag_new (device, target, true);
}
/*
@ -112,6 +152,12 @@ mifare_ultralight_tag_free (FreefareTag tag)
free (tag);
}
void
mifare_ultralightc_tag_free (FreefareTag tag)
{
mifare_ultralight_tag_free (tag);
}
/*
* MIFARE card communication preparation functions
@ -129,7 +175,6 @@ int
mifare_ultralight_connect (FreefareTag tag)
{
ASSERT_INACTIVE (tag);
ASSERT_MIFARE_ULTRALIGHT (tag);
nfc_target pnti;
nfc_modulation modulation = {
@ -154,7 +199,6 @@ int
mifare_ultralight_disconnect (FreefareTag tag)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_ULTRALIGHT (tag);
if (nfc_initiator_deselect_target (tag->device) >= 0) {
tag->active = 0;
@ -180,7 +224,6 @@ int
mifare_ultralight_read (FreefareTag tag, MifareUltralightPageNumber page, MifareUltralightPage *data)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_ULTRALIGHT (tag);
ASSERT_VALID_PAGE (tag, page, false);
if (!MIFARE_ULTRALIGHT(tag)->cached_pages[page]) {
@ -194,7 +237,7 @@ mifare_ultralight_read (FreefareTag tag, MifareUltralightPageNumber page, Mifare
/* Handle wrapped pages */
int iPageCount;
if (IS_MIFARE_ULTRALIGHT_C(tag)) {
if (is_mifare_ultralightc (tag)) {
iPageCount = MIFARE_ULTRALIGHT_C_PAGE_COUNT_READ;
} else {
iPageCount = MIFARE_ULTRALIGHT_PAGE_COUNT;
@ -220,7 +263,6 @@ int
mifare_ultralight_write (FreefareTag tag, const MifareUltralightPageNumber page, const MifareUltralightPage data)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_ULTRALIGHT (tag);
ASSERT_VALID_PAGE (tag, page, true);
BUFFER_INIT (cmd, 6);
@ -245,7 +287,6 @@ int
mifare_ultralightc_authenticate (FreefareTag tag, const MifareDESFireKey key)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_ULTRALIGHT_C (tag);
BUFFER_INIT (cmd1, 2);
BUFFER_INIT (res, 9);
@ -306,6 +347,18 @@ mifare_ultralightc_authenticate (FreefareTag tag, const MifareDESFireKey key)
return 0;
}
bool
is_mifare_ultralight (FreefareTag tag)
{
return tag->type == MIFARE_ULTRALIGHT;
}
bool
is_mifare_ultralightc (FreefareTag tag)
{
return tag->type == MIFARE_ULTRALIGHT_C;
}
/*
* Callback for freefare_tag_new to test presence of a MIFARE UltralightC on the reader.
*/

View file

@ -12,6 +12,7 @@ TESTS_ENVIRONMENT = NO_MAKE=yes CUTTER="$(CUTTER)"
cutter_unit_test_libs = \
test_felica.la \
test_freefare.la \
test_mad.la \
test_mifare_application.la \
test_mifare_classic.la \
@ -39,6 +40,9 @@ test_felica_la_SOURCES = test_felica.c \
felica_fixture.h
test_felica_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la
test_freefare_la_SOURCES = test_freefare.c
test_freefare_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la
test_mad_la_SOURCES = test_mad.c
test_mad_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la

26
test/test_freefare.c Normal file
View file

@ -0,0 +1,26 @@
#include <cutter.h>
#include <freefare.h>
#include "freefare_internal.h"
void
test_is_mifare_ultralight (void)
{
FreefareTag tag;
nfc_target target;
tag = mifare_ultralight_tag_new (NULL, target);
cut_assert_true (is_mifare_ultralight (tag));
mifare_ultralight_tag_free (tag);
}
void
test_is_mifare_ultralightc (void)
{
FreefareTag tag;
nfc_target target;
tag = mifare_ultralightc_tag_new (NULL, target);
cut_assert_true (is_mifare_ultralightc (tag));
mifare_ultralightc_tag_free (tag);
}

View file

@ -75,7 +75,7 @@ test_mifare_ultralight_invalid_page (void)
MifareUltralightPage page = { 0x00, 0x00, 0x00, 0x00 };
int invalid_page;
if (IS_MIFARE_ULTRALIGHT_C (tag)) {
if (is_mifare_ultralightc (tag)) {
invalid_page = MIFARE_ULTRALIGHT_C_PAGE_COUNT;
} else {
invalid_page = MIFARE_ULTRALIGHT_PAGE_COUNT;
@ -130,7 +130,7 @@ test_mifare_ultralight_cache_wrap (void)
int res;
MifareUltralightPage page;
int last_page;
if (IS_MIFARE_ULTRALIGHT_C (tag)) {
if (is_mifare_ultralightc (tag)) {
// Last 4 blocks are for 3DES key and cannot be read, read will wrap from 0x2b
last_page = MIFARE_ULTRALIGHT_C_PAGE_COUNT_READ -1;
// Actually engineering samples require auth to read above page 0x28 so we skip the test entirely
@ -178,7 +178,7 @@ test_mifare_ultralightc_authenticate (void)
int res;
MifareDESFireKey key;
if (tag->tag_info->type == MIFARE_ULTRALIGHT_C) {
if (is_mifare_ultralightc (tag)) {
uint8_t key1_3des_data[16] = { 0x49, 0x45, 0x4D, 0x4B, 0x41, 0x45, 0x52, 0x42, 0x21, 0x4E, 0x41, 0x43, 0x55, 0x4F, 0x59, 0x46 };
key = mifare_desfire_3des_key_new (key1_3des_data);
res = mifare_ultralightc_authenticate (tag, key);