libnfc 1.8.0
nfc-relay-picc.c
Go to the documentation of this file.
1/*-
2 * Free/Libre Near Field Communication (NFC) library
3 *
4 * Libnfc historical contributors:
5 * Copyright (C) 2009 Roel Verdult
6 * Copyright (C) 2009-2013 Romuald Conty
7 * Copyright (C) 2010-2012 Romain Tartière
8 * Copyright (C) 2010-2013 Philippe Teuwen
9 * Copyright (C) 2012-2013 Ludovic Rousseau
10 * See AUTHORS file for a more comprehensive list of contributors.
11 * Additional contributors of this file:
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are met:
15 * 1) Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 * 2 )Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 *
33 * Note that this license only applies on the examples, NFC library itself is under LGPL
34 *
35 */
36
42// Notes & differences with nfc-relay:
43// - This example only works with PN532 because it relies on
44// its internal handling of ISO14443-4 specificities.
45// - Thanks to this internal handling & injection of WTX frames,
46// this example works on readers very strict on timing
47
48#ifdef HAVE_CONFIG_H
49# include "config.h"
50#endif /* HAVE_CONFIG_H */
51
52#include <inttypes.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <stdint.h>
56#include <string.h>
57#include <signal.h>
58
59#include <unistd.h>
60
61#include <nfc/nfc.h>
62
63#include "nfc-utils.h"
64
65#define MAX_FRAME_LEN 264
66#define MAX_DEVICE_COUNT 2
67
68static uint8_t abtCapdu[MAX_FRAME_LEN];
69static size_t szCapduLen;
70static uint8_t abtRapdu[MAX_FRAME_LEN];
71static size_t szRapduLen;
72static nfc_device *pndInitiator;
73static nfc_device *pndTarget;
74static bool quitting = false;
75static bool quiet_output = false;
76static bool initiator_only_mode = false;
77static bool target_only_mode = false;
78static bool swap_devices = false;
79static unsigned int waiting_time = 0;
80FILE *fd3;
81FILE *fd4;
82
83static void
84intr_hdlr(int sig)
85{
86 (void) sig;
87 printf("\nQuitting...\n");
88 printf("Please send a last command to the emulator to quit properly.\n");
89 quitting = true;
90 return;
91}
92
93static void
94print_usage(char *argv[])
95{
96 printf("Usage: %s [OPTIONS]\n", argv[0]);
97 printf("Options:\n");
98 printf("\t-h\tHelp. Print this message.\n");
99 printf("\t-q\tQuiet mode. Suppress printing of relayed data (improves timing).\n");
100 printf("\t-t\tTarget mode only (the one on reader side). Data expected from FD3 to FD4.\n");
101 printf("\t-i\tInitiator mode only (the one on tag side). Data expected from FD3 to FD4.\n");
102 printf("\t-s\tSwap roles of found devices.\n");
103 printf("\t-n N\tAdds a waiting time of N seconds (integer) in the relay to mimic long distance.\n");
104}
105
106static int print_hex_fd4(const uint8_t *pbtData, const size_t szBytes, const char *pchPrefix)
107{
108 size_t szPos;
109 if (szBytes > MAX_FRAME_LEN) {
110 return -1;
111 }
112 if (fprintf(fd4, "#%s %04" PRIxPTR ": ", pchPrefix, szBytes) < 0) {
113 return -1;
114 }
115
116 for (szPos = 0; szPos < szBytes; szPos++) {
117 if (fprintf(fd4, "%02x ", pbtData[szPos]) < 0) {
118 return -1;
119 }
120 }
121 if (fprintf(fd4, "\n") < 0) {
122 return -1;
123 }
124 fflush(fd4);
125 return 0;
126}
127
128static int scan_hex_fd3(uint8_t *pbtData, size_t *pszBytes, const char *pchPrefix)
129{
130 size_t szPos;
131 unsigned int uiBytes;
132 unsigned int uiData;
133 char pchScan[256];
134 int c;
135 // Look for our next sync marker
136 while ((c = fgetc(fd3)) != '#') {
137 if (c == EOF) {
138 return -1;
139 }
140 }
141 strncpy(pchScan, pchPrefix, 250);
142 pchScan[sizeof(pchScan) - 1] = '\0';
143 strcat(pchScan, " %04x:");
144 if (fscanf(fd3, pchScan, &uiBytes) < 1) {
145 return -1;
146 }
147 *pszBytes = uiBytes;
148 if (*pszBytes > MAX_FRAME_LEN) {
149 return -1;
150 }
151 for (szPos = 0; szPos < *pszBytes; szPos++) {
152 if (fscanf(fd3, "%02x", &uiData) < 1) {
153 return -1;
154 }
155 pbtData[szPos] = uiData;
156 }
157 return 0;
158}
159
160int
161main(int argc, char *argv[])
162{
163 int arg;
164 const char *acLibnfcVersion = nfc_version();
165 nfc_target ntRealTarget;
166
167 // Get commandline options
168 for (arg = 1; arg < argc; arg++) {
169 if (0 == strcmp(argv[arg], "-h")) {
170 print_usage(argv);
171 exit(EXIT_SUCCESS);
172 } else if (0 == strcmp(argv[arg], "-q")) {
173 quiet_output = true;
174 } else if (0 == strcmp(argv[arg], "-t")) {
175 printf("INFO: %s\n", "Target mode only.");
176 initiator_only_mode = false;
177 target_only_mode = true;
178 } else if (0 == strcmp(argv[arg], "-i")) {
179 printf("INFO: %s\n", "Initiator mode only.");
180 initiator_only_mode = true;
181 target_only_mode = false;
182 } else if (0 == strcmp(argv[arg], "-s")) {
183 printf("INFO: %s\n", "Swapping devices.");
184 swap_devices = true;
185 } else if (0 == strcmp(argv[arg], "-n")) {
186 if (++arg == argc || (sscanf(argv[arg], "%10u", &waiting_time) < 1)) {
187 ERR("Missing or wrong waiting time value: %s.", argv[arg]);
188 print_usage(argv);
189 exit(EXIT_FAILURE);
190 }
191 printf("Waiting time: %u secs.\n", waiting_time);
192 } else {
193 ERR("%s is not supported option.", argv[arg]);
194 print_usage(argv);
195 exit(EXIT_FAILURE);
196 }
197 }
198
199 // Display libnfc version
200 printf("%s uses libnfc %s\n", argv[0], acLibnfcVersion);
201
202#ifdef WIN32
203 signal(SIGINT, (void (__cdecl *)(int)) intr_hdlr);
204#else
205 signal(SIGINT, intr_hdlr);
206#endif
207
208 nfc_context *context;
209 nfc_init(&context);
210 if (context == NULL) {
211 ERR("Unable to init libnfc (malloc)");
212 exit(EXIT_FAILURE);
213 }
214
215 nfc_connstring connstrings[MAX_DEVICE_COUNT];
216 // List available devices
217 size_t szFound = nfc_list_devices(context, connstrings, MAX_DEVICE_COUNT);
218
219 if (initiator_only_mode || target_only_mode) {
220 if (szFound < 1) {
221 ERR("No device found");
222 nfc_exit(context);
223 exit(EXIT_FAILURE);
224 }
225 if ((fd3 = fdopen(3, "r")) == NULL) {
226 ERR("Could not open file descriptor 3");
227 nfc_exit(context);
228 exit(EXIT_FAILURE);
229 }
230 if ((fd4 = fdopen(4, "w")) == NULL) {
231 ERR("Could not open file descriptor 4");
232 nfc_exit(context);
233 exit(EXIT_FAILURE);
234 }
235 } else {
236 if (szFound < 2) {
237 ERR("%" PRIdPTR " device found but two opened devices are needed to relay NFC.", szFound);
238 nfc_exit(context);
239 exit(EXIT_FAILURE);
240 }
241 }
242
243 if (!target_only_mode) {
244 // Try to open the NFC reader used as initiator
245 // Little hack to allow using initiator no matter if
246 // there is already a target used locally or not on the same machine:
247 // if there is more than one readers opened we open the second reader
248 // (we hope they're always detected in the same order)
249 if ((szFound == 1) || swap_devices) {
250 pndInitiator = nfc_open(context, connstrings[0]);
251 } else {
252 pndInitiator = nfc_open(context, connstrings[1]);
253 }
254
255 if (pndInitiator == NULL) {
256 printf("Error opening NFC reader\n");
257 nfc_exit(context);
258 exit(EXIT_FAILURE);
259 }
260
261 printf("NFC reader device: %s opened\n", nfc_device_get_name(pndInitiator));
262
263 if (nfc_initiator_init(pndInitiator) < 0) {
264 printf("Error: fail initializing initiator\n");
265 nfc_close(pndInitiator);
266 nfc_exit(context);
267 exit(EXIT_FAILURE);
268 }
269
270 // Try to find a ISO 14443-4A tag
271 nfc_modulation nm = {
272 .nmt = NMT_ISO14443A,
273 .nbr = NBR_106,
274 };
275 if (nfc_initiator_select_passive_target(pndInitiator, nm, NULL, 0, &ntRealTarget) <= 0) {
276 printf("Error: no tag was found\n");
277 nfc_close(pndInitiator);
278 nfc_exit(context);
279 exit(EXIT_FAILURE);
280 }
281
282 printf("Found tag:\n");
283 print_nfc_target(&ntRealTarget, false);
284 if (initiator_only_mode) {
285 if (print_hex_fd4(ntRealTarget.nti.nai.abtUid, ntRealTarget.nti.nai.szUidLen, "UID") < 0) {
286 fprintf(stderr, "Error while printing UID to FD4\n");
287 nfc_close(pndInitiator);
288 nfc_exit(context);
289 exit(EXIT_FAILURE);
290 }
291 if (print_hex_fd4(ntRealTarget.nti.nai.abtAtqa, 2, "ATQA") < 0) {
292 fprintf(stderr, "Error while printing ATQA to FD4\n");
293 nfc_close(pndInitiator);
294 nfc_exit(context);
295 exit(EXIT_FAILURE);
296 }
297 if (print_hex_fd4(&(ntRealTarget.nti.nai.btSak), 1, "SAK") < 0) {
298 fprintf(stderr, "Error while printing SAK to FD4\n");
299 nfc_close(pndInitiator);
300 nfc_exit(context);
301 exit(EXIT_FAILURE);
302 }
303 if (print_hex_fd4(ntRealTarget.nti.nai.abtAts, ntRealTarget.nti.nai.szAtsLen, "ATS") < 0) {
304 fprintf(stderr, "Error while printing ATS to FD4\n");
305 nfc_close(pndInitiator);
306 nfc_exit(context);
307 exit(EXIT_FAILURE);
308 }
309 }
310 }
311 if (initiator_only_mode) {
312 printf("Hint: tag <---> *INITIATOR* (relay) <-FD3/FD4-> target (relay) <---> original reader\n\n");
313 } else if (target_only_mode) {
314 printf("Hint: tag <---> initiator (relay) <-FD3/FD4-> *TARGET* (relay) <---> original reader\n\n");
315 } else {
316 printf("Hint: tag <---> initiator (relay) <---> target (relay) <---> original reader\n\n");
317 }
318 if (!initiator_only_mode) {
319 nfc_target ntEmulatedTarget = {
320 .nm = {
321 .nmt = NMT_ISO14443A,
322 .nbr = NBR_106,
323 },
324 };
325 if (target_only_mode) {
326 size_t foo;
327 if (scan_hex_fd3(ntEmulatedTarget.nti.nai.abtUid, &(ntEmulatedTarget.nti.nai.szUidLen), "UID") < 0) {
328 fprintf(stderr, "Error while scanning UID from FD3\n");
329 nfc_close(pndInitiator);
330 nfc_exit(context);
331 exit(EXIT_FAILURE);
332 }
333 if (scan_hex_fd3(ntEmulatedTarget.nti.nai.abtAtqa, &foo, "ATQA") < 0) {
334 fprintf(stderr, "Error while scanning ATQA from FD3\n");
335 nfc_close(pndInitiator);
336 nfc_exit(context);
337 exit(EXIT_FAILURE);
338 }
339 if (scan_hex_fd3(&(ntEmulatedTarget.nti.nai.btSak), &foo, "SAK") < 0) {
340 fprintf(stderr, "Error while scanning SAK from FD3\n");
341 nfc_close(pndInitiator);
342 nfc_exit(context);
343 exit(EXIT_FAILURE);
344 }
345 if (scan_hex_fd3(ntEmulatedTarget.nti.nai.abtAts, &(ntEmulatedTarget.nti.nai.szAtsLen), "ATS") < 0) {
346 fprintf(stderr, "Error while scanning ATS from FD3\n");
347 nfc_close(pndInitiator);
348 nfc_exit(context);
349 exit(EXIT_FAILURE);
350 }
351 } else {
352 ntEmulatedTarget.nti = ntRealTarget.nti;
353 }
354 // We can only emulate a short UID, so fix length & ATQA bit:
355 ntEmulatedTarget.nti.nai.szUidLen = 4;
356 ntEmulatedTarget.nti.nai.abtAtqa[1] &= (0xFF - 0x40);
357 // First byte of UID is always automatically replaced by 0x08 in this mode anyway
358 ntEmulatedTarget.nti.nai.abtUid[0] = 0x08;
359 // ATS is always automatically replaced by PN532, we've no control on it:
360 // ATS = (05) 75 33 92 03
361 // (TL) T0 TA TB TC
362 // | | | +-- CID supported, NAD supported
363 // | | +----- FWI=9 SFGI=2 => FWT=154ms, SFGT=1.21ms
364 // | +-------- DR=2,4 DS=2,4 => supports 106, 212 & 424bps in both directions
365 // +----------- TA,TB,TC, FSCI=5 => FSC=64
366 // It seems hazardous to tell we support NAD if the tag doesn't support NAD but I don't know how to disable it
367 // PC/SC pseudo-ATR = 3B 80 80 01 01 if there is no historical bytes
368
369 // Creates ATS and copy max 48 bytes of Tk:
370 uint8_t *pbtTk;
371 size_t szTk;
372 pbtTk = iso14443a_locate_historical_bytes(ntEmulatedTarget.nti.nai.abtAts, ntEmulatedTarget.nti.nai.szAtsLen, &szTk);
373 szTk = (szTk > 48) ? 48 : szTk;
374 uint8_t pbtTkt[48];
375 memcpy(pbtTkt, pbtTk, szTk);
376 ntEmulatedTarget.nti.nai.abtAts[0] = 0x75;
377 ntEmulatedTarget.nti.nai.abtAts[1] = 0x33;
378 ntEmulatedTarget.nti.nai.abtAts[2] = 0x92;
379 ntEmulatedTarget.nti.nai.abtAts[3] = 0x03;
380 ntEmulatedTarget.nti.nai.szAtsLen = 4 + szTk;
381 memcpy(&(ntEmulatedTarget.nti.nai.abtAts[4]), pbtTkt, szTk);
382
383 printf("We will emulate:\n");
384 print_nfc_target(&ntEmulatedTarget, false);
385
386 // Try to open the NFC emulator device
387 if (swap_devices) {
388 pndTarget = nfc_open(context, connstrings[1]);
389 } else {
390 pndTarget = nfc_open(context, connstrings[0]);
391 }
392 if (pndTarget == NULL) {
393 printf("Error opening NFC emulator device\n");
394 if (!target_only_mode) {
395 nfc_close(pndInitiator);
396 }
397 nfc_exit(context);
398 exit(EXIT_FAILURE);
399 }
400
401 printf("NFC emulator device: %s opened\n", nfc_device_get_name(pndTarget));
402 if (nfc_target_init(pndTarget, &ntEmulatedTarget, abtCapdu, sizeof(abtCapdu), 0) < 0) {
403 ERR("%s", "Initialization of NFC emulator failed");
404 if (!target_only_mode) {
405 nfc_close(pndInitiator);
406 }
407 nfc_close(pndTarget);
408 nfc_exit(context);
409 exit(EXIT_FAILURE);
410 }
411 printf("%s\n", "Done, relaying frames now!");
412 }
413
414 while (!quitting) {
415 bool ret;
416 int res = 0;
417 if (!initiator_only_mode) {
418 // Receive external reader command through target
419 if ((res = nfc_target_receive_bytes(pndTarget, abtCapdu, sizeof(abtCapdu), 0)) < 0) {
420 nfc_perror(pndTarget, "nfc_target_receive_bytes");
421 if (!target_only_mode) {
422 nfc_close(pndInitiator);
423 }
424 nfc_close(pndTarget);
425 nfc_exit(context);
426 exit(EXIT_FAILURE);
427 }
428 szCapduLen = (size_t) res;
429 if (target_only_mode) {
430 if (print_hex_fd4(abtCapdu, szCapduLen, "C-APDU") < 0) {
431 fprintf(stderr, "Error while printing C-APDU to FD4\n");
432 nfc_close(pndTarget);
433 nfc_exit(context);
434 exit(EXIT_FAILURE);
435 }
436 }
437 } else {
438 if (scan_hex_fd3(abtCapdu, &szCapduLen, "C-APDU") < 0) {
439 fprintf(stderr, "Error while scanning C-APDU from FD3\n");
440 nfc_close(pndInitiator);
441 nfc_exit(context);
442 exit(EXIT_FAILURE);
443 }
444 }
445 // Show transmitted response
446 if (!quiet_output) {
447 printf("Forwarding C-APDU: ");
448 print_hex(abtCapdu, szCapduLen);
449 }
450
451 if (!target_only_mode) {
452 // Forward the frame to the original tag
453 if ((res = nfc_initiator_transceive_bytes(pndInitiator, abtCapdu, szCapduLen, abtRapdu, sizeof(abtRapdu), -1)) < 0) {
454 ret = false;
455 } else {
456 szRapduLen = (size_t) res;
457 ret = true;
458 }
459 } else {
460 if (scan_hex_fd3(abtRapdu, &szRapduLen, "R-APDU") < 0) {
461 fprintf(stderr, "Error while scanning R-APDU from FD3\n");
462 nfc_close(pndTarget);
463 nfc_exit(context);
464 exit(EXIT_FAILURE);
465 }
466 ret = true;
467 }
468 if (ret) {
469 // Redirect the answer back to the external reader
470 if (waiting_time != 0) {
471 if (!quiet_output) {
472 printf("Waiting %us to simulate longer relay...\n", waiting_time);
473 }
474 sleep(waiting_time);
475 }
476 // Show transmitted response
477 if (!quiet_output) {
478 printf("Forwarding R-APDU: ");
479 print_hex(abtRapdu, szRapduLen);
480 }
481 if (!initiator_only_mode) {
482 // Transmit the response bytes
483 if (nfc_target_send_bytes(pndTarget, abtRapdu, szRapduLen, 0) < 0) {
484 nfc_perror(pndTarget, "nfc_target_send_bytes");
485 if (!target_only_mode) {
486 nfc_close(pndInitiator);
487 }
488 if (!initiator_only_mode) {
489 nfc_close(pndTarget);
490 }
491 nfc_exit(context);
492 exit(EXIT_FAILURE);
493 }
494 } else {
495 if (print_hex_fd4(abtRapdu, szRapduLen, "R-APDU") < 0) {
496 fprintf(stderr, "Error while printing R-APDU to FD4\n");
497 nfc_close(pndInitiator);
498 nfc_exit(context);
499 exit(EXIT_FAILURE);
500 }
501 }
502 }
503 }
504
505 if (!target_only_mode) {
506 nfc_close(pndInitiator);
507 }
508 if (!initiator_only_mode) {
509 nfc_close(pndTarget);
510 }
511 nfc_exit(context);
512 exit(EXIT_SUCCESS);
513}
514
const char * nfc_device_get_name(nfc_device *pnd)
Returns the device name.
Definition nfc.c:1209
void nfc_close(nfc_device *pnd)
Close from a NFC device.
Definition nfc.c:339
nfc_device * nfc_open(nfc_context *context, const nfc_connstring connstring)
Open a NFC device.
Definition nfc.c:277
size_t nfc_list_devices(nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len)
Scan for discoverable supported devices (ie. only available for some drivers)
Definition nfc.c:356
void nfc_perror(const nfc_device *pnd, const char *pcString)
Display the last error occured on a nfc_device.
Definition nfc.c:1183
int nfc_initiator_transceive_bytes(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, int timeout)
Send data to target then retrieve data from target.
Definition nfc.c:809
int nfc_initiator_init(nfc_device *pnd)
Initialize NFC device as initiator (reader)
Definition nfc.c:493
int nfc_initiator_select_passive_target(nfc_device *pnd, const nfc_modulation nm, const uint8_t *pbtInitData, const size_t szInitData, nfc_target *pnt)
Select a passive or emulated tag.
Definition nfc.c:562
void nfc_exit(nfc_context *context)
Deinitialize libnfc. Should be called after closing all open devices and before your application term...
Definition nfc.c:248
void nfc_init(nfc_context **context)
Initialize libnfc. This function must be called before calling any other libnfc function.
Definition nfc.c:231
const char * nfc_version(void)
Returns the library version.
Definition nfc.c:1319
int nfc_target_send_bytes(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, int timeout)
Send bytes and APDU frames.
Definition nfc.c:1057
int nfc_target_init(nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const size_t szRx, int timeout)
Initialize NFC device as an emulated tag.
Definition nfc.c:978
int nfc_target_receive_bytes(nfc_device *pnd, uint8_t *pbtRx, const size_t szRx, int timeout)
Receive bytes and APDU frames.
Definition nfc.c:1077
char nfc_connstring[NFC_BUFSIZE_CONNSTRING]
Definition nfc-types.h:63
Provide some examples shared functions like print, parity calculation, options parsing.
#define ERR(...)
Print a error message.
Definition nfc-utils.h:85
libnfc interface
NFC library context Struct which contains internal options, references, pointers, etc....
NFC device information.
NFC modulation structure.
Definition nfc-types.h:342
NFC target structure.
Definition nfc-types.h:351