libnfc  1.7.0-rc7
nfc-relay-picc.c
Go to the documentation of this file.
00001 /*-
00002  * Free/Libre Near Field Communication (NFC) library
00003  *
00004  * Libnfc historical contributors:
00005  * Copyright (C) 2009      Roel Verdult
00006  * Copyright (C) 2009-2013 Romuald Conty
00007  * Copyright (C) 2010-2012 Romain Tartière
00008  * Copyright (C) 2010-2013 Philippe Teuwen
00009  * Copyright (C) 2012-2013 Ludovic Rousseau
00010  * Additional contributors of this file:
00011  *
00012  * Redistribution and use in source and binary forms, with or without
00013  * modification, are permitted provided that the following conditions are met:
00014  *  1) Redistributions of source code must retain the above copyright notice,
00015  *  this list of conditions and the following disclaimer.
00016  *  2 )Redistributions in binary form must reproduce the above copyright
00017  *  notice, this list of conditions and the following disclaimer in the
00018  *  documentation and/or other materials provided with the distribution.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00021  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00022  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00023  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00024  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00025  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00026  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00027  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00028  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00029  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00030  * POSSIBILITY OF SUCH DAMAGE.
00031  *
00032  * Note that this license only applies on the examples, NFC library itself is under LGPL
00033  *
00034  */
00035 
00041 // Notes & differences with nfc-relay:
00042 // - This example only works with PN532 because it relies on
00043 //   its internal handling of ISO14443-4 specificities.
00044 // - Thanks to this internal handling & injection of WTX frames,
00045 //   this example works on readers very strict on timing
00046 
00047 #ifdef HAVE_CONFIG_H
00048 #  include "config.h"
00049 #endif /* HAVE_CONFIG_H */
00050 
00051 #include <inttypes.h>
00052 #include <stdio.h>
00053 #include <stdlib.h>
00054 #include <stdint.h>
00055 #include <string.h>
00056 #include <signal.h>
00057 
00058 #include <unistd.h>
00059 
00060 #include <nfc/nfc.h>
00061 
00062 #include "nfc-utils.h"
00063 
00064 #define MAX_FRAME_LEN 264
00065 #define MAX_DEVICE_COUNT 2
00066 
00067 static uint8_t abtCapdu[MAX_FRAME_LEN];
00068 static size_t szCapduLen;
00069 static uint8_t abtRapdu[MAX_FRAME_LEN];
00070 static size_t szRapduLen;
00071 static nfc_device *pndInitiator;
00072 static nfc_device *pndTarget;
00073 static bool quitting = false;
00074 static bool quiet_output = false;
00075 static bool initiator_only_mode = false;
00076 static bool target_only_mode = false;
00077 static bool swap_devices = false;
00078 static int waiting_time = 0;
00079 FILE *fd3;
00080 FILE *fd4;
00081 
00082 static void
00083 intr_hdlr(int sig)
00084 {
00085   (void) sig;
00086   printf("\nQuitting...\n");
00087   printf("Please send a last command to the emulator to quit properly.\n");
00088   quitting = true;
00089   return;
00090 }
00091 
00092 static void
00093 print_usage(char *argv[])
00094 {
00095   printf("Usage: %s [OPTIONS]\n", argv[0]);
00096   printf("Options:\n");
00097   printf("\t-h\tHelp. Print this message.\n");
00098   printf("\t-q\tQuiet mode. Suppress printing of relayed data (improves timing).\n");
00099   printf("\t-t\tTarget mode only (the one on reader side). Data expected from FD3 to FD4.\n");
00100   printf("\t-i\tInitiator mode only (the one on tag side). Data expected from FD3 to FD4.\n");
00101   printf("\t-n N\tAdds a waiting time of N seconds (integer) in the relay to mimic long distance.\n");
00102 }
00103 
00104 static int print_hex_fd4(const uint8_t *pbtData, const size_t szBytes, const char *pchPrefix)
00105 {
00106   size_t  szPos;
00107   if (szBytes > MAX_FRAME_LEN) {
00108     return -1;
00109   }
00110   if (fprintf(fd4, "#%s %04" PRIxPTR ": ", pchPrefix, szBytes) < 0) {
00111     return -1;
00112   }
00113 
00114   for (szPos = 0; szPos < szBytes; szPos++) {
00115     if (fprintf(fd4, "%02x ", pbtData[szPos]) < 0) {
00116       return -1;
00117     }
00118   }
00119   if (fprintf(fd4, "\n") < 0) {
00120     return -1;
00121   }
00122   fflush(fd4);
00123   return 0;
00124 }
00125 
00126 static int scan_hex_fd3(uint8_t *pbtData, size_t *pszBytes, const char *pchPrefix)
00127 {
00128   size_t  szPos;
00129   unsigned int uiBytes;
00130   unsigned int uiData;
00131   char pchScan[256];
00132   int c;
00133   // Look for our next sync marker
00134   while ((c = fgetc(fd3)) != '#') {
00135     if (c == EOF) {
00136       return -1;
00137     }
00138   }
00139   strncpy(pchScan, pchPrefix, 250);
00140   pchScan[sizeof(pchScan) - 1] = '\0';
00141   strcat(pchScan, " %04x:");
00142   if (fscanf(fd3, pchScan, &uiBytes) < 1) {
00143     return -1;
00144   }
00145   *pszBytes = uiBytes;
00146   if (*pszBytes > MAX_FRAME_LEN) {
00147     return -1;
00148   }
00149   for (szPos = 0; szPos < *pszBytes; szPos++) {
00150     if (fscanf(fd3, "%02x", &uiData) < 1) {
00151       return -1;
00152     }
00153     pbtData[szPos] = uiData;
00154   }
00155   return 0;
00156 }
00157 
00158 int
00159 main(int argc, char *argv[])
00160 {
00161   int     arg;
00162   const char *acLibnfcVersion = nfc_version();
00163   nfc_target ntRealTarget;
00164 
00165   // Get commandline options
00166   for (arg = 1; arg < argc; arg++) {
00167     if (0 == strcmp(argv[arg], "-h")) {
00168       print_usage(argv);
00169       exit(EXIT_SUCCESS);
00170     } else if (0 == strcmp(argv[arg], "-q")) {
00171       quiet_output = true;
00172     } else if (0 == strcmp(argv[arg], "-t")) {
00173       printf("INFO: %s\n", "Target mode only.");
00174       initiator_only_mode = false;
00175       target_only_mode = true;
00176     } else if (0 == strcmp(argv[arg], "-i")) {
00177       printf("INFO: %s\n", "Initiator mode only.");
00178       initiator_only_mode = true;
00179       target_only_mode = false;
00180     } else if (0 == strcmp(argv[arg], "-s")) {
00181       printf("INFO: %s\n", "Swapping devices.");
00182       swap_devices = true;
00183     } else if (0 == strcmp(argv[arg], "-n")) {
00184       if (++arg == argc || (sscanf(argv[arg], "%10i", &waiting_time) < 1)) {
00185         ERR("Missing or wrong waiting time value: %s.", argv[arg]);
00186         print_usage(argv);
00187         exit(EXIT_FAILURE);
00188       }
00189       printf("Waiting time: %i secs.\n", waiting_time);
00190     } else {
00191       ERR("%s is not supported option.", argv[arg]);
00192       print_usage(argv);
00193       exit(EXIT_FAILURE);
00194     }
00195   }
00196 
00197   // Display libnfc version
00198   printf("%s uses libnfc %s\n", argv[0], acLibnfcVersion);
00199 
00200 #ifdef WIN32
00201   signal(SIGINT, (void (__cdecl *)(int)) intr_hdlr);
00202 #else
00203   signal(SIGINT, intr_hdlr);
00204 #endif
00205 
00206   nfc_context *context;
00207   nfc_init(&context);
00208   if (context == NULL) {
00209     ERR("Unable to init libnfc (malloc)");
00210     exit(EXIT_FAILURE);
00211   }
00212 
00213   nfc_connstring connstrings[MAX_DEVICE_COUNT];
00214   // List available devices
00215   size_t szFound = nfc_list_devices(context, connstrings, MAX_DEVICE_COUNT);
00216 
00217   if (initiator_only_mode || target_only_mode) {
00218     if (szFound < 1) {
00219       ERR("No device found");
00220       nfc_exit(context);
00221       exit(EXIT_FAILURE);
00222     }
00223     if ((fd3 = fdopen(3, "r")) == NULL) {
00224       ERR("Could not open file descriptor 3");
00225       nfc_exit(context);
00226       exit(EXIT_FAILURE);
00227     }
00228     if ((fd4 = fdopen(4, "r")) == NULL) {
00229       ERR("Could not open file descriptor 4");
00230       nfc_exit(context);
00231       exit(EXIT_FAILURE);
00232     }
00233   } else {
00234     if (szFound < 2) {
00235       ERR("%" PRIdPTR " device found but two opened devices are needed to relay NFC.", szFound);
00236       nfc_exit(context);
00237       exit(EXIT_FAILURE);
00238     }
00239   }
00240 
00241   if (!target_only_mode) {
00242     // Try to open the NFC reader used as initiator
00243     // Little hack to allow using initiator no matter if
00244     // there is already a target used locally or not on the same machine:
00245     // if there is more than one readers opened we open the second reader
00246     // (we hope they're always detected in the same order)
00247     if ((szFound == 1) || swap_devices) {
00248       pndInitiator = nfc_open(context, connstrings[0]);
00249     } else {
00250       pndInitiator = nfc_open(context, connstrings[1]);
00251     }
00252 
00253     if (pndInitiator == NULL) {
00254       printf("Error opening NFC reader\n");
00255       nfc_exit(context);
00256       exit(EXIT_FAILURE);
00257     }
00258 
00259     printf("NFC reader device: %s opened\n", nfc_device_get_name(pndInitiator));
00260 
00261     if (nfc_initiator_init(pndInitiator) < 0) {
00262       printf("Error: fail initializing initiator\n");
00263       nfc_close(pndInitiator);
00264       nfc_exit(context);
00265       exit(EXIT_FAILURE);
00266     }
00267 
00268     // Try to find a ISO 14443-4A tag
00269     nfc_modulation nm = {
00270       .nmt = NMT_ISO14443A,
00271       .nbr = NBR_106,
00272     };
00273     if (nfc_initiator_select_passive_target(pndInitiator, nm, NULL, 0, &ntRealTarget) <= 0) {
00274       printf("Error: no tag was found\n");
00275       nfc_close(pndInitiator);
00276       nfc_exit(context);
00277       exit(EXIT_FAILURE);
00278     }
00279 
00280     printf("Found tag:\n");
00281     print_nfc_target(&ntRealTarget, false);
00282     if (initiator_only_mode) {
00283       if (print_hex_fd4(ntRealTarget.nti.nai.abtUid, ntRealTarget.nti.nai.szUidLen, "UID") < 0) {
00284         fprintf(stderr, "Error while printing UID to FD4\n");
00285         nfc_close(pndInitiator);
00286         nfc_exit(context);
00287         exit(EXIT_FAILURE);
00288       }
00289       if (print_hex_fd4(ntRealTarget.nti.nai.abtAtqa, 2, "ATQA") < 0) {
00290         fprintf(stderr, "Error while printing ATQA to FD4\n");
00291         nfc_close(pndInitiator);
00292         nfc_exit(context);
00293         exit(EXIT_FAILURE);
00294       }
00295       if (print_hex_fd4(&(ntRealTarget.nti.nai.btSak), 1, "SAK") < 0) {
00296         fprintf(stderr, "Error while printing SAK to FD4\n");
00297         nfc_close(pndInitiator);
00298         nfc_exit(context);
00299         exit(EXIT_FAILURE);
00300       }
00301       if (print_hex_fd4(ntRealTarget.nti.nai.abtAts, ntRealTarget.nti.nai.szAtsLen, "ATS") < 0) {
00302         fprintf(stderr, "Error while printing ATS to FD4\n");
00303         nfc_close(pndInitiator);
00304         nfc_exit(context);
00305         exit(EXIT_FAILURE);
00306       }
00307     }
00308   }
00309   if (initiator_only_mode) {
00310     printf("Hint: tag <---> *INITIATOR* (relay) <-FD3/FD4-> target (relay) <---> original reader\n\n");
00311   } else if (target_only_mode) {
00312     printf("Hint: tag <---> initiator (relay) <-FD3/FD4-> *TARGET* (relay) <---> original reader\n\n");
00313   } else {
00314     printf("Hint: tag <---> initiator (relay) <---> target (relay) <---> original reader\n\n");
00315   }
00316   if (!initiator_only_mode) {
00317     nfc_target ntEmulatedTarget = {
00318       .nm = {
00319         .nmt = NMT_ISO14443A,
00320         .nbr = NBR_106,
00321       },
00322     };
00323     if (target_only_mode) {
00324       size_t foo;
00325       if (scan_hex_fd3(ntEmulatedTarget.nti.nai.abtUid, &(ntEmulatedTarget.nti.nai.szUidLen), "UID") < 0) {
00326         fprintf(stderr, "Error while scanning UID from FD3\n");
00327         nfc_close(pndInitiator);
00328         nfc_exit(context);
00329         exit(EXIT_FAILURE);
00330       }
00331       if (scan_hex_fd3(ntEmulatedTarget.nti.nai.abtAtqa, &foo, "ATQA") < 0) {
00332         fprintf(stderr, "Error while scanning ATQA from FD3\n");
00333         nfc_close(pndInitiator);
00334         nfc_exit(context);
00335         exit(EXIT_FAILURE);
00336       }
00337       if (scan_hex_fd3(&(ntEmulatedTarget.nti.nai.btSak), &foo, "SAK") < 0) {
00338         fprintf(stderr, "Error while scanning SAK from FD3\n");
00339         nfc_close(pndInitiator);
00340         nfc_exit(context);
00341         exit(EXIT_FAILURE);
00342       }
00343       if (scan_hex_fd3(ntEmulatedTarget.nti.nai.abtAts, &(ntEmulatedTarget.nti.nai.szAtsLen), "ATS") < 0) {
00344         fprintf(stderr, "Error while scanning ATS from FD3\n");
00345         nfc_close(pndInitiator);
00346         nfc_exit(context);
00347         exit(EXIT_FAILURE);
00348       }
00349     } else {
00350       ntEmulatedTarget.nti = ntRealTarget.nti;
00351     }
00352     // We can only emulate a short UID, so fix length & ATQA bit:
00353     ntEmulatedTarget.nti.nai.szUidLen = 4;
00354     ntEmulatedTarget.nti.nai.abtAtqa[1] &= (0xFF - 0x40);
00355     // First byte of UID is always automatically replaced by 0x08 in this mode anyway
00356     ntEmulatedTarget.nti.nai.abtUid[0] = 0x08;
00357     // ATS is always automatically replaced by PN532, we've no control on it:
00358     // ATS = (05) 75 33 92 03
00359     //       (TL) T0 TA TB TC
00360     //             |  |  |  +-- CID supported, NAD supported
00361     //             |  |  +----- FWI=9 SFGI=2 => FWT=154ms, SFGT=1.21ms
00362     //             |  +-------- DR=2,4 DS=2,4 => supports 106, 212 & 424bps in both directions
00363     //             +----------- TA,TB,TC, FSCI=5 => FSC=64
00364     // It seems hazardous to tell we support NAD if the tag doesn't support NAD but I don't know how to disable it
00365     // PC/SC pseudo-ATR = 3B 80 80 01 01 if there is no historical bytes
00366 
00367     // Creates ATS and copy max 48 bytes of Tk:
00368     uint8_t *pbtTk;
00369     size_t szTk;
00370     pbtTk = iso14443a_locate_historical_bytes(ntEmulatedTarget.nti.nai.abtAts, ntEmulatedTarget.nti.nai.szAtsLen, &szTk);
00371     szTk = (szTk > 48) ? 48 : szTk;
00372     uint8_t pbtTkt[48];
00373     memcpy(pbtTkt, pbtTk, szTk);
00374     ntEmulatedTarget.nti.nai.abtAts[0] = 0x75;
00375     ntEmulatedTarget.nti.nai.abtAts[1] = 0x33;
00376     ntEmulatedTarget.nti.nai.abtAts[2] = 0x92;
00377     ntEmulatedTarget.nti.nai.abtAts[3] = 0x03;
00378     ntEmulatedTarget.nti.nai.szAtsLen = 4 + szTk;
00379     memcpy(&(ntEmulatedTarget.nti.nai.abtAts[4]), pbtTkt, szTk);
00380 
00381     printf("We will emulate:\n");
00382     print_nfc_target(&ntEmulatedTarget, false);
00383 
00384     // Try to open the NFC emulator device
00385     if (swap_devices) {
00386       pndTarget = nfc_open(context, connstrings[1]);
00387     } else {
00388       pndTarget = nfc_open(context, connstrings[0]);
00389     }
00390     if (pndTarget == NULL) {
00391       printf("Error opening NFC emulator device\n");
00392       if (!target_only_mode) {
00393         nfc_close(pndInitiator);
00394       }
00395       nfc_exit(context);
00396       exit(EXIT_FAILURE);
00397     }
00398 
00399     printf("NFC emulator device: %s opened\n", nfc_device_get_name(pndTarget));
00400     if (nfc_target_init(pndTarget, &ntEmulatedTarget, abtCapdu, sizeof(abtCapdu), 0) < 0) {
00401       ERR("%s", "Initialization of NFC emulator failed");
00402       if (!target_only_mode) {
00403         nfc_close(pndInitiator);
00404       }
00405       nfc_close(pndTarget);
00406       nfc_exit(context);
00407       exit(EXIT_FAILURE);
00408     }
00409     printf("%s\n", "Done, relaying frames now!");
00410   }
00411 
00412   while (!quitting) {
00413     bool ret;
00414     int res = 0;
00415     if (!initiator_only_mode) {
00416       // Receive external reader command through target
00417       if ((res = nfc_target_receive_bytes(pndTarget, abtCapdu, sizeof(abtCapdu), 0)) < 0) {
00418         nfc_perror(pndTarget, "nfc_target_receive_bytes");
00419         if (!target_only_mode) {
00420           nfc_close(pndInitiator);
00421         }
00422         nfc_close(pndTarget);
00423         nfc_exit(context);
00424         exit(EXIT_FAILURE);
00425       }
00426       szCapduLen = (size_t) res;
00427       if (target_only_mode) {
00428         if (print_hex_fd4(abtCapdu, szCapduLen, "C-APDU") < 0) {
00429           fprintf(stderr, "Error while printing C-APDU to FD4\n");
00430           nfc_close(pndTarget);
00431           nfc_exit(context);
00432           exit(EXIT_FAILURE);
00433         }
00434       }
00435     } else {
00436       if (scan_hex_fd3(abtCapdu, &szCapduLen, "C-APDU") < 0) {
00437         fprintf(stderr, "Error while scanning C-APDU from FD3\n");
00438         nfc_close(pndInitiator);
00439         nfc_exit(context);
00440         exit(EXIT_FAILURE);
00441       }
00442     }
00443     // Show transmitted response
00444     if (!quiet_output) {
00445       printf("Forwarding C-APDU: ");
00446       print_hex(abtCapdu, szCapduLen);
00447     }
00448 
00449     if (!target_only_mode) {
00450       // Forward the frame to the original tag
00451       if ((res = nfc_initiator_transceive_bytes(pndInitiator, abtCapdu, szCapduLen, abtRapdu, sizeof(abtRapdu), -1)) < 0) {
00452         ret = false;
00453       } else {
00454         szRapduLen = (size_t) res;
00455         ret = true;
00456       }
00457     } else {
00458       if (scan_hex_fd3(abtRapdu, &szRapduLen, "R-APDU") < 0) {
00459         fprintf(stderr, "Error while scanning R-APDU from FD3\n");
00460         nfc_close(pndTarget);
00461         nfc_exit(context);
00462         exit(EXIT_FAILURE);
00463       }
00464       ret = true;
00465     }
00466     if (ret) {
00467       // Redirect the answer back to the external reader
00468       if (waiting_time > 0) {
00469         if (!quiet_output) {
00470           printf("Waiting %is to simulate longer relay...\n", waiting_time);
00471         }
00472         sleep(waiting_time);
00473       }
00474       // Show transmitted response
00475       if (!quiet_output) {
00476         printf("Forwarding R-APDU: ");
00477         print_hex(abtRapdu, szRapduLen);
00478       }
00479       if (!initiator_only_mode) {
00480         // Transmit the response bytes
00481         if (nfc_target_send_bytes(pndTarget, abtRapdu, szRapduLen, 0) < 0) {
00482           nfc_perror(pndTarget, "nfc_target_send_bytes");
00483           if (!target_only_mode) {
00484             nfc_close(pndInitiator);
00485           }
00486           if (!initiator_only_mode) {
00487             nfc_close(pndTarget);
00488             nfc_exit(context);
00489           }
00490           nfc_exit(context);
00491           exit(EXIT_FAILURE);
00492         }
00493       } else {
00494         if (print_hex_fd4(abtRapdu, szRapduLen, "R-APDU") < 0) {
00495           fprintf(stderr, "Error while printing R-APDU to FD4\n");
00496           nfc_close(pndInitiator);
00497           nfc_exit(context);
00498           exit(EXIT_FAILURE);
00499         }
00500       }
00501     }
00502   }
00503 
00504   if (!target_only_mode) {
00505     nfc_close(pndInitiator);
00506   }
00507   if (!initiator_only_mode) {
00508     nfc_close(pndTarget);
00509   }
00510   nfc_exit(context);
00511   exit(EXIT_SUCCESS);
00512 }
00513