Fix issues for NTAG21x tags
- Change default tag from NTAG_213 to NTAG_UNKNOWN so unknown tags can be detected. ntag_get_info() MUST be called after connect; - Fix reuse function which used to reset all tag info; - Introduce ntag21x error reporting through freefare_error(3);
This commit is contained in:
parent
75f08d3a85
commit
c18f702840
10 changed files with 119 additions and 20 deletions
|
@ -37,6 +37,8 @@ that you don't have to care about indentation anymore. For more details, please
|
||||||
read the [style(9) man page from FreeBSD's
|
read the [style(9) man page from FreeBSD's
|
||||||
website](http://www.freebsd.org/cgi/man.cgi?query=style).
|
website](http://www.freebsd.org/cgi/man.cgi?query=style).
|
||||||
|
|
||||||
|
For style correction install package `astyle`. Then run `make style`.
|
||||||
|
|
||||||
## Write tests
|
## Write tests
|
||||||
|
|
||||||
I already told you cutter is lovely, so you really should use it! If you want
|
I already told you cutter is lovely, so you really should use it! If you want
|
||||||
|
|
|
@ -153,8 +153,8 @@ main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 4: // Random UID
|
case 4: { // Random UID
|
||||||
{} // Compilation fails if label is directly followed by the declaration rather than a statement
|
} // Compilation fails if label is directly followed by the declaration rather than a statement
|
||||||
MifareDESFireKey key_picc = mifare_desfire_des_key_new_with_version(key_data_picc);
|
MifareDESFireKey key_picc = mifare_desfire_des_key_new_with_version(key_data_picc);
|
||||||
res = mifare_desfire_authenticate(tags[i], 0, key_picc);
|
res = mifare_desfire_authenticate(tags[i], 0, key_picc);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
|
|
|
@ -13,6 +13,7 @@ set(LIBRARY_SOURCES
|
||||||
mifare_key_deriver
|
mifare_key_deriver
|
||||||
mifare_ultralight
|
mifare_ultralight
|
||||||
ntag21x
|
ntag21x
|
||||||
|
ntag21x_error
|
||||||
tlv
|
tlv
|
||||||
../contrib/libutil/hexdump
|
../contrib/libutil/hexdump
|
||||||
)
|
)
|
||||||
|
|
|
@ -16,6 +16,7 @@ libfreefare_la_SOURCES = felica.c \
|
||||||
mad.c \
|
mad.c \
|
||||||
mifare_application.c \
|
mifare_application.c \
|
||||||
ntag21x.c \
|
ntag21x.c \
|
||||||
|
ntag21x_error.c \
|
||||||
tlv.c
|
tlv.c
|
||||||
libfreefare_la_LIBADD =
|
libfreefare_la_LIBADD =
|
||||||
|
|
||||||
|
|
|
@ -225,6 +225,8 @@ freefare_strerror(FreefareTag tag)
|
||||||
} else if (MIFARE_DESFIRE(tag)->last_picc_error) {
|
} else if (MIFARE_DESFIRE(tag)->last_picc_error) {
|
||||||
p = mifare_desfire_error_lookup(MIFARE_DESFIRE(tag)->last_picc_error);
|
p = mifare_desfire_error_lookup(MIFARE_DESFIRE(tag)->last_picc_error);
|
||||||
}
|
}
|
||||||
|
} else if (tag->type == NTAG_21x) {
|
||||||
|
p = ntag21x_error_lookup(NTAG_21x(tag)->last_error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
|
|
|
@ -93,6 +93,7 @@ bool is_mifare_ultralightc_on_reader(nfc_device *device, nfc_iso14443a_info na
|
||||||
|
|
||||||
|
|
||||||
bool ntag21x_taste(nfc_device *device, nfc_target target);
|
bool ntag21x_taste(nfc_device *device, nfc_target target);
|
||||||
|
uint8_t ntag21x_last_error(FreefareTag tag);
|
||||||
|
|
||||||
/* NTAG21x access features */
|
/* NTAG21x access features */
|
||||||
#define NTAG_PROT 0x80
|
#define NTAG_PROT 0x80
|
||||||
|
@ -102,6 +103,7 @@ bool ntag21x_taste(nfc_device *device, nfc_target target);
|
||||||
#define NTAG_AUTHLIM 0x07
|
#define NTAG_AUTHLIM 0x07
|
||||||
|
|
||||||
enum ntag_tag_subtype {
|
enum ntag_tag_subtype {
|
||||||
|
NTAG_UNKNOWN,
|
||||||
NTAG_213,
|
NTAG_213,
|
||||||
NTAG_215,
|
NTAG_215,
|
||||||
NTAG_216
|
NTAG_216
|
||||||
|
@ -367,6 +369,8 @@ bit 0: PICC master key frozen (reversible with configuration change or when form
|
||||||
/* Error code managed by the library */
|
/* Error code managed by the library */
|
||||||
|
|
||||||
#define CRYPTO_ERROR 0x01
|
#define CRYPTO_ERROR 0x01
|
||||||
|
#define TAG_INFO_MISSING_ERROR 0xBA
|
||||||
|
#define UNKNOWN_TAG_TYPE_ERROR 0xBB
|
||||||
|
|
||||||
struct mifare_desfire_aid;
|
struct mifare_desfire_aid;
|
||||||
typedef struct mifare_desfire_aid *MifareDESFireAID;
|
typedef struct mifare_desfire_aid *MifareDESFireAID;
|
||||||
|
|
|
@ -243,6 +243,8 @@ struct ntag21x_tag {
|
||||||
uint8_t minor_product_version;
|
uint8_t minor_product_version;
|
||||||
uint8_t storage_size;
|
uint8_t storage_size;
|
||||||
uint8_t protocol_type;
|
uint8_t protocol_type;
|
||||||
|
|
||||||
|
uint8_t last_error;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ntag21x_key {
|
struct ntag21x_key {
|
||||||
|
@ -250,6 +252,8 @@ struct ntag21x_key {
|
||||||
uint8_t pack[2]; // 2B Password Acknowlege
|
uint8_t pack[2]; // 2B Password Acknowlege
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char *ntag21x_error_lookup(uint8_t code);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FreefareTag assertion macros
|
* FreefareTag assertion macros
|
||||||
*
|
*
|
||||||
|
|
|
@ -44,6 +44,8 @@
|
||||||
{return errno = EINVAL, -1;} \
|
{return errno = EINVAL, -1;} \
|
||||||
else if(NTAG_21x(tag)->subtype == NTAG_216&&page>0xE6) \
|
else if(NTAG_21x(tag)->subtype == NTAG_216&&page>0xE6) \
|
||||||
{return errno = EINVAL, -1;} \
|
{return errno = EINVAL, -1;} \
|
||||||
|
else if(NTAG_21x(tag)->subtype == NTAG_UNKNOWN) \
|
||||||
|
{return errno = EINVAL, -1;} \
|
||||||
} else { \
|
} else { \
|
||||||
if(NTAG_21x(tag)->subtype == NTAG_213&&page>0x2C) \
|
if(NTAG_21x(tag)->subtype == NTAG_213&&page>0x2C) \
|
||||||
{return errno = EINVAL, -1;} \
|
{return errno = EINVAL, -1;} \
|
||||||
|
@ -51,6 +53,8 @@
|
||||||
{return errno = EINVAL, -1;} \
|
{return errno = EINVAL, -1;} \
|
||||||
else if(NTAG_21x(tag)->subtype == NTAG_216&&page>0xE6) \
|
else if(NTAG_21x(tag)->subtype == NTAG_216&&page>0xE6) \
|
||||||
{return errno = EINVAL, -1;} \
|
{return errno = EINVAL, -1;} \
|
||||||
|
else if(NTAG_21x(tag)->subtype == NTAG_UNKNOWN) \
|
||||||
|
{return errno = EINVAL, -1;} \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
@ -113,14 +117,15 @@ _ntag21x_tag_new(nfc_device *device, nfc_target target)
|
||||||
tag->device = device;
|
tag->device = device;
|
||||||
tag->info = target;
|
tag->info = target;
|
||||||
tag->active = 0;
|
tag->active = 0;
|
||||||
NTAG_21x(tag)->subtype = NTAG_213; // Set tag subtype
|
NTAG_21x(tag)->subtype = NTAG_UNKNOWN;
|
||||||
NTAG_21x(tag)->vendor_id = 0x04;
|
NTAG_21x(tag)->vendor_id = 0x00;
|
||||||
NTAG_21x(tag)->product_type = 0x04;
|
NTAG_21x(tag)->product_type = 0x00;
|
||||||
NTAG_21x(tag)->product_subtype = 0x02;
|
NTAG_21x(tag)->product_subtype = 0x00;
|
||||||
NTAG_21x(tag)->major_product_version = 0x01;
|
NTAG_21x(tag)->major_product_version = 0x00;
|
||||||
NTAG_21x(tag)->minor_product_version = 0x00;
|
NTAG_21x(tag)->minor_product_version = 0x00;
|
||||||
NTAG_21x(tag)->storage_size = 0x0f;
|
NTAG_21x(tag)->storage_size = 0x00;
|
||||||
NTAG_21x(tag)->protocol_type = 0x03;
|
NTAG_21x(tag)->protocol_type = 0x00;
|
||||||
|
NTAG_21x(tag)->last_error = OPERATION_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
return tag;
|
return tag;
|
||||||
|
@ -137,14 +142,15 @@ _ntag21x_tag_reuse(FreefareTag old_tag)
|
||||||
tag->device = old_tag->device;
|
tag->device = old_tag->device;
|
||||||
tag->info = old_tag->info;
|
tag->info = old_tag->info;
|
||||||
tag->active = 0;
|
tag->active = 0;
|
||||||
NTAG_21x(tag)->subtype = NTAG_213; // Set tag subtype
|
NTAG_21x(tag)->subtype = NTAG_21x(old_tag)->subtype;
|
||||||
NTAG_21x(tag)->vendor_id = 0x04;
|
NTAG_21x(tag)->vendor_id = NTAG_21x(old_tag)->vendor_id;
|
||||||
NTAG_21x(tag)->product_type = 0x04;
|
NTAG_21x(tag)->product_type = NTAG_21x(old_tag)->product_type;
|
||||||
NTAG_21x(tag)->product_subtype = 0x02;
|
NTAG_21x(tag)->product_subtype = NTAG_21x(old_tag)->product_subtype;
|
||||||
NTAG_21x(tag)->major_product_version = 0x01;
|
NTAG_21x(tag)->major_product_version = NTAG_21x(old_tag)->major_product_version;
|
||||||
NTAG_21x(tag)->minor_product_version = 0x00;
|
NTAG_21x(tag)->minor_product_version = NTAG_21x(old_tag)->minor_product_version;
|
||||||
NTAG_21x(tag)->storage_size = 0x0f;
|
NTAG_21x(tag)->storage_size = NTAG_21x(old_tag)->storage_size;
|
||||||
NTAG_21x(tag)->protocol_type = 0x03;
|
NTAG_21x(tag)->protocol_type = NTAG_21x(old_tag)->protocol_type;
|
||||||
|
NTAG_21x(tag)->last_error = NTAG_21x(old_tag)->last_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return tag;
|
return tag;
|
||||||
|
@ -282,7 +288,8 @@ ntag21x_get_info(FreefareTag tag)
|
||||||
NTAG_21x(tag)->subtype = NTAG_216;
|
NTAG_21x(tag)->subtype = NTAG_216;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
NTAG_21x(tag)->subtype = NTAG_213;
|
NTAG_21x(tag)->last_error = UNKNOWN_TAG_TYPE_ERROR;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -309,6 +316,7 @@ ntag21x_get_last_page(FreefareTag tag)
|
||||||
case NTAG_216:
|
case NTAG_216:
|
||||||
return 0xE6;
|
return 0xE6;
|
||||||
default:
|
default:
|
||||||
|
NTAG_21x(tag)->last_error = TAG_INFO_MISSING_ERROR;
|
||||||
return 0x00;
|
return 0x00;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -348,6 +356,10 @@ ntag21x_read_signature(FreefareTag tag, uint8_t *data)
|
||||||
int
|
int
|
||||||
ntag21x_set_pwd(FreefareTag tag, uint8_t data[4]) // Set password
|
ntag21x_set_pwd(FreefareTag tag, uint8_t data[4]) // Set password
|
||||||
{
|
{
|
||||||
|
if (NTAG_21x(tag)->subtype == NTAG_UNKNOWN) {
|
||||||
|
NTAG_21x(tag)->last_error = TAG_INFO_MISSING_ERROR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
uint8_t page = ntag21x_get_last_page(tag) - 1; // PWD page is located 1 before last page
|
uint8_t page = ntag21x_get_last_page(tag) - 1; // PWD page is located 1 before last page
|
||||||
int res = ntag21x_write(tag, page, data);
|
int res = ntag21x_write(tag, page, data);
|
||||||
return res;
|
return res;
|
||||||
|
@ -356,6 +368,10 @@ ntag21x_set_pwd(FreefareTag tag, uint8_t data[4]) // Set password
|
||||||
int
|
int
|
||||||
ntag21x_set_pack(FreefareTag tag, uint8_t data[2]) // Set pack
|
ntag21x_set_pack(FreefareTag tag, uint8_t data[2]) // Set pack
|
||||||
{
|
{
|
||||||
|
if (NTAG_21x(tag)->subtype == NTAG_UNKNOWN) {
|
||||||
|
NTAG_21x(tag)->last_error = TAG_INFO_MISSING_ERROR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
BUFFER_INIT(buff, 4);
|
BUFFER_INIT(buff, 4);
|
||||||
BUFFER_APPEND_BYTES(buff, data, 2);
|
BUFFER_APPEND_BYTES(buff, data, 2);
|
||||||
BUFFER_APPEND(buff, 0x00);
|
BUFFER_APPEND(buff, 0x00);
|
||||||
|
@ -382,6 +398,10 @@ ntag21x_set_key(FreefareTag tag, const NTAG21xKey key) // Set key
|
||||||
int
|
int
|
||||||
ntag21x_set_auth(FreefareTag tag, uint8_t byte) // Set AUTH0 byte (from which page starts password protection)
|
ntag21x_set_auth(FreefareTag tag, uint8_t byte) // Set AUTH0 byte (from which page starts password protection)
|
||||||
{
|
{
|
||||||
|
if (NTAG_21x(tag)->subtype == NTAG_UNKNOWN) {
|
||||||
|
NTAG_21x(tag)->last_error = TAG_INFO_MISSING_ERROR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
BUFFER_INIT(cdata, 4);
|
BUFFER_INIT(cdata, 4);
|
||||||
int page = ntag21x_get_last_page(tag) - 3; // AUTH0 byte is on 4th page from back
|
int page = ntag21x_get_last_page(tag) - 3; // AUTH0 byte is on 4th page from back
|
||||||
int res;
|
int res;
|
||||||
|
@ -396,6 +416,10 @@ ntag21x_set_auth(FreefareTag tag, uint8_t byte) // Set AUTH0 byte (from which pa
|
||||||
int
|
int
|
||||||
ntag21x_get_auth(FreefareTag tag, uint8_t *byte) // Get AUTH0 byte
|
ntag21x_get_auth(FreefareTag tag, uint8_t *byte) // Get AUTH0 byte
|
||||||
{
|
{
|
||||||
|
if (NTAG_21x(tag)->subtype == NTAG_UNKNOWN) {
|
||||||
|
NTAG_21x(tag)->last_error = TAG_INFO_MISSING_ERROR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
BUFFER_INIT(cdata, 4);
|
BUFFER_INIT(cdata, 4);
|
||||||
int page = ntag21x_get_last_page(tag) - 3; // AUTH0 byte is on 4th page from back
|
int page = ntag21x_get_last_page(tag) - 3; // AUTH0 byte is on 4th page from back
|
||||||
int res;
|
int res;
|
||||||
|
@ -409,6 +433,10 @@ ntag21x_get_auth(FreefareTag tag, uint8_t *byte) // Get AUTH0 byte
|
||||||
int
|
int
|
||||||
ntag21x_access_enable(FreefareTag tag, uint8_t byte) // Enable access feature in ACCESS byte
|
ntag21x_access_enable(FreefareTag tag, uint8_t byte) // Enable access feature in ACCESS byte
|
||||||
{
|
{
|
||||||
|
if (NTAG_21x(tag)->subtype == NTAG_UNKNOWN) {
|
||||||
|
NTAG_21x(tag)->last_error = TAG_INFO_MISSING_ERROR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
BUFFER_INIT(cdata, 4);
|
BUFFER_INIT(cdata, 4);
|
||||||
int page = ntag21x_get_last_page(tag) - 2; // ACCESS byte is on 3th page from back
|
int page = ntag21x_get_last_page(tag) - 2; // ACCESS byte is on 3th page from back
|
||||||
int res;
|
int res;
|
||||||
|
@ -423,6 +451,10 @@ ntag21x_access_enable(FreefareTag tag, uint8_t byte) // Enable access feature in
|
||||||
int
|
int
|
||||||
ntag21x_access_disable(FreefareTag tag, uint8_t byte) // Disable access feature in ACCESS byte
|
ntag21x_access_disable(FreefareTag tag, uint8_t byte) // Disable access feature in ACCESS byte
|
||||||
{
|
{
|
||||||
|
if (NTAG_21x(tag)->subtype == NTAG_UNKNOWN) {
|
||||||
|
NTAG_21x(tag)->last_error = TAG_INFO_MISSING_ERROR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
BUFFER_INIT(cdata, 4);
|
BUFFER_INIT(cdata, 4);
|
||||||
int page = ntag21x_get_last_page(tag) - 2; // ACCESS byte is on 3th page from back
|
int page = ntag21x_get_last_page(tag) - 2; // ACCESS byte is on 3th page from back
|
||||||
int res;
|
int res;
|
||||||
|
@ -437,6 +469,10 @@ ntag21x_access_disable(FreefareTag tag, uint8_t byte) // Disable access feature
|
||||||
int
|
int
|
||||||
ntag21x_get_access(FreefareTag tag, uint8_t *byte) // Get ACCESS byte
|
ntag21x_get_access(FreefareTag tag, uint8_t *byte) // Get ACCESS byte
|
||||||
{
|
{
|
||||||
|
if (NTAG_21x(tag)->subtype == NTAG_UNKNOWN) {
|
||||||
|
NTAG_21x(tag)->last_error = TAG_INFO_MISSING_ERROR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
BUFFER_INIT(cdata, 4);
|
BUFFER_INIT(cdata, 4);
|
||||||
uint8_t page = ntag21x_get_last_page(tag) - 2; // ACCESS byte is on 3th page from back
|
uint8_t page = ntag21x_get_last_page(tag) - 2; // ACCESS byte is on 3th page from back
|
||||||
int res;
|
int res;
|
||||||
|
@ -464,6 +500,10 @@ ntag21x_check_access(FreefareTag tag, uint8_t byte, bool *result) // Check if ac
|
||||||
int
|
int
|
||||||
ntag21x_get_authentication_limit(FreefareTag tag, uint8_t *byte) // Get authentication limit
|
ntag21x_get_authentication_limit(FreefareTag tag, uint8_t *byte) // Get authentication limit
|
||||||
{
|
{
|
||||||
|
if (NTAG_21x(tag)->subtype == NTAG_UNKNOWN) {
|
||||||
|
NTAG_21x(tag)->last_error = TAG_INFO_MISSING_ERROR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
BUFFER_INIT(cdata, 4);
|
BUFFER_INIT(cdata, 4);
|
||||||
uint8_t page = ntag21x_get_last_page(tag) - 2; // ACCESS byte is on 3th page from back
|
uint8_t page = ntag21x_get_last_page(tag) - 2; // ACCESS byte is on 3th page from back
|
||||||
int res;
|
int res;
|
||||||
|
@ -480,6 +520,10 @@ ntag21x_set_authentication_limit(FreefareTag tag, uint8_t byte) // Set authentic
|
||||||
{
|
{
|
||||||
if (byte > 7) // Check for invalid range of auth limit
|
if (byte > 7) // Check for invalid range of auth limit
|
||||||
return -1;
|
return -1;
|
||||||
|
if (NTAG_21x(tag)->subtype == NTAG_UNKNOWN) {
|
||||||
|
NTAG_21x(tag)->last_error = TAG_INFO_MISSING_ERROR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
BUFFER_INIT(cdata, 4);
|
BUFFER_INIT(cdata, 4);
|
||||||
int page = ntag21x_get_last_page(tag) - 2; // ACCESS byte is on 3th page from back
|
int page = ntag21x_get_last_page(tag) - 2; // ACCESS byte is on 3th page from back
|
||||||
|
|
41
libfreefare/ntag21x_error.c
Normal file
41
libfreefare/ntag21x_error.c
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <freefare.h>
|
||||||
|
|
||||||
|
#include "freefare_internal.h"
|
||||||
|
|
||||||
|
#define EM(e) { e, #e }
|
||||||
|
|
||||||
|
static struct ntag21x_error_message {
|
||||||
|
uint8_t code;
|
||||||
|
const char *message;
|
||||||
|
} ntag21x_error_messages[] = {
|
||||||
|
EM(OPERATION_OK),
|
||||||
|
EM(TAG_INFO_MISSING_ERROR),
|
||||||
|
EM(UNKNOWN_TAG_TYPE_ERROR),
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *
|
||||||
|
ntag21x_error_lookup(uint8_t code)
|
||||||
|
{
|
||||||
|
struct ntag21x_error_message *e = ntag21x_error_messages;
|
||||||
|
while (e->message) {
|
||||||
|
if (e->code == code)
|
||||||
|
return (e->message);
|
||||||
|
e++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Invalid error code";
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
ntag21x_last_error(FreefareTag tag)
|
||||||
|
{
|
||||||
|
if (tag->type != NTAG_21x)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return NTAG_21x(tag)->last_error;
|
||||||
|
}
|
Loading…
Reference in a new issue