1 /*-
2 * Copyright (C) 2010, Romain Tartiere.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by the
6 * Free Software Foundation, either version 3 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>
16 *
17 * $Id$
18 */
19
20 /*
21 * This implementation was written based on information provided by the
22 * following documents:
23 *
24 * Contactless Single-trip Ticket IC
25 * MF0 IC U1
26 * Functional Specification
27 * Revision 3.0
28 * March 2003
29 */
30
31 #include "config.h"
32
33 #if defined(HAVE_SYS_TYPES_H)
34 # include <sys/types.h>
35 #endif
36
37 #include <errno.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 #ifdef WITH_DEBUG
42 # include <libutil.h>
43 #endif
44
45 #include <freefare.h>
46 #include "freefare_internal.h"
47
48 #define ASSERT_VALID_PAGE(tag, page, mode_write) \
49 do { \
50 if (IS_MIFARE_ULTRALIGHT_C(tag)) { \
51 if (mode_write) { \
52 if (page >= MIFARE_ULTRALIGHT_C_PAGE_COUNT) return errno = EINVAL, -1; \
53 } else { \
54 if (page >= MIFARE_ULTRALIGHT_C_PAGE_COUNT_READ) return errno = EINVAL, -1; \
55 } \
56 } else { \
57 if (page >= MIFARE_ULTRALIGHT_PAGE_COUNT) return errno = EINVAL, -1; \
58 } \
59 } while (0)
60
61 #define ULTRALIGHT_TRANSCEIVE(tag, msg, res) \
62 do { \
63 errno = 0; \
64 DEBUG_XFER (msg, __##msg##_n, "===> "); \
65 int _res; \
66 if ((_res = nfc_initiator_transceive_bytes (tag->device, msg, __##msg##_n, res, __##res##_size, 0)) < 0) { \
67 return errno = EIO, -1; \
68 } \
69 __##res##_n = _res; \
70 DEBUG_XFER (res, __##res##_n, "<=== "); \
71 } while (0)
72
73 #define ULTRALIGHT_TRANSCEIVE_RAW(tag, msg, res) \
74 do { \
75 errno = 0; \
76 if (nfc_device_set_property_bool (tag->device, NP_EASY_FRAMING, false) < 0) { \
77 errno = EIO; \
78 return -1; \
79 } \
80 DEBUG_XFER (msg, __##msg##_n, "===> "); \
81 int _res; \
82 if ((_res = nfc_initiator_transceive_bytes (tag->device, msg, __##msg##_n, res, __##res##_size, 0)) < 0) { \
83 nfc_device_set_property_bool (tag->device, NP_EASY_FRAMING, true); \
84 return errno = EIO, -1; \
85 } \
86 __##res##_n = _res; \
87 DEBUG_XFER (res, __##res##_n, "<=== "); \
88 if (nfc_device_set_property_bool (tag->device, NP_EASY_FRAMING, true) < 0) { \
89 errno = EIO; \
90 return -1; \
91 } \
92 } while (0)
93
94
95 /*
96 * Memory management functions.
97 */
98
99 /*
100 * Allocates and initialize a MIFARE UltraLight tag.
101 */
102 MifareTag
mifare_ultralight_tag_new(void)103 mifare_ultralight_tag_new (void)
104 {
105 return malloc (sizeof (struct mifare_ultralight_tag));
106 }
107
108 /*
109 * Free the provided tag.
110 */
111 void
mifare_ultralight_tag_free(MifareTag tag)112 mifare_ultralight_tag_free (MifareTag tag)
113 {
114 free (tag);
115 }
116
117
118 /*
119 * MIFARE card communication preparation functions
120 *
121 * The following functions send NFC commands to the initiator to prepare
122 * communication with a MIFARE card, and perform required cleanups after using
123 * the target.
124 */
125
126
127 /*
128 * Establish connection to the provided tag.
129 */
130 int
mifare_ultralight_connect(MifareTag tag)131 mifare_ultralight_connect (MifareTag tag)
132 {
133 ASSERT_INACTIVE (tag);
134 ASSERT_MIFARE_ULTRALIGHT (tag);
135
136 nfc_target pnti;
137 nfc_modulation modulation = {
138 .nmt = NMT_ISO14443A,
139 .nbr = NBR_106
140 };
141 if (nfc_initiator_select_passive_target (tag->device, modulation, tag->info.abtUid, tag->info.szUidLen, &pnti) >= 0) {
142 tag->active = 1;
143 for (int i = 0; i < MIFARE_ULTRALIGHT_MAX_PAGE_COUNT; i++)
144 MIFARE_ULTRALIGHT(tag)->cached_pages[i] = 0;
145 } else {
146 errno = EIO;
147 return -1;
148 }
149 return 0;
150 }
151
152 /*
153 * Terminate connection with the provided tag.
154 */
155 int
mifare_ultralight_disconnect(MifareTag tag)156 mifare_ultralight_disconnect (MifareTag tag)
157 {
158 ASSERT_ACTIVE (tag);
159 ASSERT_MIFARE_ULTRALIGHT (tag);
160
161 if (nfc_initiator_deselect_target (tag->device) >= 0) {
162 tag->active = 0;
163 } else {
164 errno = EIO;
165 return -1;
166 }
167 return 0;
168 }
169
170
171 /*
172 * Card manipulation functions
173 *
174 * The following functions perform direct communication with the connected
175 * MIFARE UltraLight tag.
176 */
177
178 /*
179 * Read data from the provided MIFARE tag.
180 */
181 int
mifare_ultralight_read(MifareTag tag,MifareUltralightPageNumber page,MifareUltralightPage * data)182 mifare_ultralight_read (MifareTag tag, MifareUltralightPageNumber page, MifareUltralightPage *data)
183 {
184 ASSERT_ACTIVE (tag);
185 ASSERT_MIFARE_ULTRALIGHT (tag);
186 ASSERT_VALID_PAGE (tag, page, false);
187
188 if (!MIFARE_ULTRALIGHT(tag)->cached_pages[page]) {
189 BUFFER_INIT (cmd, 2);
190 BUFFER_ALIAS (res, MIFARE_ULTRALIGHT(tag)->cache[page], sizeof(MifareUltralightPage) * 4);
191
192 BUFFER_APPEND (cmd, 0x30);
193 BUFFER_APPEND (cmd, page);
194
195 ULTRALIGHT_TRANSCEIVE (tag, cmd, res);
196
197 /* Handle wrapped pages */
198 int iPageCount;
199 if (IS_MIFARE_ULTRALIGHT_C(tag)) {
200 iPageCount = MIFARE_ULTRALIGHT_C_PAGE_COUNT_READ;
201 } else {
202 iPageCount = MIFARE_ULTRALIGHT_PAGE_COUNT;
203 }
204 for (int i = iPageCount; i <= page + 3; i++) {
205 memcpy (MIFARE_ULTRALIGHT(tag)->cache[i % iPageCount], MIFARE_ULTRALIGHT(tag)->cache[i], sizeof (MifareUltralightPage));
206 }
207
208 /* Mark pages as cached */
209 for (int i = page; i <= page + 3; i++) {
210 MIFARE_ULTRALIGHT(tag)->cached_pages[i % iPageCount] = 1;
211 }
212 }
213
214 memcpy (data, MIFARE_ULTRALIGHT(tag)->cache[page], sizeof (*data));
215 return 0;
216 }
217
218 /*
219 * Read data to the provided MIFARE tag.
220 */
221 int
mifare_ultralight_write(MifareTag tag,const MifareUltralightPageNumber page,const MifareUltralightPage data)222 mifare_ultralight_write (MifareTag tag, const MifareUltralightPageNumber page, const MifareUltralightPage data)
223 {
224 ASSERT_ACTIVE (tag);
225 ASSERT_MIFARE_ULTRALIGHT (tag);
226 ASSERT_VALID_PAGE (tag, page, true);
227
228 BUFFER_INIT (cmd, 6);
229 BUFFER_INIT (res, 1);
230
231 BUFFER_APPEND (cmd, 0xA2);
232 BUFFER_APPEND (cmd, page);
233 BUFFER_APPEND_BYTES (cmd, data, sizeof (MifareUltralightPage));
234
235 ULTRALIGHT_TRANSCEIVE (tag, cmd, res);
236
237 /* Invalidate page in cache */
238 MIFARE_ULTRALIGHT(tag)->cached_pages[page] = 0;
239
240 return 0;
241 }
242
243 /*
244 * Authenticate to the provided MIFARE tag.
245 */
246 int
mifare_ultralightc_authenticate(MifareTag tag,const MifareDESFireKey key)247 mifare_ultralightc_authenticate (MifareTag tag, const MifareDESFireKey key)
248 {
249 ASSERT_ACTIVE (tag);
250 ASSERT_MIFARE_ULTRALIGHT_C (tag);
251
252 BUFFER_INIT (cmd1, 2);
253 BUFFER_INIT (res, 9);
254 BUFFER_APPEND (cmd1, 0x1A);
255 BUFFER_APPEND (cmd1, 0x00);
256
257 ULTRALIGHT_TRANSCEIVE_RAW(tag, cmd1, res);
258
259 uint8_t PICC_E_RndB[8];
260 memcpy (PICC_E_RndB, res+1, 8);
261
262 uint8_t PICC_RndB[8];
263 memcpy (PICC_RndB, PICC_E_RndB, 8);
264 uint8_t ivect[8];
265 memset (ivect, '\0', sizeof (ivect));
266 mifare_cypher_single_block (key, PICC_RndB, ivect, MCD_RECEIVE, MCO_DECYPHER, 8);
267
268 uint8_t PCD_RndA[8];
269 DES_random_key ((DES_cblock*)&PCD_RndA);
270
271 uint8_t PCD_r_RndB[8];
272 memcpy (PCD_r_RndB, PICC_RndB, 8);
273 rol (PCD_r_RndB, 8);
274
275 uint8_t token[16];
276 memcpy (token, PCD_RndA, 8);
277 memcpy (token+8, PCD_r_RndB, 8);
278 size_t offset = 0;
279
280 while (offset < 16) {
281 mifare_cypher_single_block (key, token + offset, ivect, MCD_SEND, MCO_ENCYPHER, 8);
282 offset += 8;
283 }
284
285 BUFFER_INIT (cmd2, 17);
286
287 BUFFER_APPEND (cmd2, 0xAF);
288 BUFFER_APPEND_BYTES (cmd2, token, 16);
289
290 ULTRALIGHT_TRANSCEIVE_RAW(tag, cmd2, res);
291
292 uint8_t PICC_E_RndA_s[8];
293 memcpy (PICC_E_RndA_s, res+1, 8);
294
295 uint8_t PICC_RndA_s[8];
296 memcpy (PICC_RndA_s, PICC_E_RndA_s, 8);
297 mifare_cypher_single_block (key, PICC_RndA_s, ivect, MCD_RECEIVE, MCO_DECYPHER, 8);
298
299 uint8_t PCD_RndA_s[8];
300 memcpy (PCD_RndA_s, PCD_RndA, 8);
301 rol (PCD_RndA_s, 8);
302
303 if (0 != memcmp (PCD_RndA_s, PICC_RndA_s, 8)) {
304 return -1;
305 }
306 // XXX Should we store the state "authenticated" in the tag struct??
307 return 0;
308 }
309
310 /*
311 * Callback for freefare_tag_new to test presence of a MIFARE UltralightC on the reader.
312 */
313 bool
is_mifare_ultralightc_on_reader(nfc_device * device,nfc_iso14443a_info nai)314 is_mifare_ultralightc_on_reader (nfc_device *device, nfc_iso14443a_info nai)
315 {
316 int ret;
317 uint8_t cmd_step1[2];
318 uint8_t res_step1[9];
319 cmd_step1[0] = 0x1A;
320 cmd_step1[1] = 0x00;
321
322 nfc_target pnti;
323 nfc_modulation modulation = {
324 .nmt = NMT_ISO14443A,
325 .nbr = NBR_106
326 };
327 nfc_initiator_select_passive_target (device, modulation, nai.abtUid, nai.szUidLen, &pnti);
328 nfc_device_set_property_bool (device, NP_EASY_FRAMING, false);
329 ret = nfc_initiator_transceive_bytes (device, cmd_step1, sizeof (cmd_step1), res_step1, sizeof(res_step1), 0);
330 nfc_device_set_property_bool (device, NP_EASY_FRAMING, true);
331 nfc_initiator_deselect_target (device);
332 return ret >= 0;
333 }
334