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