Fixes error handling when performing MIFARE commands:
Before this commit, MFOC was considering any errors as authentication error (AUTH command) or permission error (READ/WRITE commands); With this patch, any error which is not a tag-related error will produce a program exit (with EXIT_FAILURE flag). Plus, this commit silents MIFARE authentication error while MFOC try some default keys...
This commit is contained in:
parent
9a02d34ede
commit
0c2d2b5894
3 changed files with 86 additions and 58 deletions
66
src/mfoc.c
66
src/mfoc.c
|
@ -277,9 +277,12 @@ int main(int argc, char *const argv[])
|
||||||
if (trailer_block(block)) {
|
if (trailer_block(block)) {
|
||||||
if (!t.sectors[i].foundKeyA) {
|
if (!t.sectors[i].foundKeyA) {
|
||||||
mc = MC_AUTH_A;
|
mc = MC_AUTH_A;
|
||||||
if (!nfc_initiator_mifare_cmd(r.pdi, mc, block, &mp)) {
|
int res;
|
||||||
// fprintf(stdout, "!!Error: AUTH [Key A:%012llx] sector %02x t_block %02x\n",
|
if ((res = nfc_initiator_mifare_cmd(r.pdi, mc, block, &mp)) < 0) {
|
||||||
// bytes_to_num(mp.mpa.abtKey, 6), i, block);
|
if (res != NFC_EMFCAUTHFAIL) {
|
||||||
|
nfc_perror (r.pdi, "nfc_initiator_mifare_cmd");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
mf_anticollision(t, r);
|
mf_anticollision(t, r);
|
||||||
} else {
|
} else {
|
||||||
// Save all information about successfull keyA authentization
|
// Save all information about successfull keyA authentization
|
||||||
|
@ -289,9 +292,12 @@ int main(int argc, char *const argv[])
|
||||||
}
|
}
|
||||||
if (!t.sectors[i].foundKeyB) {
|
if (!t.sectors[i].foundKeyB) {
|
||||||
mc = MC_AUTH_B;
|
mc = MC_AUTH_B;
|
||||||
if (!nfc_initiator_mifare_cmd(r.pdi, mc, block, &mp)) {
|
int res;
|
||||||
// fprintf(stdout, "!!Error: AUTH [Key B:%012llx] sector %02x t_block %02x\n",
|
if ((res = nfc_initiator_mifare_cmd(r.pdi, mc, block, &mp)) < 0) {
|
||||||
// bytes_to_num(mp.mpa.abtKey, 6), i, block);
|
if (res != NFC_EMFCAUTHFAIL) {
|
||||||
|
nfc_perror (r.pdi, "nfc_initiator_mifare_cmd");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
mf_anticollision(t, r);
|
mf_anticollision(t, r);
|
||||||
// No success, try next block
|
// No success, try next block
|
||||||
t.sectors[i].trailer = block;
|
t.sectors[i].trailer = block;
|
||||||
|
@ -310,8 +316,6 @@ int main(int argc, char *const argv[])
|
||||||
fprintf(stdout, ".");
|
fprintf(stdout, ".");
|
||||||
}
|
}
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
// fprintf(stdout, "\nSuccess: AUTH [Key %c:%012llx] sector %02x t_block %02x\n",
|
|
||||||
// (mc == MC_AUTH_A ? 'A' :'B'), bytes_to_num(mp.mpa.abtKey, 6), i, block);
|
|
||||||
// Save position of a trailer block to sector struct
|
// Save position of a trailer block to sector struct
|
||||||
t.sectors[i++].trailer = block;
|
t.sectors[i++].trailer = block;
|
||||||
}
|
}
|
||||||
|
@ -343,9 +347,12 @@ int main(int argc, char *const argv[])
|
||||||
for (uint32_t o = 0; o < bk->size; o++) {
|
for (uint32_t o = 0; o < bk->size; o++) {
|
||||||
num_to_bytes(bk->brokenKeys[o], 6, mp.mpa.abtKey);
|
num_to_bytes(bk->brokenKeys[o], 6, mp.mpa.abtKey);
|
||||||
mc = dumpKeysA ? MC_AUTH_A : MC_AUTH_B;
|
mc = dumpKeysA ? MC_AUTH_A : MC_AUTH_B;
|
||||||
if (!nfc_initiator_mifare_cmd(r.pdi, mc, t.sectors[j].trailer, &mp)) {
|
int res;
|
||||||
// fprintf(stdout, "!!Error: AUTH [Key A:%012llx] sector %02x t_block %02x, key %d\n",
|
if ((res = nfc_initiator_mifare_cmd(r.pdi, mc, t.sectors[j].trailer, &mp)) < 0) {
|
||||||
// bytes_to_num(mp.mpa.abtKey, 6), j, t.sectors[j].trailer, o);
|
if (res != NFC_EMFCAUTHFAIL) {
|
||||||
|
nfc_perror (r.pdi, "nfc_initiator_mifare_cmd");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
mf_anticollision(t, r);
|
mf_anticollision(t, r);
|
||||||
} else {
|
} else {
|
||||||
// Save all information about successfull authentization
|
// Save all information about successfull authentization
|
||||||
|
@ -398,9 +405,12 @@ int main(int argc, char *const argv[])
|
||||||
// Set required authetication method
|
// Set required authetication method
|
||||||
num_to_bytes(ck[i].key, 6, mp.mpa.abtKey);
|
num_to_bytes(ck[i].key, 6, mp.mpa.abtKey);
|
||||||
mc = dumpKeysA ? MC_AUTH_A : MC_AUTH_B;
|
mc = dumpKeysA ? MC_AUTH_A : MC_AUTH_B;
|
||||||
if (!nfc_initiator_mifare_cmd(r.pdi, mc, t.sectors[j].trailer, &mp)) {
|
int res;
|
||||||
// fprintf(stdout, "!!Error: AUTH [Key A:%llx] sector %02x t_block %02x\n",
|
if ((res = nfc_initiator_mifare_cmd(r.pdi, mc, t.sectors[j].trailer, &mp)) < 0) {
|
||||||
// bytes_to_num(mp.mpa.abtKey, 6), j, t.sectors[j].trailer);
|
if (res != NFC_EMFCAUTHFAIL) {
|
||||||
|
nfc_perror (r.pdi, "nfc_initiator_mifare_cmd");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
mf_anticollision(t, r);
|
mf_anticollision(t, r);
|
||||||
} else {
|
} else {
|
||||||
// Save all information about successfull authentization
|
// Save all information about successfull authentization
|
||||||
|
@ -457,12 +467,16 @@ int main(int argc, char *const argv[])
|
||||||
|
|
||||||
// Try A key, auth() + read()
|
// Try A key, auth() + read()
|
||||||
memcpy(mp.mpa.abtKey, t.sectors[i].KeyA, sizeof(t.sectors[i].KeyA));
|
memcpy(mp.mpa.abtKey, t.sectors[i].KeyA, sizeof(t.sectors[i].KeyA));
|
||||||
if (!nfc_initiator_mifare_cmd(r.pdi, MC_AUTH_A, block, &mp)) {
|
int res;
|
||||||
// ERR ("Error: Auth A");
|
if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_AUTH_A, block, &mp)) < 0) {
|
||||||
|
if (res != NFC_EMFCAUTHFAIL) {
|
||||||
|
nfc_perror (r.pdi, "nfc_initiator_mifare_cmd");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
mf_configure(r.pdi);
|
mf_configure(r.pdi);
|
||||||
mf_anticollision(t, r);
|
mf_anticollision(t, r);
|
||||||
} else { // and Read
|
} else { // and Read
|
||||||
if (nfc_initiator_mifare_cmd(r.pdi, MC_READ, block, &mp)) {
|
if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_READ, block, &mp)) >= 0) {
|
||||||
fprintf(stdout, "Block %02d, type %c, key %012llx :", block, 'A', bytes_to_num(t.sectors[i].KeyA, 6));
|
fprintf(stdout, "Block %02d, type %c, key %012llx :", block, 'A', bytes_to_num(t.sectors[i].KeyA, 6));
|
||||||
print_hex(mp.mpd.abtData, 16);
|
print_hex(mp.mpd.abtData, 16);
|
||||||
mf_configure(r.pdi);
|
mf_configure(r.pdi);
|
||||||
|
@ -470,22 +484,32 @@ int main(int argc, char *const argv[])
|
||||||
failure = false;
|
failure = false;
|
||||||
} else {
|
} else {
|
||||||
// Error, now try read() with B key
|
// Error, now try read() with B key
|
||||||
// ERR ("Error: Read A");
|
if (res != NFC_ERFTRANS) {
|
||||||
|
nfc_perror (r.pdi, "nfc_initiator_mifare_cmd");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
mf_configure(r.pdi);
|
mf_configure(r.pdi);
|
||||||
mf_anticollision(t, r);
|
mf_anticollision(t, r);
|
||||||
memcpy(mp.mpa.abtKey, t.sectors[i].KeyB, sizeof(t.sectors[i].KeyB));
|
memcpy(mp.mpa.abtKey, t.sectors[i].KeyB, sizeof(t.sectors[i].KeyB));
|
||||||
if (!nfc_initiator_mifare_cmd(r.pdi, MC_AUTH_B, block, &mp)) {
|
if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_AUTH_B, block, &mp)) < 0) {
|
||||||
// ERR ("Error: Auth B");
|
if (res != NFC_EMFCAUTHFAIL) {
|
||||||
|
nfc_perror (r.pdi, "nfc_initiator_mifare_cmd");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
mf_configure(r.pdi);
|
mf_configure(r.pdi);
|
||||||
mf_anticollision(t, r);
|
mf_anticollision(t, r);
|
||||||
} else { // and Read
|
} else { // and Read
|
||||||
if (nfc_initiator_mifare_cmd(r.pdi, MC_READ, block, &mp)) {
|
if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_READ, block, &mp)) >= 0) {
|
||||||
fprintf(stdout, "Block %02d, type %c, key %012llx :", block, 'B', bytes_to_num(t.sectors[i].KeyB, 6));
|
fprintf(stdout, "Block %02d, type %c, key %012llx :", block, 'B', bytes_to_num(t.sectors[i].KeyB, 6));
|
||||||
print_hex(mp.mpd.abtData, 16);
|
print_hex(mp.mpd.abtData, 16);
|
||||||
mf_configure(r.pdi);
|
mf_configure(r.pdi);
|
||||||
mf_select_tag(r.pdi, &(t.nt));
|
mf_select_tag(r.pdi, &(t.nt));
|
||||||
failure = false;
|
failure = false;
|
||||||
} else {
|
} else {
|
||||||
|
if (res != NFC_ERFTRANS) {
|
||||||
|
nfc_perror (r.pdi, "nfc_initiator_mifare_cmd");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
mf_configure(r.pdi);
|
mf_configure(r.pdi);
|
||||||
mf_anticollision(t, r);
|
mf_anticollision(t, r);
|
||||||
// ERR ("Error: Read B");
|
// ERR ("Error: Read B");
|
||||||
|
|
68
src/mifare.c
68
src/mifare.c
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009 Roel Verdult
|
* Copyright (C) 2009 Roel Verdult
|
||||||
* Copyright (C) 2010 Romain Tartière
|
* Copyright (C) 2010 Romain Tartière
|
||||||
* Copyright (C) 2010, 2011 Romuald Conty
|
* Copyright (C) 2010, 2011, 2013 Romuald Conty
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
@ -28,10 +28,23 @@
|
||||||
* Note that this license only applies on the examples, NFC library itself is under LGPL
|
* Note that this license only applies on the examples, NFC library itself is under LGPL
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file mifare.c
|
* @file mifare.c
|
||||||
* @brief provide samples structs and functions to manipulate MIFARE Classic and Ultralight tags using libnfc
|
* @brief provide samples structs and functions to manipulate MIFARE Classic and Ultralight tags using libnfc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This implementation was written based on information provided by the
|
||||||
|
* following document:
|
||||||
|
*
|
||||||
|
* MIFARE Classic Specification
|
||||||
|
* MF1ICS50
|
||||||
|
* Functional specification
|
||||||
|
* Rev. 5.3 - 29 January 2008
|
||||||
|
* http://www.nxp.com/acrobat/other/identification/M001053_MF1ICS50_rev5_3.pdf
|
||||||
|
*/
|
||||||
|
|
||||||
#include "mifare.h"
|
#include "mifare.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -39,25 +52,33 @@
|
||||||
#include <nfc/nfc.h>
|
#include <nfc/nfc.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Execute a MIFARE Classic Command
|
* @brief Execute a MIFARE Classic command
|
||||||
* @return Returns true if action was successfully performed; otherwise returns false.
|
* @return Returns NFC_SUCCESS if action was successfully performed; otherwise returns error code (negative value).
|
||||||
* @param pmp Some commands need additional information. This information should be supplied in the mifare_param union.
|
* @param pmp Some commands need additional information. This information should be supplied in the mifare_param union.
|
||||||
*
|
*
|
||||||
* The specified MIFARE command will be executed on the tag. There are different commands possible, they all require the destination block number.
|
* The specified MIFARE command will be executed on the tag. There are
|
||||||
|
* different commands possible, they all require the destination block number.
|
||||||
|
*
|
||||||
* @note There are three different types of information (Authenticate, Data and Value).
|
* @note There are three different types of information (Authenticate, Data and Value).
|
||||||
*
|
*
|
||||||
* First an authentication must take place using Key A or B. It requires a 48 bit Key (6 bytes) and the UID.
|
* First an authentication must take place using Key A or B. It requires a 48 bit Key (6 bytes) and the UID.
|
||||||
* They are both used to initialize the internal cipher-state of the PN53X chip (http://libnfc.org/hardware/pn53x-chip).
|
|
||||||
* After a successful authentication it will be possible to execute other commands (e.g. Read/Write).
|
* After a successful authentication it will be possible to execute other commands (e.g. Read/Write).
|
||||||
* The MIFARE Classic Specification (http://www.nxp.com/acrobat/other/identification/M001053_MF1ICS50_rev5_3.pdf) explains more about this process.
|
*
|
||||||
|
* Like libnfc's functions, this one returns negative value on error (libnfc's
|
||||||
|
* error code) but two of them need a special attention in this context (MIFARE
|
||||||
|
* Classic):
|
||||||
|
* - NFC_EMFCAUTHFAIL, "MIFARE authentication failed", means key is not valid
|
||||||
|
* on specified sector.
|
||||||
|
* - NFC_ERFTRANS, "Invalid received frame", when occurs on MIFARE command
|
||||||
|
* read or write after a successful authentication, means permissions allowed
|
||||||
|
* by current acces bytes are not sufficient to process the command.
|
||||||
*/
|
*/
|
||||||
bool
|
int
|
||||||
nfc_initiator_mifare_cmd(nfc_device *pnd, const mifare_cmd mc, const uint8_t ui8Block, mifare_param *pmp)
|
nfc_initiator_mifare_cmd(nfc_device *pnd, const mifare_cmd mc, const uint8_t ui8Block, mifare_param *pmp)
|
||||||
{
|
{
|
||||||
uint8_t abtRx[265];
|
uint8_t abtRx[265];
|
||||||
size_t szParamLen;
|
size_t szParamLen;
|
||||||
uint8_t abtCmd[265];
|
uint8_t abtCmd[265];
|
||||||
//bool bEasyFraming;
|
|
||||||
|
|
||||||
abtCmd[0] = mc; // The MIFARE Classic command
|
abtCmd[0] = mc; // The MIFARE Classic command
|
||||||
abtCmd[1] = ui8Block; // The block address (1K=0x00..0x39, 4K=0x00..0xff)
|
abtCmd[1] = ui8Block; // The block address (1K=0x00..0x39, 4K=0x00..0xff)
|
||||||
|
@ -89,7 +110,7 @@ nfc_initiator_mifare_cmd(nfc_device *pnd, const mifare_cmd mc, const uint8_t ui8
|
||||||
|
|
||||||
// Please fix your code, you never should reach this statement
|
// Please fix your code, you never should reach this statement
|
||||||
default:
|
default:
|
||||||
return false;
|
return NFC_EINVARG;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,40 +119,23 @@ nfc_initiator_mifare_cmd(nfc_device *pnd, const mifare_cmd mc, const uint8_t ui8
|
||||||
memcpy(abtCmd + 2, (uint8_t *) pmp, szParamLen);
|
memcpy(abtCmd + 2, (uint8_t *) pmp, szParamLen);
|
||||||
|
|
||||||
// FIXME: Save and restore bEasyFraming
|
// FIXME: Save and restore bEasyFraming
|
||||||
// bEasyFraming = nfc_device_get_property_bool (pnd, NP_EASY_FRAMING, &bEasyFraming);
|
int res;
|
||||||
if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, true) < 0) {
|
if ((res = nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, true)) < 0) {
|
||||||
nfc_perror(pnd, "nfc_device_set_property_bool");
|
return res;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
// Fire the mifare command
|
// Fire the mifare command
|
||||||
int res;
|
|
||||||
if ((res = nfc_initiator_transceive_bytes(pnd, abtCmd, 2 + szParamLen, abtRx, sizeof(abtRx), -1)) < 0) {
|
if ((res = nfc_initiator_transceive_bytes(pnd, abtCmd, 2 + szParamLen, abtRx, sizeof(abtRx), -1)) < 0) {
|
||||||
if (res == NFC_ERFTRANS) {
|
return res;
|
||||||
// "Invalid received frame", usual means we are
|
|
||||||
// authenticated on a sector but the requested MIFARE cmd (read, write)
|
|
||||||
// is not permitted by current acces bytes;
|
|
||||||
// So there is nothing to do here.
|
|
||||||
} else {
|
|
||||||
nfc_perror(pnd, "nfc_initiator_transceive_bytes");
|
|
||||||
}
|
|
||||||
// XXX nfc_device_set_property_bool (pnd, NP_EASY_FRAMING, bEasyFraming);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
/* XXX
|
|
||||||
if (nfc_device_set_property_bool (pnd, NP_EASY_FRAMING, bEasyFraming) < 0) {
|
|
||||||
nfc_perror (pnd, "nfc_device_set_property_bool");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// When we have executed a read command, copy the received bytes into the param
|
// When we have executed a read command, copy the received bytes into the param
|
||||||
if (mc == MC_READ) {
|
if (mc == MC_READ) {
|
||||||
if (res == 16) {
|
if (res == 16) {
|
||||||
memcpy(pmp->mpd.abtData, abtRx, 16);
|
memcpy(pmp->mpd.abtData, abtRx, 16);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return NFC_EINVARG;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Command succesfully executed
|
// Command succesfully executed
|
||||||
return true;
|
return NFC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
10
src/mifare.h
10
src/mifare.h
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009 Roel Verdult
|
* Copyright (C) 2009 Roel Verdult
|
||||||
* Copyright (C) 2010 Romain Tartière
|
* Copyright (C) 2010 Romain Tartière
|
||||||
* Copyright (C) 2010, 2011 Romuald Conty
|
* Copyright (C) 2010, 2011, 2013 Romuald Conty
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
@ -35,12 +35,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LIBNFC_MIFARE_H_
|
#ifndef _LIBNFC_MIFARE_H_
|
||||||
# define _LIBNFC_MIFARE_H_
|
#define _LIBNFC_MIFARE_H_
|
||||||
|
|
||||||
# include <nfc/nfc-types.h>
|
#include <nfc/nfc-types.h>
|
||||||
|
|
||||||
// Compiler directive, set struct alignment to 1 uint8_t for compatibility
|
// Compiler directive, set struct alignment to 1 uint8_t for compatibility
|
||||||
# pragma pack(1)
|
#pragma pack(1)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MC_AUTH_A = 0x60,
|
MC_AUTH_A = 0x60,
|
||||||
|
@ -76,7 +76,7 @@ typedef union {
|
||||||
// Reset struct alignment to default
|
// Reset struct alignment to default
|
||||||
# pragma pack()
|
# pragma pack()
|
||||||
|
|
||||||
bool nfc_initiator_mifare_cmd(nfc_device *pnd, const mifare_cmd mc, const uint8_t ui8Block, mifare_param *pmp);
|
int nfc_initiator_mifare_cmd(nfc_device *pnd, const mifare_cmd mc, const uint8_t ui8Block, mifare_param *pmp);
|
||||||
|
|
||||||
// Compiler directive, set struct alignment to 1 uint8_t for compatibility
|
// Compiler directive, set struct alignment to 1 uint8_t for compatibility
|
||||||
# pragma pack(1)
|
# pragma pack(1)
|
||||||
|
|
Loading…
Reference in a new issue