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