]> git.zerfleddert.de Git - proxmark3-svn/blob - client/cmdhftopaz.c
add: hf topaz reader (basic functionality)
[proxmark3-svn] / client / cmdhftopaz.c
1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2015 Piwi
3 //
4 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
5 // at your option, any later version. See the LICENSE.txt file for the text of
6 // the license.
7 //-----------------------------------------------------------------------------
8 // High frequency Topaz (NFC Type 1) commands
9 //-----------------------------------------------------------------------------
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include "cmdmain.h"
16 #include "cmdparser.h"
17 #include "cmdhftopaz.h"
18 #include "cmdhf14a.h"
19 #include "ui.h"
20 #include "mifare.h"
21 #include "proxmark3.h"
22 #include "iso14443crc.h"
23 #include "protocols.h"
24
25
26
27
28 static void topaz_switch_on_field(void)
29 {
30 UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_SELECT | ISO14A_NO_DISCONNECT | ISO14A_TOPAZMODE, 0, 0}};
31 SendCommand(&c);
32 }
33
34
35 static void topaz_switch_off_field(void)
36 {
37 UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}};
38 SendCommand(&c);
39 }
40
41
42 static int topaz_send_cmd_raw(uint8_t *cmd, uint8_t len, uint8_t *response)
43 {
44 UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT | ISO14A_TOPAZMODE, len, 0}};
45 memcpy(c.d.asBytes, cmd, len);
46 SendCommand(&c);
47
48 UsbCommand resp;
49 WaitForResponse(CMD_ACK, &resp);
50
51 if (resp.arg[0] > 0) {
52 memcpy(response, resp.d.asBytes, resp.arg[0]);
53 }
54
55 return resp.arg[0];
56 }
57
58
59 static int topaz_send_cmd(uint8_t *cmd, uint8_t len, uint8_t *response)
60 {
61 if (len > 1) {
62 uint8_t first, second;
63 ComputeCrc14443(CRC_14443_B, cmd, len-2, &first, &second);
64 cmd[len-2] = first;
65 cmd[len-1] = second;
66 }
67
68 return topaz_send_cmd_raw(cmd, len, response);
69 }
70
71
72 static int topaz_select(uint8_t *atqa, uint8_t *rid_response)
73 {
74 // ToDo: implement anticollision
75
76 uint8_t wupa_cmd[] = {TOPAZ_WUPA};
77 uint8_t rid_cmd[] = {TOPAZ_RID, 0, 0, 0, 0, 0, 0, 0, 0};
78
79 topaz_switch_on_field();
80
81 if (!topaz_send_cmd(wupa_cmd, sizeof(wupa_cmd), atqa)) {
82 topaz_switch_off_field();
83 return -1; // WUPA failed
84 }
85
86 if (!topaz_send_cmd(rid_cmd, sizeof(rid_cmd), rid_response)) {
87 topaz_switch_off_field();
88 return -2; // RID failed
89 }
90
91 return 0; // OK
92 }
93
94
95 static int topaz_rall(uint8_t *uid, uint8_t *rall_response)
96 {
97 uint8_t rall_cmd[] = {TOPAZ_RALL, 0, 0, 0, 0, 0, 0, 0, 0};
98
99 memcpy(&rall_cmd[3], uid, 4);
100 if (!topaz_send_cmd(rall_cmd, sizeof(rall_cmd), rall_response)) {
101 topaz_switch_off_field();
102 return -1; // RALL failed
103 }
104
105 return 0;
106 }
107
108
109 static bool topaz_block_is_locked(uint8_t blockno, uint8_t *lockbits)
110 {
111 if(lockbits[blockno/8] >> (blockno % 8) & 0x01) {
112 return true;
113 } else {
114 return false;
115 }
116 }
117
118
119 static int topaz_print_CC(uint8_t *data)
120 {
121 if(data[0] != 0xe1) {
122 return -1; // no NDEF message
123 }
124
125 PrintAndLog("Capability Container: %02x %02x %02x %02x", data[0], data[1], data[2], data[3]);
126 PrintAndLog(" %02x: NDEF Magic Number", data[0]);
127 PrintAndLog(" %02x: version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f);
128 PrintAndLog(" %02x: Physical Memory Size of this tag: %d bytes", data[2], (data[2] + 1) * 8);
129 PrintAndLog(" %02x: %s / %s", data[3],
130 (data[3] & 0xF0) ? "(RFU)" : "Read access granted without any security",
131 (data[3] & 0x0F)==0 ? "Write access granted without any security" : (data[3] & 0x0F)==0x0F ? "No write access granted at all" : "(RFU)");
132 return 0;
133 }
134
135
136 static void get_TLV(uint8_t **TLV_ptr, uint8_t *tag, uint16_t *length, uint8_t **value)
137 {
138 *length = 0;
139 *value = NULL;
140
141 *tag = **TLV_ptr;
142 *TLV_ptr += 1;
143 switch (*tag) {
144 case 0x00: // NULL TLV.
145 case 0xFE: // Terminator TLV.
146 break;
147 case 0x01: // Lock Control TLV
148 case 0x02: // Reserved Memory TLV
149 case 0x03: // NDEF message TLV
150 case 0xFD: // proprietary TLV
151 *length = **TLV_ptr;
152 *TLV_ptr += 1;
153 if (*length == 0xff) {
154 *length = **TLV_ptr << 8;
155 *TLV_ptr += 1;
156 *length |= **TLV_ptr;
157 *TLV_ptr += 1;
158 }
159 *value = *TLV_ptr;
160 *TLV_ptr += *length;
161 break;
162 default: // RFU
163 break;
164 }
165 }
166
167
168 static bool topaz_print_lock_control_TLVs(uint8_t *memory)
169 {
170 uint8_t *TLV_ptr = memory;
171 uint8_t tag = 0;
172 uint16_t length;
173 uint8_t *value;
174 bool lock_TLV_present = false;
175
176 while(*TLV_ptr != 0x03 && *TLV_ptr != 0xFD && *TLV_ptr != 0xFE) {
177 // all Lock Control TLVs shall be present before the NDEF message TLV, the proprietary TLV (and the Terminator TLV)
178 get_TLV(&TLV_ptr, &tag, &length, &value);
179 if (tag == 0x01) { // the Lock Control TLV
180 uint8_t pages_addr = value[0] >> 4;
181 uint8_t byte_offset = value[0] & 0x0f;
182 uint8_t size_in_bits = value[1] ? value[1] : 256;
183 uint8_t bytes_per_page = 1 << (value[2] & 0x0f);
184 uint8_t bytes_locked_per_bit = 1 << (value[2] >> 4);
185 PrintAndLog("Lock Area of %d bits at byte offset 0x%02x. Each Lock Bit locks %d bytes.",
186 size_in_bits,
187 pages_addr * bytes_per_page + byte_offset,
188 bytes_locked_per_bit);
189 lock_TLV_present = true;
190 }
191 }
192
193 if (!lock_TLV_present) {
194 PrintAndLog("(No Lock Control TLV present)");
195 return -1;
196 } else {
197 return 0;
198 }
199 }
200
201
202 static int topaz_print_reserved_memory_control_TLVs(uint8_t *memory)
203 {
204 uint8_t *TLV_ptr = memory;
205 uint8_t tag = 0;
206 uint16_t length;
207 uint8_t *value;
208 bool reserved_memory_control_TLV_present = false;
209
210 while(*TLV_ptr != 0x03 && *TLV_ptr != 0xFD && *TLV_ptr != 0xFE) {
211 // all Reserved Memory Control TLVs shall be present before the NDEF message TLV, the proprietary TLV (and the Terminator TLV)
212 get_TLV(&TLV_ptr, &tag, &length, &value);
213 if (tag == 0x02) { // the Reserved Memory Control TLV
214 uint8_t pages_addr = value[0] >> 4;
215 uint8_t byte_offset = value[0] & 0x0f;
216 uint8_t size_in_bytes = value[1] ? value[1] : 256;
217 uint8_t bytes_per_page = 1 << (value[2] & 0x0f);
218 PrintAndLog("Reserved Memory of %d bytes at byte offset 0x%02x.",
219 size_in_bytes,
220 pages_addr * bytes_per_page + byte_offset);
221 reserved_memory_control_TLV_present = true;
222 }
223 }
224
225 if (!reserved_memory_control_TLV_present) {
226 PrintAndLog("(No Reserved Memory Control TLV present)");
227 return -1;
228 } else {
229 return 0;
230 }
231 }
232
233
234 static void topaz_print_lifecycle_state(uint8_t *data)
235 {
236
237 }
238
239
240 static void topaz_print_NDEF(uint8_t *data)
241 {
242
243 }
244
245
246 int CmdHFTopazReader(const char *Cmd)
247 {
248 int status;
249 uint8_t atqa[2];
250 uint8_t rid_response[8];
251 uint8_t *uid_echo = &rid_response[2];
252 union {
253 uint8_t raw_content[124];
254 struct {
255 uint8_t HR[2];
256 uint8_t data_block[15][8];
257 uint8_t CRC[2];
258 } static_memory;
259 } rall_response;
260 uint8_t *static_lock_bytes = rall_response.static_memory.data_block[0x0e];
261
262 status = topaz_select(atqa, rid_response);
263
264 if (status == -1) {
265 PrintAndLog("Error: couldn't receive ATQA");
266 return -1;
267 }
268
269 PrintAndLog("ATQA : %02x %02x", atqa[1], atqa[0]);
270 if (atqa[1] != 0x0c && atqa[0] != 0x00) {
271 PrintAndLog("Tag doesn't support the Topaz protocol.");
272 topaz_switch_off_field();
273 return -1;
274 }
275
276 if (status == -2) {
277 PrintAndLog("Error: tag didn't answer to RID");
278 topaz_switch_off_field();
279 return -1;
280 }
281
282 // ToDo: CRC check
283 PrintAndLog("HR0 : %02x (%sa Topaz tag (%scapable of carrying a NDEF message), %s memory map)", rid_response[0],
284 (rid_response[0] & 0xF0) == 0x10 ? "" : "not ",
285 (rid_response[0] & 0xF0) == 0x10 ? "" : "not ",
286 (rid_response[0] & 0x0F) == 0x10 ? "static" : "dynamic");
287 PrintAndLog("HR1 : %02x", rid_response[1]);
288
289 status = topaz_rall(uid_echo, rall_response.raw_content);
290
291 if(status == -1) {
292 PrintAndLog("Error: tag didn't answer to RALL");
293 topaz_switch_off_field();
294 return -1;
295 }
296
297 PrintAndLog("UID : %02x %02x %02x %02x %02x %02x %02x",
298 rall_response.static_memory.data_block[0][6],
299 rall_response.static_memory.data_block[0][5],
300 rall_response.static_memory.data_block[0][4],
301 rall_response.static_memory.data_block[0][3],
302 rall_response.static_memory.data_block[0][2],
303 rall_response.static_memory.data_block[0][1],
304 rall_response.static_memory.data_block[0][0]);
305 PrintAndLog(" UID[6] (Manufacturer Byte) = %02x, Manufacturer: %s",
306 rall_response.static_memory.data_block[0][6],
307 getTagInfo(rall_response.static_memory.data_block[0][6]));
308
309 PrintAndLog("");
310 PrintAndLog("Static Data blocks 00 to 0c:");
311 PrintAndLog("block# | offset | Data | Locked?");
312 char line[80];
313 for (uint16_t i = 0; i <= 0x0c; i++) {
314 for (uint16_t j = 0; j < 8; j++) {
315 sprintf(&line[3*j], "%02x ", rall_response.static_memory.data_block[i][j] /*rall_response[2 + 8*i + j]*/);
316 }
317 PrintAndLog(" 0x%02x | 0x%02x | %s| %-3s", i, i*8, line, topaz_block_is_locked(i, static_lock_bytes) ? "yes" : "no");
318 }
319
320 PrintAndLog("");
321 PrintAndLog("Static Reserved block 0d:");
322 for (uint16_t j = 0; j < 8; j++) {
323 sprintf(&line[3*j], "%02x ", rall_response.static_memory.data_block[0x0d][j]);
324 }
325 PrintAndLog(" 0x%02x | 0x%02x | %s| %-3s", 0x0d, 0x0d*8, line, "n/a");
326
327 PrintAndLog("");
328 PrintAndLog("Static Lockbits / OTP block 0e:");
329 for (uint16_t j = 0; j < 8; j++) {
330 sprintf(&line[3*j], "%02x ", static_lock_bytes[j]);
331 }
332 PrintAndLog(" 0x%02x | 0x%02x | %s| %-3s", 0x0e, 0x0e*8, line, "n/a");
333
334 PrintAndLog("");
335
336 status = topaz_print_CC(&rall_response.static_memory.data_block[1][0]);
337
338 if (status == -1) {
339 PrintAndLog("No NDEF message present");
340 topaz_switch_off_field();
341 return 0;
342 }
343
344 PrintAndLog("");
345 bool lock_TLV_present = topaz_print_lock_control_TLVs(&rall_response.static_memory.data_block[1][4]);
346
347 PrintAndLog("");
348 bool reserved_mem_present = topaz_print_reserved_memory_control_TLVs(&rall_response.static_memory.data_block[1][4]);
349
350 topaz_print_lifecycle_state(&rall_response.static_memory.data_block[1][0]);
351
352 topaz_print_NDEF(&rall_response.static_memory.data_block[1][0]);
353
354 topaz_switch_off_field();
355 return 0;
356 }
357
358
359 int CmdHFTopazSim(const char *Cmd)
360 {
361 PrintAndLog("not yet implemented");
362 return 0;
363 }
364
365
366 int CmdHFTopazCmdRaw(const char *Cmd)
367 {
368 PrintAndLog("not yet implemented");
369 return 0;
370 }
371
372
373 static int CmdHelp(const char *Cmd);
374
375
376 static command_t CommandTable[] =
377 {
378 {"help", CmdHelp, 1, "This help"},
379 {"reader", CmdHFTopazReader, 0, "Act like a Topaz reader"},
380 {"sim", CmdHFTopazSim, 0, "<UID> -- Simulate Topaz tag"},
381 {"snoop", CmdHF14ASnoop, 0, "Eavesdrop a Topaz reader-tag communication"},
382 {"raw", CmdHFTopazCmdRaw, 0, "Send raw hex data to tag"},
383 {NULL, NULL, 0, NULL}
384 };
385
386
387 int CmdHFTopaz(const char *Cmd) {
388 // flush
389 WaitForResponseTimeout(CMD_ACK,NULL,100);
390
391 // parse
392 CmdsParse(CommandTable, Cmd);
393 return 0;
394 }
395
396 static int CmdHelp(const char *Cmd)
397 {
398 CmdsHelp(CommandTable);
399 return 0;
400 }
401
402
Impressum, Datenschutz