libnfc  1.7.0
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  if (stat(filename, &sb) < 0) {
259  printf("file not found or not accessible '%s'", filename);
260  return -1;
261  }
262 
263  /* Check file size */
264  if (sb.st_size > 0xFFFF) {
265  printf("file size too large '%s'", filename);
266  return -1;
267  }
268 
269  tag_data->ndef_file_len = sb.st_size + 2;
270 
271  tag_data->ndef_file[0] = (uint8_t)(sb.st_size >> 8);
272  tag_data->ndef_file[1] = (uint8_t)(sb.st_size);
273 
274  FILE *F;
275  if (!(F = fopen(filename, "r"))) {
276  printf("fopen (%s, \"r\")", filename);
277  return -1;
278  }
279 
280  if (1 != fread(tag_data->ndef_file + 2, sb.st_size, 1, F)) {
281  printf("Can't read from %s", filename);
282  fclose(F);
283  return -1;
284  }
285 
286  fclose(F);
287  return sb.st_size;
288 }
289 
290 static int
291 ndef_message_save(char *filename, struct nfcforum_tag4_ndef_data *tag_data)
292 {
293  FILE *F;
294  if (!(F = fopen(filename, "w"))) {
295  printf("fopen (%s, w)", filename);
296  return -1;
297  }
298 
299  if (1 != fwrite(tag_data->ndef_file + 2, tag_data->ndef_file_len - 2, 1, F)) {
300  printf("fwrite (%d)", (int) tag_data->ndef_file_len - 2);
301  fclose(F);
302  return -1;
303  }
304 
305  fclose(F);
306  return tag_data->ndef_file_len - 2;
307 }
308 
309 static void
310 usage(char *progname)
311 {
312  fprintf(stderr, "usage: %s [-1] [infile [outfile]]\n", progname);
313  fprintf(stderr, " -1: force Tag Type 4 v1.0 (default is v2.0)\n");
314 }
315 
316 int
317 main(int argc, char *argv[])
318 {
319  int options = 0;
320  nfc_target nt = {
321  .nm = {
322  .nmt = NMT_ISO14443A,
323  .nbr = NBR_UNDEFINED, // Will be updated by nfc_target_init()
324  },
325  .nti = {
326  .nai = {
327  .abtAtqa = { 0x00, 0x04 },
328  .abtUid = { 0x08, 0x00, 0xb0, 0x0b },
329  .szUidLen = 4,
330  .btSak = 0x20,
331  .abtAts = { 0x75, 0x33, 0x92, 0x03 }, /* Not used by PN532 */
332  .szAtsLen = 4,
333  },
334  },
335  };
336 
337  uint8_t ndef_file[0xfffe] = {
338  0x00, 33,
339  0xd1, 0x02, 0x1c, 0x53, 0x70, 0x91, 0x01, 0x09, 0x54, 0x02,
340  0x65, 0x6e, 0x4c, 0x69, 0x62, 0x6e, 0x66, 0x63, 0x51, 0x01,
341  0x0b, 0x55, 0x03, 0x6c, 0x69, 0x62, 0x6e, 0x66, 0x63, 0x2e,
342  0x6f, 0x72, 0x67
343  };
344 
345  struct nfcforum_tag4_ndef_data nfcforum_tag4_data = {
346  .ndef_file = ndef_file,
347  .ndef_file_len = ndef_file[1] + 2,
348  };
349 
350  struct nfcforum_tag4_state_machine_data state_machine_data = {
351  .current_file = NONE,
352  };
353 
354  struct nfc_emulation_state_machine state_machine = {
355  .io = nfcforum_tag4_io,
356  .data = &state_machine_data,
357  };
358 
359  struct nfc_emulator emulator = {
360  .target = &nt,
361  .state_machine = &state_machine,
362  .user_data = &nfcforum_tag4_data,
363  };
364 
365  if ((argc > (1 + options)) && (0 == strcmp("-h", argv[1 + options]))) {
366  usage(argv[0]);
367  exit(EXIT_SUCCESS);
368  }
369 
370  if ((argc > (1 + options)) && (0 == strcmp("-1", argv[1 + options]))) {
371  type4v = 1;
372  nfcforum_capability_container[2] = 0x10;
373  options += 1;
374  }
375 
376  if (argc > (3 + options)) {
377  usage(argv[0]);
378  exit(EXIT_FAILURE);
379  }
380 
381  // If some file is provided load it
382  if (argc >= (2 + options)) {
383  if (ndef_message_load(argv[1 + options], &nfcforum_tag4_data) < 0) {
384  printf("Can't load NDEF file '%s'", argv[1 + options]);
385  exit(EXIT_FAILURE);
386  }
387  }
388 
389  nfc_init(&context);
390  if (context == NULL) {
391  ERR("Unable to init libnfc (malloc)\n");
392  exit(EXIT_FAILURE);
393  }
394 
395  // Try to open the NFC reader
396  pnd = nfc_open(context, NULL);
397 
398  if (pnd == NULL) {
399  ERR("Unable to open NFC device");
400  nfc_exit(context);
401  exit(EXIT_FAILURE);
402  }
403 
404  signal(SIGINT, stop_emulation);
405 
406  printf("NFC device: %s opened\n", nfc_device_get_name(pnd));
407  printf("Emulating NDEF tag now, please touch it with a second NFC device\n");
408 
409  if (0 != nfc_emulate_target(pnd, &emulator, 0)) { // contains already nfc_target_init() call
410  nfc_perror(pnd, "nfc_emulate_target");
411  nfc_close(pnd);
412  nfc_exit(context);
413  exit(EXIT_FAILURE);
414  }
415 
416  if (argc == (3 + options)) {
417  if (ndef_message_save(argv[2 + options], &nfcforum_tag4_data) < 0) {
418  printf("Can't save NDEF file '%s'", argv[2 + options]);
419  nfc_close(pnd);
420  nfc_exit(context);
421  exit(EXIT_FAILURE);
422  }
423  }
424 
425  nfc_close(pnd);
426  nfc_exit(context);
427  exit(EXIT_SUCCESS);
428 }