]> git.zerfleddert.de Git - proxmark3-svn/blame - client/cmdhftopaz.c
add: hf topaz reader (basic functionality)
[proxmark3-svn] / client / cmdhftopaz.c
CommitLineData
05ddb52c 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"
48ece4a7 20#include "mifare.h"
21#include "proxmark3.h"
22#include "iso14443crc.h"
23#include "protocols.h"
24
25
26
de15fc5f 27
48ece4a7 28static 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);
48ece4a7 32}
33
34
35static void topaz_switch_off_field(void)
36{
37 UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}};
38 SendCommand(&c);
48ece4a7 39}
40
41
de15fc5f 42static int topaz_send_cmd_raw(uint8_t *cmd, uint8_t len, uint8_t *response)
48ece4a7 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
de15fc5f 51 if (resp.arg[0] > 0) {
52 memcpy(response, resp.d.asBytes, resp.arg[0]);
53 }
54
55 return resp.arg[0];
48ece4a7 56}
57
58
de15fc5f 59static int topaz_send_cmd(uint8_t *cmd, uint8_t len, uint8_t *response)
48ece4a7 60{
61 if (len > 1) {
62 uint8_t first, second;
de15fc5f 63 ComputeCrc14443(CRC_14443_B, cmd, len-2, &first, &second);
64 cmd[len-2] = first;
65 cmd[len-1] = second;
48ece4a7 66 }
67
de15fc5f 68 return topaz_send_cmd_raw(cmd, len, response);
48ece4a7 69}
70
71
de15fc5f 72static int topaz_select(uint8_t *atqa, uint8_t *rid_response)
48ece4a7 73{
74 // ToDo: implement anticollision
de15fc5f 75
48ece4a7 76 uint8_t wupa_cmd[] = {TOPAZ_WUPA};
de15fc5f 77 uint8_t rid_cmd[] = {TOPAZ_RID, 0, 0, 0, 0, 0, 0, 0, 0};
78
48ece4a7 79 topaz_switch_on_field();
de15fc5f 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
95static 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;
48ece4a7 106}
107
05ddb52c 108
de15fc5f 109static 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
119static 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
136static 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
168static 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
202static 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
234static void topaz_print_lifecycle_state(uint8_t *data)
235{
236
237}
238
239
240static void topaz_print_NDEF(uint8_t *data)
241{
242
243}
244
245
05ddb52c 246int CmdHFTopazReader(const char *Cmd)
247{
de15fc5f 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();
05ddb52c 355 return 0;
356}
357
358
359int CmdHFTopazSim(const char *Cmd)
360{
361 PrintAndLog("not yet implemented");
362 return 0;
363}
364
365
366int CmdHFTopazCmdRaw(const char *Cmd)
367{
368 PrintAndLog("not yet implemented");
369 return 0;
370}
371
372
373static int CmdHelp(const char *Cmd);
374
375
376static 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
387int CmdHFTopaz(const char *Cmd) {
388 // flush
389 WaitForResponseTimeout(CMD_ACK,NULL,100);
390
391 // parse
392 CmdsParse(CommandTable, Cmd);
393 return 0;
394}
395
396static int CmdHelp(const char *Cmd)
397{
398 CmdsHelp(CommandTable);
399 return 0;
400}
401
402
Impressum, Datenschutz