libnfc  1.7.1
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-n N\tAdds a waiting time of N seconds (integer) in the relay to mimic long distance.\n");
103 }
104 
105 static int print_hex_fd4(const uint8_t *pbtData, const size_t szBytes, const char *pchPrefix)
106 {
107  size_t szPos;
108  if (szBytes > MAX_FRAME_LEN) {
109  return -1;
110  }
111  if (fprintf(fd4, "#%s %04" PRIxPTR ": ", pchPrefix, szBytes) < 0) {
112  return -1;
113  }
114 
115  for (szPos = 0; szPos < szBytes; szPos++) {
116  if (fprintf(fd4, "%02x ", pbtData[szPos]) < 0) {
117  return -1;
118  }
119  }
120  if (fprintf(fd4, "\n") < 0) {
121  return -1;
122  }
123  fflush(fd4);
124  return 0;
125 }
126 
127 static int scan_hex_fd3(uint8_t *pbtData, size_t *pszBytes, const char *pchPrefix)
128 {
129  size_t szPos;
130  unsigned int uiBytes;
131  unsigned int uiData;
132  char pchScan[256];
133  int c;
134  // Look for our next sync marker
135  while ((c = fgetc(fd3)) != '#') {
136  if (c == EOF) {
137  return -1;
138  }
139  }
140  strncpy(pchScan, pchPrefix, 250);
141  pchScan[sizeof(pchScan) - 1] = '\0';
142  strcat(pchScan, " %04x:");
143  if (fscanf(fd3, pchScan, &uiBytes) < 1) {
144  return -1;
145  }
146  *pszBytes = uiBytes;
147  if (*pszBytes > MAX_FRAME_LEN) {
148  return -1;
149  }
150  for (szPos = 0; szPos < *pszBytes; szPos++) {
151  if (fscanf(fd3, "%02x", &uiData) < 1) {
152  return -1;
153  }
154  pbtData[szPos] = uiData;
155  }
156  return 0;
157 }
158 
159 int
160 main(int argc, char *argv[])
161 {
162  int arg;
163  const char *acLibnfcVersion = nfc_version();
164  nfc_target ntRealTarget;
165 
166  // Get commandline options
167  for (arg = 1; arg < argc; arg++) {
168  if (0 == strcmp(argv[arg], "-h")) {
169  print_usage(argv);
170  exit(EXIT_SUCCESS);
171  } else if (0 == strcmp(argv[arg], "-q")) {
172  quiet_output = true;
173  } else if (0 == strcmp(argv[arg], "-t")) {
174  printf("INFO: %s\n", "Target mode only.");
175  initiator_only_mode = false;
176  target_only_mode = true;
177  } else if (0 == strcmp(argv[arg], "-i")) {
178  printf("INFO: %s\n", "Initiator mode only.");
179  initiator_only_mode = true;
180  target_only_mode = false;
181  } else if (0 == strcmp(argv[arg], "-s")) {
182  printf("INFO: %s\n", "Swapping devices.");
183  swap_devices = true;
184  } else if (0 == strcmp(argv[arg], "-n")) {
185  if (++arg == argc || (sscanf(argv[arg], "%10u", &waiting_time) < 1)) {
186  ERR("Missing or wrong waiting time value: %s.", argv[arg]);
187  print_usage(argv);
188  exit(EXIT_FAILURE);
189  }
190  printf("Waiting time: %u secs.\n", waiting_time);
191  } else {
192  ERR("%s is not supported option.", argv[arg]);
193  print_usage(argv);
194  exit(EXIT_FAILURE);
195  }
196  }
197 
198  // Display libnfc version
199  printf("%s uses libnfc %s\n", argv[0], acLibnfcVersion);
200 
201 #ifdef WIN32
202  signal(SIGINT, (void (__cdecl *)(int)) intr_hdlr);
203 #else
204  signal(SIGINT, intr_hdlr);
205 #endif
206 
207  nfc_context *context;
208  nfc_init(&context);
209  if (context == NULL) {
210  ERR("Unable to init libnfc (malloc)");
211  exit(EXIT_FAILURE);
212  }
213 
214  nfc_connstring connstrings[MAX_DEVICE_COUNT];
215  // List available devices
216  size_t szFound = nfc_list_devices(context, connstrings, MAX_DEVICE_COUNT);
217 
218  if (initiator_only_mode || target_only_mode) {
219  if (szFound < 1) {
220  ERR("No device found");
221  nfc_exit(context);
222  exit(EXIT_FAILURE);
223  }
224  if ((fd3 = fdopen(3, "r")) == NULL) {
225  ERR("Could not open file descriptor 3");
226  nfc_exit(context);
227  exit(EXIT_FAILURE);
228  }
229  if ((fd4 = fdopen(4, "r")) == NULL) {
230  ERR("Could not open file descriptor 4");
231  nfc_exit(context);
232  exit(EXIT_FAILURE);
233  }
234  } else {
235  if (szFound < 2) {
236  ERR("%" PRIdPTR " device found but two opened devices are needed to relay NFC.", szFound);
237  nfc_exit(context);
238  exit(EXIT_FAILURE);
239  }
240  }
241 
242  if (!target_only_mode) {
243  // Try to open the NFC reader used as initiator
244  // Little hack to allow using initiator no matter if
245  // there is already a target used locally or not on the same machine:
246  // if there is more than one readers opened we open the second reader
247  // (we hope they're always detected in the same order)
248  if ((szFound == 1) || swap_devices) {
249  pndInitiator = nfc_open(context, connstrings[0]);
250  } else {
251  pndInitiator = nfc_open(context, connstrings[1]);
252  }
253 
254  if (pndInitiator == NULL) {
255  printf("Error opening NFC reader\n");
256  nfc_exit(context);
257  exit(EXIT_FAILURE);
258  }
259 
260  printf("NFC reader device: %s opened\n", nfc_device_get_name(pndInitiator));
261 
262  if (nfc_initiator_init(pndInitiator) < 0) {
263  printf("Error: fail initializing initiator\n");
264  nfc_close(pndInitiator);
265  nfc_exit(context);
266  exit(EXIT_FAILURE);
267  }
268 
269  // Try to find a ISO 14443-4A tag
270  nfc_modulation nm = {
271  .nmt = NMT_ISO14443A,
272  .nbr = NBR_106,
273  };
274  if (nfc_initiator_select_passive_target(pndInitiator, nm, NULL, 0, &ntRealTarget) <= 0) {
275  printf("Error: no tag was found\n");
276  nfc_close(pndInitiator);
277  nfc_exit(context);
278  exit(EXIT_FAILURE);
279  }
280 
281  printf("Found tag:\n");
282  print_nfc_target(&ntRealTarget, false);
283  if (initiator_only_mode) {
284  if (print_hex_fd4(ntRealTarget.nti.nai.abtUid, ntRealTarget.nti.nai.szUidLen, "UID") < 0) {
285  fprintf(stderr, "Error while printing UID to FD4\n");
286  nfc_close(pndInitiator);
287  nfc_exit(context);
288  exit(EXIT_FAILURE);
289  }
290  if (print_hex_fd4(ntRealTarget.nti.nai.abtAtqa, 2, "ATQA") < 0) {
291  fprintf(stderr, "Error while printing ATQA to FD4\n");
292  nfc_close(pndInitiator);
293  nfc_exit(context);
294  exit(EXIT_FAILURE);
295  }
296  if (print_hex_fd4(&(ntRealTarget.nti.nai.btSak), 1, "SAK") < 0) {
297  fprintf(stderr, "Error while printing SAK to FD4\n");
298  nfc_close(pndInitiator);
299  nfc_exit(context);
300  exit(EXIT_FAILURE);
301  }
302  if (print_hex_fd4(ntRealTarget.nti.nai.abtAts, ntRealTarget.nti.nai.szAtsLen, "ATS") < 0) {
303  fprintf(stderr, "Error while printing ATS to FD4\n");
304  nfc_close(pndInitiator);
305  nfc_exit(context);
306  exit(EXIT_FAILURE);
307  }
308  }
309  }
310  if (initiator_only_mode) {
311  printf("Hint: tag <---> *INITIATOR* (relay) <-FD3/FD4-> target (relay) <---> original reader\n\n");
312  } else if (target_only_mode) {
313  printf("Hint: tag <---> initiator (relay) <-FD3/FD4-> *TARGET* (relay) <---> original reader\n\n");
314  } else {
315  printf("Hint: tag <---> initiator (relay) <---> target (relay) <---> original reader\n\n");
316  }
317  if (!initiator_only_mode) {
318  nfc_target ntEmulatedTarget = {
319  .nm = {
320  .nmt = NMT_ISO14443A,
321  .nbr = NBR_106,
322  },
323  };
324  if (target_only_mode) {
325  size_t foo;
326  if (scan_hex_fd3(ntEmulatedTarget.nti.nai.abtUid, &(ntEmulatedTarget.nti.nai.szUidLen), "UID") < 0) {
327  fprintf(stderr, "Error while scanning UID from FD3\n");
328  nfc_close(pndInitiator);
329  nfc_exit(context);
330  exit(EXIT_FAILURE);
331  }
332  if (scan_hex_fd3(ntEmulatedTarget.nti.nai.abtAtqa, &foo, "ATQA") < 0) {
333  fprintf(stderr, "Error while scanning ATQA from FD3\n");
334  nfc_close(pndInitiator);
335  nfc_exit(context);
336  exit(EXIT_FAILURE);
337  }
338  if (scan_hex_fd3(&(ntEmulatedTarget.nti.nai.btSak), &foo, "SAK") < 0) {
339  fprintf(stderr, "Error while scanning SAK from FD3\n");
340  nfc_close(pndInitiator);
341  nfc_exit(context);
342  exit(EXIT_FAILURE);
343  }
344  if (scan_hex_fd3(ntEmulatedTarget.nti.nai.abtAts, &(ntEmulatedTarget.nti.nai.szAtsLen), "ATS") < 0) {
345  fprintf(stderr, "Error while scanning ATS from FD3\n");
346  nfc_close(pndInitiator);
347  nfc_exit(context);
348  exit(EXIT_FAILURE);
349  }
350  } else {
351  ntEmulatedTarget.nti = ntRealTarget.nti;
352  }
353  // We can only emulate a short UID, so fix length & ATQA bit:
354  ntEmulatedTarget.nti.nai.szUidLen = 4;
355  ntEmulatedTarget.nti.nai.abtAtqa[1] &= (0xFF - 0x40);
356  // First byte of UID is always automatically replaced by 0x08 in this mode anyway
357  ntEmulatedTarget.nti.nai.abtUid[0] = 0x08;
358  // ATS is always automatically replaced by PN532, we've no control on it:
359  // ATS = (05) 75 33 92 03
360  // (TL) T0 TA TB TC
361  // | | | +-- CID supported, NAD supported
362  // | | +----- FWI=9 SFGI=2 => FWT=154ms, SFGT=1.21ms
363  // | +-------- DR=2,4 DS=2,4 => supports 106, 212 & 424bps in both directions
364  // +----------- TA,TB,TC, FSCI=5 => FSC=64
365  // It seems hazardous to tell we support NAD if the tag doesn't support NAD but I don't know how to disable it
366  // PC/SC pseudo-ATR = 3B 80 80 01 01 if there is no historical bytes
367 
368  // Creates ATS and copy max 48 bytes of Tk:
369  uint8_t *pbtTk;
370  size_t szTk;
371  pbtTk = iso14443a_locate_historical_bytes(ntEmulatedTarget.nti.nai.abtAts, ntEmulatedTarget.nti.nai.szAtsLen, &szTk);
372  szTk = (szTk > 48) ? 48 : szTk;
373  uint8_t pbtTkt[48];
374  memcpy(pbtTkt, pbtTk, szTk);
375  ntEmulatedTarget.nti.nai.abtAts[0] = 0x75;
376  ntEmulatedTarget.nti.nai.abtAts[1] = 0x33;
377  ntEmulatedTarget.nti.nai.abtAts[2] = 0x92;
378  ntEmulatedTarget.nti.nai.abtAts[3] = 0x03;
379  ntEmulatedTarget.nti.nai.szAtsLen = 4 + szTk;
380  memcpy(&(ntEmulatedTarget.nti.nai.abtAts[4]), pbtTkt, szTk);
381 
382  printf("We will emulate:\n");
383  print_nfc_target(&ntEmulatedTarget, false);
384 
385  // Try to open the NFC emulator device
386  if (swap_devices) {
387  pndTarget = nfc_open(context, connstrings[1]);
388  } else {
389  pndTarget = nfc_open(context, connstrings[0]);
390  }
391  if (pndTarget == NULL) {
392  printf("Error opening NFC emulator device\n");
393  if (!target_only_mode) {
394  nfc_close(pndInitiator);
395  }
396  nfc_exit(context);
397  exit(EXIT_FAILURE);
398  }
399 
400  printf("NFC emulator device: %s opened\n", nfc_device_get_name(pndTarget));
401  if (nfc_target_init(pndTarget, &ntEmulatedTarget, abtCapdu, sizeof(abtCapdu), 0) < 0) {
402  ERR("%s", "Initialization of NFC emulator failed");
403  if (!target_only_mode) {
404  nfc_close(pndInitiator);
405  }
406  nfc_close(pndTarget);
407  nfc_exit(context);
408  exit(EXIT_FAILURE);
409  }
410  printf("%s\n", "Done, relaying frames now!");
411  }
412 
413  while (!quitting) {
414  bool ret;
415  int res = 0;
416  if (!initiator_only_mode) {
417  // Receive external reader command through target
418  if ((res = nfc_target_receive_bytes(pndTarget, abtCapdu, sizeof(abtCapdu), 0)) < 0) {
419  nfc_perror(pndTarget, "nfc_target_receive_bytes");
420  if (!target_only_mode) {
421  nfc_close(pndInitiator);
422  }
423  nfc_close(pndTarget);
424  nfc_exit(context);
425  exit(EXIT_FAILURE);
426  }
427  szCapduLen = (size_t) res;
428  if (target_only_mode) {
429  if (print_hex_fd4(abtCapdu, szCapduLen, "C-APDU") < 0) {
430  fprintf(stderr, "Error while printing C-APDU to FD4\n");
431  nfc_close(pndTarget);
432  nfc_exit(context);
433  exit(EXIT_FAILURE);
434  }
435  }
436  } else {
437  if (scan_hex_fd3(abtCapdu, &szCapduLen, "C-APDU") < 0) {
438  fprintf(stderr, "Error while scanning C-APDU from FD3\n");
439  nfc_close(pndInitiator);
440  nfc_exit(context);
441  exit(EXIT_FAILURE);
442  }
443  }
444  // Show transmitted response
445  if (!quiet_output) {
446  printf("Forwarding C-APDU: ");
447  print_hex(abtCapdu, szCapduLen);
448  }
449 
450  if (!target_only_mode) {
451  // Forward the frame to the original tag
452  if ((res = nfc_initiator_transceive_bytes(pndInitiator, abtCapdu, szCapduLen, abtRapdu, sizeof(abtRapdu), -1)) < 0) {
453  ret = false;
454  } else {
455  szRapduLen = (size_t) res;
456  ret = true;
457  }
458  } else {
459  if (scan_hex_fd3(abtRapdu, &szRapduLen, "R-APDU") < 0) {
460  fprintf(stderr, "Error while scanning R-APDU from FD3\n");
461  nfc_close(pndTarget);
462  nfc_exit(context);
463  exit(EXIT_FAILURE);
464  }
465  ret = true;
466  }
467  if (ret) {
468  // Redirect the answer back to the external reader
469  if (waiting_time != 0) {
470  if (!quiet_output) {
471  printf("Waiting %us to simulate longer relay...\n", waiting_time);
472  }
473  sleep(waiting_time);
474  }
475  // Show transmitted response
476  if (!quiet_output) {
477  printf("Forwarding R-APDU: ");
478  print_hex(abtRapdu, szRapduLen);
479  }
480  if (!initiator_only_mode) {
481  // Transmit the response bytes
482  if (nfc_target_send_bytes(pndTarget, abtRapdu, szRapduLen, 0) < 0) {
483  nfc_perror(pndTarget, "nfc_target_send_bytes");
484  if (!target_only_mode) {
485  nfc_close(pndInitiator);
486  }
487  if (!initiator_only_mode) {
488  nfc_close(pndTarget);
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 
nfc_initiator_init
int nfc_initiator_init(nfc_device *pnd)
Initialize NFC device as initiator (reader)
Definition: nfc.c:452
nfc_init
void nfc_init(nfc_context **context)
Initialize libnfc. This function must be called before calling any other libnfc function.
Definition: nfc.c:192
nfc_context
NFC library context Struct which contains internal options, references, pointers, etc....
Definition: nfc-internal.h:175
nfc_device
NFC device information.
Definition: nfc-internal.h:190
nfc_version
const char * nfc_version(void)
Returns the library version.
Definition: nfc.c:1218
nfc_target_init
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:933
nfc_exit
void nfc_exit(nfc_context *context)
Deinitialize libnfc. Should be called after closing all open devices and before your application term...
Definition: nfc.c:209
nfc_target
NFC target structure.
Definition: nfc-types.h:328
nfc_initiator_transceive_bytes
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:764
nfc_modulation
NFC modulation structure.
Definition: nfc-types.h:319
nfc_connstring
char nfc_connstring[NFC_BUFSIZE_CONNSTRING]
Definition: nfc-types.h:62
nfc_device_get_name
const char * nfc_device_get_name(nfc_device *pnd)
Returns the device name.
Definition: nfc.c:1164
nfc_open
nfc_device * nfc_open(nfc_context *context, const nfc_connstring connstring)
Open a NFC device.
Definition: nfc.c:238
nfc_initiator_select_passive_target
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:521
nfc_perror
void nfc_perror(const nfc_device *pnd, const char *pcString)
Display the last error occured on a nfc_device.
Definition: nfc.c:1138
nfc_list_devices
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:317
ERR
#define ERR(...)
Print a error message.
Definition: nfc-utils.h:85
nfc_close
void nfc_close(nfc_device *pnd)
Close from a NFC device.
Definition: nfc.c:300
nfc_target_receive_bytes
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:1032
nfc-utils.h
Provide some examples shared functions like print, parity calculation, options parsing.
nfc_target_send_bytes
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:1012
nfc.h
libnfc interface