Libnfc:APDU example
From NFC Tools
Contents |
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