mirror of
https://github.com/brmlab/brmdoor_libnfc.git
synced 2025-06-08 16:36:25 +02:00
Reading NDEF from Desfire
This commit is contained in:
parent
dd37e20a02
commit
8dad9a5cc4
2 changed files with 118 additions and 1 deletions
|
@ -1,9 +1,10 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <nfc/nfc.h>
|
#include <nfc/nfc.h>
|
||||||
#include <nfc/nfc-types.h>
|
#include <nfc/nfc-types.h>
|
||||||
|
#include <freefare.h>
|
||||||
|
|
||||||
#include "nfc_smartcard.h"
|
#include "nfc_smartcard.h"
|
||||||
|
|
||||||
|
@ -149,6 +150,113 @@ ResponseAPDU NFCDevice::sendAPDU(const string &apdu) throw(NFCError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string NFCDevice::readDesfireNDEF() throw(NFCError)
|
||||||
|
{
|
||||||
|
uint8_t key_data_app[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; //auth key
|
||||||
|
int res;
|
||||||
|
uint16_t ndef_msg_len;
|
||||||
|
|
||||||
|
std::unique_ptr<MifareTag, std::function<void(MifareTag*)> > tags = {freefare_get_tags (_nfcDevice), freefare_free_tags};
|
||||||
|
if (!tags) {
|
||||||
|
throw NFCError("No tags detected");
|
||||||
|
}
|
||||||
|
MifareTag& tag = *tags; //only first one is used
|
||||||
|
|
||||||
|
if (DESFIRE != freefare_get_tag_type (tag)) {
|
||||||
|
throw NFCError("Tag is not a Desfire tag");
|
||||||
|
}
|
||||||
|
|
||||||
|
res = mifare_desfire_connect (tag);
|
||||||
|
if (res < 0) {
|
||||||
|
throw NFCError("Can't connect to Mifare DESFire target.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// We've to track DESFire version as NDEF mapping is different
|
||||||
|
struct mifare_desfire_version_info info;
|
||||||
|
res = mifare_desfire_get_version (tag, &info);
|
||||||
|
if (res < 0) {
|
||||||
|
throw NFCError("Error getting Desfire version");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<mifare_desfire_key, std::function<void(MifareDESFireKey)> > key_app{mifare_desfire_des_key_new_with_version (key_data_app),
|
||||||
|
mifare_desfire_key_free};
|
||||||
|
|
||||||
|
// Mifare DESFire SelectApplication (Select application)
|
||||||
|
MifareDESFireAID aid;
|
||||||
|
if (info.software.version_major==0) {
|
||||||
|
aid = mifare_desfire_aid_new(0xEEEE10);
|
||||||
|
} else {
|
||||||
|
// There is no more relationship between DESFire AID and ISO AID...
|
||||||
|
// Let's assume it's in AID 000001h as proposed in the spec
|
||||||
|
aid = mifare_desfire_aid_new(0x000001);
|
||||||
|
}
|
||||||
|
|
||||||
|
res = mifare_desfire_select_application(tag, aid);
|
||||||
|
if (res < 0)
|
||||||
|
throw NFCError("Application selection failed. NDEF message might not have been created yet.");
|
||||||
|
free (aid);
|
||||||
|
|
||||||
|
// Authentication with NDEF Tag Application master key (Authentication with key 0)
|
||||||
|
res = mifare_desfire_authenticate (tag, 0, key_app.get());
|
||||||
|
if (res < 0)
|
||||||
|
throw NFCError("Authentication with NDEF Tag Application master key failed");
|
||||||
|
|
||||||
|
// Read Capability Container file E103
|
||||||
|
uint8_t lendata[20]; // cf FIXME in mifare_desfire.c read_data()
|
||||||
|
if (info.software.version_major==0)
|
||||||
|
res = mifare_desfire_read_data (tag, 0x03, 0, 2, lendata);
|
||||||
|
else
|
||||||
|
// There is no more relationship between DESFire FID and ISO FileID...
|
||||||
|
// Let's assume it's in FID 01h as proposed in the spec
|
||||||
|
res = mifare_desfire_read_data (tag, 0x01, 0, 2, lendata);
|
||||||
|
if (res < 0)
|
||||||
|
throw NFCError("Read CC len failed");
|
||||||
|
uint16_t cclen = (((uint16_t) lendata[0]) << 8) + ((uint16_t) lendata[1]);
|
||||||
|
if (cclen < 15)
|
||||||
|
throw NFCError("CC too short IMHO");
|
||||||
|
std::unique_ptr<uint8_t[]> cc_data{new uint8_t[cclen+20]};
|
||||||
|
if (info.software.version_major==0)
|
||||||
|
res = mifare_desfire_read_data (tag, 0x03, 0, cclen, cc_data.get());
|
||||||
|
else
|
||||||
|
res = mifare_desfire_read_data (tag, 0x01, 0, cclen, cc_data.get());
|
||||||
|
if (res < 0)
|
||||||
|
throw NFCError("Read CC data failed");
|
||||||
|
// Search NDEF File Control TLV
|
||||||
|
uint8_t off = 7;
|
||||||
|
while (((off+7) < cclen) && (cc_data[off] != 0x04)) {
|
||||||
|
// Skip TLV
|
||||||
|
off += cc_data[off+1] + 2;
|
||||||
|
}
|
||||||
|
if (off+7 >= cclen)
|
||||||
|
throw NFCError("CC does not contain expected NDEF File Control TLV");
|
||||||
|
if (cc_data[off+2] != 0xE1)
|
||||||
|
throw NFCError("Unknown NDEF File reference in CC");
|
||||||
|
uint8_t file_no;
|
||||||
|
if (info.software.version_major==0)
|
||||||
|
file_no = cc_data[off+3];
|
||||||
|
else
|
||||||
|
// There is no more relationship between DESFire FID and ISO FileID...
|
||||||
|
// Let's assume it's in FID 02h as proposed in the spec
|
||||||
|
file_no = 2;
|
||||||
|
uint16_t ndefmaxlen = (((uint16_t) cc_data[off+4]) << 8) + ((uint16_t) cc_data[off+5]);
|
||||||
|
std::unique_ptr<uint8_t[]> ndef_msg{new uint8_t[ndefmaxlen+20]}; // cf FIXME in mifare_desfire.c read_data()
|
||||||
|
|
||||||
|
res = mifare_desfire_read_data (tag, file_no, 0, 2, lendata);
|
||||||
|
if (res < 0)
|
||||||
|
throw NFCError("Read NDEF len failed");
|
||||||
|
ndef_msg_len = (((uint16_t) lendata[0]) << 8) + ((uint16_t) lendata[1]);
|
||||||
|
if (ndef_msg_len + 2 > ndefmaxlen)
|
||||||
|
throw NFCError("Declared NDEF size larger than max NDEF size");
|
||||||
|
res = mifare_desfire_read_data (tag, file_no, 2, ndef_msg_len, ndef_msg.get());
|
||||||
|
if (res < 0)
|
||||||
|
throw NFCError("Read data failed");
|
||||||
|
std::string result{(char*)ndef_msg.get(), ndef_msg_len};
|
||||||
|
|
||||||
|
mifare_desfire_disconnect (tag);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const nfc_modulation NFCDevice::_modulations[5] = {
|
const nfc_modulation NFCDevice::_modulations[5] = {
|
||||||
{ /*.nmt = */ NMT_ISO14443A, /* .nbr = */ NBR_106 }
|
{ /*.nmt = */ NMT_ISO14443A, /* .nbr = */ NBR_106 }
|
||||||
//{ /*.nmt = */ NMT_ISO14443B, /* .nbr = */ NBR_106 },
|
//{ /*.nmt = */ NMT_ISO14443B, /* .nbr = */ NBR_106 },
|
||||||
|
|
|
@ -118,9 +118,18 @@ public:
|
||||||
*
|
*
|
||||||
* @param apdu command APDU to send
|
* @param apdu command APDU to send
|
||||||
* @param returns response APDU received from target
|
* @param returns response APDU received from target
|
||||||
|
* @throws NFCError if response APDU is too long or couldn't send APDU
|
||||||
*/
|
*/
|
||||||
ResponseAPDU sendAPDU(const std::string& apdu) throw(NFCError);
|
ResponseAPDU sendAPDU(const std::string& apdu) throw(NFCError);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read NDEF message from Desfire.
|
||||||
|
*
|
||||||
|
* @returns NDEF message or empty string if there wasn't message
|
||||||
|
* @throws NFCError if there was problem communication with card or couldn't authenticate
|
||||||
|
*/
|
||||||
|
std::string readDesfireNDEF() throw(NFCError);
|
||||||
|
|
||||||
/** Open device explicitly. May be useful after explicit close */
|
/** Open device explicitly. May be useful after explicit close */
|
||||||
void open() throw(NFCError);
|
void open() throw(NFCError);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue