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