libnfc  1.7.1
nfc-emulate-forum-tag4.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 /*
43  * This implementation was written based on information provided by the
44  * following documents:
45  *
46  * NFC Forum Type 4 Tag Operation
47  * Technical Specification
48  * NFCForum-TS-Type-4-Tag_1.0 - 2007-03-13
49  * NFCForum-TS-Type-4-Tag_2.0 - 2010-11-18
50  */
51 
52 // Notes & differences with nfc-emulate-tag:
53 // - This example only works with PN532 because it relies on
54 // its internal handling of ISO14443-4 specificities.
55 // - Thanks to this internal handling & injection of WTX frames,
56 // this example works on readers very strict on timing
57 
58 #ifdef HAVE_CONFIG_H
59 # include "config.h"
60 #endif // HAVE_CONFIG_H
61 
62 #include <sys/types.h>
63 #include <sys/stat.h>
64 
65 #include <errno.h>
66 #include <signal.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <stddef.h>
70 #include <stdint.h>
71 #include <string.h>
72 
73 #include <nfc/nfc.h>
74 #include <nfc/nfc-emulation.h>
75 
76 #include "nfc-utils.h"
77 
78 static nfc_device *pnd;
79 static nfc_context *context;
80 static bool quiet_output = false;
81 // Version of the emulated type4 tag:
82 static int type4v = 2;
83 
84 #define SYMBOL_PARAM_fISO14443_4_PICC 0x20
85 
86 typedef enum { NONE, CC_FILE, NDEF_FILE } file;
87 
88 struct nfcforum_tag4_ndef_data {
89  uint8_t *ndef_file;
90  size_t ndef_file_len;
91 };
92 
93 struct nfcforum_tag4_state_machine_data {
94  file current_file;
95 };
96 
97 uint8_t nfcforum_capability_container[] = {
98  0x00, 0x0F, /* CCLEN 15 bytes */
99  0x20, /* Mapping version 2.0, use option -1 to force v1.0 */
100  0x00, 0x54, /* MLe Maximum R-ADPU data size */
101 // Notes:
102 // - I (Romuald) don't know why Nokia 6212 Classic refuses the NDEF message if MLe is more than 0xFD (any suggests are welcome);
103 // - ARYGON devices doesn't support extended frame sending, consequently these devices can't sent more than 0xFE bytes as APDU, so 0xFB APDU data bytes.
104 // - I (Romuald) don't know why ARYGON device doesn't ACK when MLe > 0x54 (ARYGON frame length = 0xC2 (192 bytes))
105  0x00, 0xFF, /* MLc Maximum C-ADPU data size */
106  0x04, /* T field of the NDEF File-Control TLV */
107  0x06, /* L field of the NDEF File-Control TLV */
108  /* V field of the NDEF File-Control TLV */
109  0xE1, 0x04, /* File identifier */
110  0xFF, 0xFE, /* Maximum NDEF Size */
111  0x00, /* NDEF file read access condition */
112  0x00, /* NDEF file write access condition */
113 };
114 
115 /* C-ADPU offsets */
116 #define CLA 0
117 #define INS 1
118 #define P1 2
119 #define P2 3
120 #define LC 4
121 #define DATA 5
122 
123 #define ISO144434A_RATS 0xE0
124 
125 static int
126 nfcforum_tag4_io(struct nfc_emulator *emulator, const uint8_t *data_in, const size_t data_in_len, uint8_t *data_out, const size_t data_out_len)
127 {
128  int res = 0;
129 
130  struct nfcforum_tag4_ndef_data *ndef_data = (struct nfcforum_tag4_ndef_data *)(emulator->user_data);
131  struct nfcforum_tag4_state_machine_data *state_machine_data = (struct nfcforum_tag4_state_machine_data *)(emulator->state_machine->data);
132 
133  if (data_in_len == 0) {
134  // No input data, nothing to do
135  return res;
136  }
137 
138  // Show transmitted command
139  if (!quiet_output) {
140  printf(" In: ");
141  print_hex(data_in, data_in_len);
142  }
143 
144  if (data_in_len >= 4) {
145  if (data_in[CLA] != 0x00)
146  return -ENOTSUP;
147 
148 #define ISO7816_SELECT 0xA4
149 #define ISO7816_READ_BINARY 0xB0
150 #define ISO7816_UPDATE_BINARY 0xD6
151 
152  switch (data_in[INS]) {
153  case ISO7816_SELECT:
154 
155  switch (data_in[P1]) {
156  case 0x00: /* Select by ID */
157  if ((data_in[P2] | 0x0C) != 0x0C)
158  return -ENOTSUP;
159 
160  const uint8_t ndef_capability_container[] = { 0xE1, 0x03 };
161  const uint8_t ndef_file[] = { 0xE1, 0x04 };
162  if ((data_in[LC] == sizeof(ndef_capability_container)) && (0 == memcmp(ndef_capability_container, data_in + DATA, data_in[LC]))) {
163  memcpy(data_out, "\x90\x00", res = 2);
164  state_machine_data->current_file = CC_FILE;
165  } else if ((data_in[LC] == sizeof(ndef_file)) && (0 == memcmp(ndef_file, data_in + DATA, data_in[LC]))) {
166  memcpy(data_out, "\x90\x00", res = 2);
167  state_machine_data->current_file = NDEF_FILE;
168  } else {
169  memcpy(data_out, "\x6a\x00", res = 2);
170  state_machine_data->current_file = NONE;
171  }
172 
173  break;
174  case 0x04: /* Select by name */
175  if (data_in[P2] != 0x00)
176  return -ENOTSUP;
177 
178  const uint8_t ndef_tag_application_name_v1[] = { 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x00 };
179  const uint8_t ndef_tag_application_name_v2[] = { 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01 };
180  if ((type4v == 1) && (data_in[LC] == sizeof(ndef_tag_application_name_v1)) && (0 == memcmp(ndef_tag_application_name_v1, data_in + DATA, data_in[LC])))
181  memcpy(data_out, "\x90\x00", res = 2);
182  else if ((type4v == 2) && (data_in[LC] == sizeof(ndef_tag_application_name_v2)) && (0 == memcmp(ndef_tag_application_name_v2, data_in + DATA, data_in[LC])))
183  memcpy(data_out, "\x90\x00", res = 2);
184  else
185  memcpy(data_out, "\x6a\x82", res = 2);
186 
187  break;
188  default:
189  return -ENOTSUP;
190  }
191 
192  break;
193  case ISO7816_READ_BINARY:
194  if ((size_t)(data_in[LC] + 2) > data_out_len) {
195  return -ENOSPC;
196  }
197  switch (state_machine_data->current_file) {
198  case NONE:
199  memcpy(data_out, "\x6a\x82", res = 2);
200  break;
201  case CC_FILE:
202  memcpy(data_out, nfcforum_capability_container + (data_in[P1] << 8) + data_in[P2], data_in[LC]);
203  memcpy(data_out + data_in[LC], "\x90\x00", 2);
204  res = data_in[LC] + 2;
205  break;
206  case NDEF_FILE:
207  memcpy(data_out, ndef_data->ndef_file + (data_in[P1] << 8) + data_in[P2], data_in[LC]);
208  memcpy(data_out + data_in[LC], "\x90\x00", 2);
209  res = data_in[LC] + 2;
210  break;
211  }
212  break;
213 
214  case ISO7816_UPDATE_BINARY:
215  memcpy(ndef_data->ndef_file + (data_in[P1] << 8) + data_in[P2], data_in + DATA, data_in[LC]);
216  if ((data_in[P1] << 8) + data_in[P2] == 0) {
217  ndef_data->ndef_file_len = (ndef_data->ndef_file[0] << 8) + ndef_data->ndef_file[1] + 2;
218  }
219  memcpy(data_out, "\x90\x00", res = 2);
220  break;
221  default: // Unknown
222  if (!quiet_output) {
223  printf("Unknown frame, emulated target abort.\n");
224  }
225  res = -ENOTSUP;
226  }
227  } else {
228  res = -ENOTSUP;
229  }
230 
231  // Show transmitted command
232  if (!quiet_output) {
233  if (res < 0) {
234  ERR("%s (%d)", strerror(-res), -res);
235  } else {
236  printf(" Out: ");
237  print_hex(data_out, res);
238  }
239  }
240  return res;
241 }
242 
243 static void stop_emulation(int sig)
244 {
245  (void) sig;
246  if (pnd != NULL) {
247  nfc_abort_command(pnd);
248  } else {
249  nfc_exit(context);
250  exit(EXIT_FAILURE);
251  }
252 }
253 
254 static int
255 ndef_message_load(char *filename, struct nfcforum_tag4_ndef_data *tag_data)
256 {
257  struct stat sb;
258  FILE *F;
259  if (!(F = fopen(filename, "r"))) {
260  printf("File not found or not accessible '%s'\n", filename);
261  return -1;
262  }
263  if (stat(filename, &sb) < 0) {
264  printf("File not found or not accessible '%s'\n", filename);
265  fclose(F);
266  return -1;
267  }
268 
269  /* Check file size */
270  if (sb.st_size > 0xFFFF) {
271  printf("File size too large '%s'\n", filename);
272  fclose(F);
273  return -1;
274  }
275 
276  tag_data->ndef_file_len = sb.st_size + 2;
277 
278  tag_data->ndef_file[0] = (uint8_t)(sb.st_size >> 8);
279  tag_data->ndef_file[1] = (uint8_t)(sb.st_size);
280 
281 
282  if (1 != fread(tag_data->ndef_file + 2, sb.st_size, 1, F)) {
283  printf("Can't read from %s\n", filename);
284  fclose(F);
285  return -1;
286  }
287 
288  fclose(F);
289  return sb.st_size;
290 }
291 
292 static int
293 ndef_message_save(char *filename, struct nfcforum_tag4_ndef_data *tag_data)
294 {
295  FILE *F;
296  if (!(F = fopen(filename, "w"))) {
297  printf("fopen (%s, w)\n", filename);
298  return -1;
299  }
300 
301  if (1 != fwrite(tag_data->ndef_file + 2, tag_data->ndef_file_len - 2, 1, F)) {
302  printf("fwrite (%d)\n", (int) tag_data->ndef_file_len - 2);
303  fclose(F);
304  return -1;
305  }
306 
307  fclose(F);
308  return tag_data->ndef_file_len - 2;
309 }
310 
311 static void
312 usage(char *progname)
313 {
314  fprintf(stderr, "usage: %s [-1] [infile [outfile]]\n", progname);
315  fprintf(stderr, " -1: force Tag Type 4 v1.0 (default is v2.0)\n");
316 }
317 
318 int
319 main(int argc, char *argv[])
320 {
321  int options = 0;
322  nfc_target nt = {
323  .nm = {
324  .nmt = NMT_ISO14443A,
325  .nbr = NBR_UNDEFINED, // Will be updated by nfc_target_init()
326  },
327  .nti = {
328  .nai = {
329  .abtAtqa = { 0x00, 0x04 },
330  .abtUid = { 0x08, 0x00, 0xb0, 0x0b },
331  .szUidLen = 4,
332  .btSak = 0x20,
333  .abtAts = { 0x75, 0x33, 0x92, 0x03 }, /* Not used by PN532 */
334  .szAtsLen = 4,
335  },
336  },
337  };
338 
339  uint8_t ndef_file[0xfffe] = {
340  0x00, 33,
341  0xd1, 0x02, 0x1c, 0x53, 0x70, 0x91, 0x01, 0x09, 0x54, 0x02,
342  0x65, 0x6e, 0x4c, 0x69, 0x62, 0x6e, 0x66, 0x63, 0x51, 0x01,
343  0x0b, 0x55, 0x03, 0x6c, 0x69, 0x62, 0x6e, 0x66, 0x63, 0x2e,
344  0x6f, 0x72, 0x67
345  };
346 
347  struct nfcforum_tag4_ndef_data nfcforum_tag4_data = {
348  .ndef_file = ndef_file,
349  .ndef_file_len = ndef_file[1] + 2,
350  };
351 
352  struct nfcforum_tag4_state_machine_data state_machine_data = {
353  .current_file = NONE,
354  };
355 
356  struct nfc_emulation_state_machine state_machine = {
357  .io = nfcforum_tag4_io,
358  .data = &state_machine_data,
359  };
360 
361  struct nfc_emulator emulator = {
362  .target = &nt,
363  .state_machine = &state_machine,
364  .user_data = &nfcforum_tag4_data,
365  };
366 
367  if ((argc > (1 + options)) && (0 == strcmp("-h", argv[1 + options]))) {
368  usage(argv[0]);
369  exit(EXIT_SUCCESS);
370  }
371 
372  if ((argc > (1 + options)) && (0 == strcmp("-1", argv[1 + options]))) {
373  type4v = 1;
374  nfcforum_capability_container[2] = 0x10;
375  options += 1;
376  }
377 
378  if (argc > (3 + options)) {
379  usage(argv[0]);
380  exit(EXIT_FAILURE);
381  }
382 
383  // If some file is provided load it
384  if (argc >= (2 + options)) {
385  if (ndef_message_load(argv[1 + options], &nfcforum_tag4_data) < 0) {
386  printf("Can't load NDEF file '%s'\n", argv[1 + options]);
387  exit(EXIT_FAILURE);
388  }
389  }
390 
391  nfc_init(&context);
392  if (context == NULL) {
393  ERR("Unable to init libnfc (malloc)\n");
394  exit(EXIT_FAILURE);
395  }
396 
397  // Try to open the NFC reader
398  pnd = nfc_open(context, NULL);
399 
400  if (pnd == NULL) {
401  ERR("Unable to open NFC device");
402  nfc_exit(context);
403  exit(EXIT_FAILURE);
404  }
405 
406  signal(SIGINT, stop_emulation);
407 
408  printf("NFC device: %s opened\n", nfc_device_get_name(pnd));
409  printf("Emulating NDEF tag now, please touch it with a second NFC device\n");
410 
411  if (0 != nfc_emulate_target(pnd, &emulator, 0)) { // contains already nfc_target_init() call
412  nfc_perror(pnd, "nfc_emulate_target");
413  nfc_close(pnd);
414  nfc_exit(context);
415  exit(EXIT_FAILURE);
416  }
417 
418  if (argc == (3 + options)) {
419  if (ndef_message_save(argv[2 + options], &nfcforum_tag4_data) < 0) {
420  printf("Can't save NDEF file '%s'", argv[2 + options]);
421  nfc_close(pnd);
422  nfc_exit(context);
423  exit(EXIT_FAILURE);
424  }
425  }
426 
427  nfc_close(pnd);
428  nfc_exit(context);
429  exit(EXIT_SUCCESS);
430 }
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_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_emulation_state_machine
NFC emulation state machine structure.
Definition: nfc-emulation.h:59
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_emulator
NFC emulator structure.
Definition: nfc-emulation.h:49
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-emulation.h
Provide a small API to ease emulation in libnfc.
ERR
#define ERR(...)
Print a error message.
Definition: nfc-utils.h:85
nfc_abort_command
int nfc_abort_command(nfc_device *pnd)
Abort current running command.
Definition: nfc.c:991
nfc_close
void nfc_close(nfc_device *pnd)
Close from a NFC device.
Definition: nfc.c:300
nfc-utils.h
Provide some examples shared functions like print, parity calculation, options parsing.
nfc_emulate_target
int nfc_emulate_target(nfc_device *pnd, struct nfc_emulator *emulator, const int timeout)
Emulate a target.
Definition: nfc-emulation.c:48
nfc.h
libnfc interface