http://nfc-tools.org/index.php/Libnfc:APDU_example
Contents[hide] |
Short example illustrating how to exchange APDUs with a ISO14443-4 tag
It can be downloaded here as apdu_example.c.
apdu_example.c
#include <stdlib.h>
#include <string.h>
#include <nfc/nfc.h>
To send APDUs, we'll use a little helper function with some debugging prints of exchanged APDUs:
int
CardTransmit(nfc_device *pnd, uint8_t * capdu, size_t capdulen, uint8_t * rapdu, size_t * rapdulen)
{
int res;
size_t szPos;
printf("=> ");
for (szPos = 0; szPos < capdulen; szPos++) {
printf("%02x ", capdu[szPos]);
}
printf("\n");
if ((res = nfc_initiator_transceive_bytes(pnd, capdu, capdulen, rapdu, *rapdulen, 500)) < 0) {
return -1;
} else {
*rapdulen = (size_t) res;
printf("<= ");
for (szPos = 0; szPos < *rapdulen; szPos++) {
printf("%02x ", rapdu[szPos]);
}
printf("\n");
return 0;
}
}
Start of main() is very similar to quick_start_example:
int
main(int argc, const char *argv[])
{
nfc_device *pnd;
nfc_target nt;
nfc_context *context;
nfc_init(&context);
if (context == NULL) {
printf("Unable to init libnfc (malloc)\n");
exit(EXIT_FAILURE);
}
const char *acLibnfcVersion = nfc_version();
(void)argc;
printf("%s uses libnfc %s\n", argv[0], acLibnfcVersion);
pnd = nfc_open(context, NULL);
if (pnd == NULL) {
printf("ERROR: %s", "Unable to open NFC device.");
exit(EXIT_FAILURE);
}
if (nfc_initiator_init(pnd) < 0) {
nfc_perror(pnd, "nfc_initiator_init");
exit(EXIT_FAILURE);
}
printf("NFC reader: %s opened\n", nfc_device_get_name(pnd));
const nfc_modulation nmMifare = {
.nmt = NMT_ISO14443A,
.nbr = NBR_106,
};
Smartcards need to get RATS, so make sure NP_AUTO_ISO14443_4 is set to true, which is its default value, otherwise if e.g. you were doing some MIFARE stuff before, set it explicitly:
// nfc_set_property_bool(pnd, NP_AUTO_ISO14443_4, true);
Polling for target... indefinitely
printf("Polling for target...\n");
while (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0);
printf("Target detected!\n");
Now we can exchange APDUs, here we're reading a NFC-Forum Type4 Tag
uint8_t capdu[264];
size_t capdulen;
uint8_t rapdu[264];
size_t rapdulen;
// Select application
memcpy(capdu, "\x00\xA4\x04\x00\x07\xd2\x76\x00\x00\x85\x01\x00", 12);
capdulen=12;
rapdulen=sizeof(rapdu);
if (CardTransmit(pnd, capdu, capdulen, rapdu, &rapdulen) < 0)
exit(EXIT_FAILURE);
if (rapdulen < 2 || rapdu[rapdulen-2] != 0x90 || rapdu[rapdulen-1] != 0x00)
exit(EXIT_FAILURE);
printf("Application selected!\n");
// Select Capability Container
memcpy(capdu, "\x00\xa4\x00\x0c\x02\xe1\x03", 7);
capdulen=7;
rapdulen=sizeof(rapdu);
if (CardTransmit(pnd, capdu, capdulen, rapdu, &rapdulen) < 0)
exit(EXIT_FAILURE);
if (rapdulen < 2 || rapdu[rapdulen-2] != 0x90 || rapdu[rapdulen-1] != 0x00) {
capdu[3]='\x00'; // Maybe an older Tag4 ?
if (CardTransmit(pnd, capdu, capdulen, rapdu, &rapdulen) < 0)
exit(EXIT_FAILURE);
}
printf("Capability Container selected!\n");
// Read Capability Container
memcpy(capdu, "\x00\xb0\x00\x00\x0f", 5);
capdulen=5;
rapdulen=sizeof(rapdu);
if (CardTransmit(pnd, capdu, capdulen, rapdu, &rapdulen) < 0)
exit(EXIT_FAILURE);
if (rapdulen < 2 || rapdu[rapdulen-2] != 0x90 || rapdu[rapdulen-1] != 0x00)
exit(EXIT_FAILURE);
printf("Capability Container header:\n");
size_t szPos;
for (szPos = 0; szPos < rapdulen-2; szPos++) {
printf("%02x ", rapdu[szPos]);
}
printf("\n");
We're done!
nfc_close(pnd);
nfc_exit(context);
exit(EXIT_SUCCESS);
}
To compile it
It assumes libnfc is installed into the system
gcc -o apdu_example apdu_example.c -lnfc
Testing...
$ ./apdu_example
./apdu_example uses libnfc libnfc-1.7.0-43-ga1ef329
NFC reader: SCM Micro / SCL3711-NFC&RW opened
Polling for target...
Target detected!
=> 00 a4 04 00 07 d2 76 00 00 85 01 00
<= 90 00
Application selected!
=> 00 a4 00 0c 02 e1 03
<= 6a 86
=> 00 a4 00 00 02 e1 03
<= 90 00
Capability Container selected!
=> 00 b0 00 00 0f
<= 00 0f 10 00 3b 00 34 04 06 e1 04 0e e0 00 ff 90 00
Capability Container header:
00 0f 10 00 3b 00 34 04 06 e1 04 0e e0 00 ff