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 
68 static uint8_t abtCapdu[MAX_FRAME_LEN];
69 static size_t szCapduLen;
70 static uint8_t abtRapdu[MAX_FRAME_LEN];
71 static size_t szRapduLen;
72 static nfc_device *pndInitiator;
73 static nfc_device *pndTarget;
74 static bool quitting = false;
75 static bool quiet_output = false;
76 static bool initiator_only_mode = false;
77 static bool target_only_mode = false;
78 static bool swap_devices = false;
79 static unsigned int waiting_time = 0;
80 FILE *fd3;
81 FILE *fd4;
82 
83 static void
84 intr_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 
93 static void
94 print_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 
106 static 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 
128 static 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 
160 int
161 main(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....
Definition: nfc-internal.h:175
NFC device information.
Definition: nfc-internal.h:190
NFC modulation structure.
Definition: nfc-types.h:342
NFC target structure.
Definition: nfc-types.h:351