libnfc 1.8.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
78static nfc_device *pnd;
79static nfc_context *context;
80static bool quiet_output = false;
81// Version of the emulated type4 tag:
82static int type4v = 2;
83
84#define SYMBOL_PARAM_fISO14443_4_PICC 0x20
85
86typedef enum { NONE, CC_FILE, NDEF_FILE } file;
87
88struct nfcforum_tag4_ndef_data {
89 uint8_t *ndef_file;
90 size_t ndef_file_len;
91};
92
93struct nfcforum_tag4_state_machine_data {
94 file current_file;
95};
96
97uint8_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
125static int
126nfcforum_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
243static void stop_emulation(int sig)
244{
245 (void) sig;
246 if (pnd != NULL) {
248 } else {
249 nfc_exit(context);
250 exit(EXIT_FAILURE);
251 }
252}
253
254static int
255ndef_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
292static int
293ndef_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
311static void
312usage(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
318int
319main(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}
const char * nfc_device_get_name(nfc_device *pnd)
Returns the device name.
Definition: nfc.c:1209
void nfc_close(nfc_device *pnd)
Close from a NFC device.
Definition: nfc.c:339
nfc_device * nfc_open(nfc_context *context, const nfc_connstring connstring)
Open a NFC device.
Definition: nfc.c:277
int nfc_abort_command(nfc_device *pnd)
Abort current running command.
Definition: nfc.c:1036
void nfc_perror(const nfc_device *pnd, const char *pcString)
Display the last error occured on a nfc_device.
Definition: nfc.c:1183
void nfc_exit(nfc_context *context)
Deinitialize libnfc. Should be called after closing all open devices and before your application term...
Definition: nfc.c:248
void nfc_init(nfc_context **context)
Initialize libnfc. This function must be called before calling any other libnfc function.
Definition: nfc.c:231
int nfc_emulate_target(nfc_device *pnd, struct nfc_emulator *emulator, const int timeout)
Emulate a target.
Definition: nfc-emulation.c:48
Provide a small API to ease emulation in libnfc.
Provide some examples shared functions like print, parity calculation, options parsing.
#define ERR(...)
Print a error message.
Definition: nfc-utils.h:85
libnfc interface
NFC library context Struct which contains internal options, references, pointers, etc....
Definition: nfc-internal.h:175
NFC device information.
Definition: nfc-internal.h:190
NFC emulation state machine structure.
Definition: nfc-emulation.h:59
NFC emulator structure.
Definition: nfc-emulation.h:49
NFC target structure.
Definition: nfc-types.h:351