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