]> git.zerfleddert.de Git - proxmark3-svn/blob - client/fido/cbortools.c
Code improved for less memory
[proxmark3-svn] / client / fido / cbortools.c
1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2018 Merlok
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 // Tools for work with CBOR format http://cbor.io/spec.html
9 // via Intel tinycbor (https://github.com/intel/tinycbor) library
10 //-----------------------------------------------------------------------------
11 //
12
13 #include "cbortools.h"
14
15 #include <stdlib.h>
16 #include <inttypes.h>
17
18 #include "emv/emvjson.h"
19 #include "util.h"
20 #include "fidocore.h"
21
22 static void indent(int nestingLevel) {
23 while (nestingLevel--)
24 printf(" ");
25 }
26
27 static CborError dumpelm(CborValue *it, bool *got_next, int nestingLevel) {
28 CborError err;
29 *got_next = false;
30
31 CborType type = cbor_value_get_type(it);
32 indent(nestingLevel);
33 switch (type) {
34 case CborMapType:
35 case CborArrayType: {
36 printf(type == CborArrayType ? "Array[" : "Map[");
37 break;
38 }
39
40 case CborIntegerType: {
41 int64_t val;
42 cbor_value_get_int64(it, &val); // can't fail
43 printf("%lld", (long long)val);
44 break;
45 }
46
47 case CborByteStringType: {
48 uint8_t *buf;
49 size_t n;
50 err = cbor_value_dup_byte_string(it, &buf, &n, it);
51 *got_next = true;
52 if (err)
53 return err; // parse error
54 printf("%s", sprint_hex(buf, n));
55 free(buf);
56 break;
57 }
58
59 case CborTextStringType: {
60 char *buf;
61 size_t n;
62 err = cbor_value_dup_text_string(it, &buf, &n, it);
63 *got_next = true;
64 if (err)
65 return err; // parse error
66 printf("%s", buf);
67 free(buf);
68 break;
69 }
70
71 case CborTagType: {
72 CborTag tag;
73 cbor_value_get_tag(it, &tag);
74 printf("Tag(%lld)", (long long)tag);
75 break;
76 }
77
78 case CborSimpleType: {
79 uint8_t type;
80 cbor_value_get_simple_type(it, &type);
81 printf("simple(%u)", type);
82 break;
83 }
84
85 case CborNullType:
86 printf("null");
87 break;
88
89 case CborUndefinedType:
90 printf("undefined");
91 break;
92
93 case CborBooleanType: {
94 bool val;
95 cbor_value_get_boolean(it, &val); // can't fail
96 printf("%s", val ? "true" : "false");
97 break;
98 }
99
100 case CborDoubleType: {
101 double val;
102 if (false) {
103 float f;
104 case CborFloatType:
105 cbor_value_get_float(it, &f);
106 val = f;
107 } else {
108 cbor_value_get_double(it, &val);
109 }
110 printf("%g", val);
111 break;
112 }
113 case CborHalfFloatType: {
114 uint16_t val;
115 cbor_value_get_half_float(it, &val);
116 printf("__f16(%04x)", val);
117 break;
118 }
119
120 case CborInvalidType:
121 printf("CborInvalidType!!!");
122 break;
123 }
124
125 return CborNoError;
126 }
127
128 static CborError dumprecursive(uint8_t cmdCode, bool isResponse, CborValue *it, bool isMapType, int nestingLevel) {
129 int elmCount = 0;
130 while (!cbor_value_at_end(it)) {
131 CborError err;
132 CborType type = cbor_value_get_type(it);
133 //printf("^%x^", type);
134 bool got_next;
135
136 switch (type) {
137 case CborMapType:
138 case CborArrayType: {
139 // recursive type
140 CborValue recursed;
141 assert(cbor_value_is_container(it));
142 if (!(isMapType && (elmCount % 2)))
143 indent(nestingLevel);
144 printf(type == CborArrayType ? "Array[\n" : "Map[\n");
145 err = cbor_value_enter_container(it, &recursed);
146 if (err)
147 return err; // parse error
148 err = dumprecursive(cmdCode, isResponse, &recursed, (type == CborMapType), nestingLevel + 1);
149 if (err)
150 return err; // parse error
151 err = cbor_value_leave_container(it, &recursed);
152 if (err)
153 return err; // parse error
154 indent(nestingLevel);
155 printf("]");
156 got_next = true;
157 break;
158 }
159
160 default: {
161 err = dumpelm(it, &got_next, (isMapType && (elmCount % 2)) ? 0 : nestingLevel);
162 if (err)
163 return err;
164 if (cmdCode > 0 && nestingLevel == 1 && isMapType && !(elmCount % 2)) {
165 int64_t val;
166 cbor_value_get_int64(it, &val);
167 char *desc = fido2GetCmdMemberDescription(cmdCode, isResponse, val);
168 if (desc)
169 printf(" (%s)", desc);
170 }
171 break;
172 }
173 }
174
175 if (!got_next) {
176 err = cbor_value_advance_fixed(it);
177 if (err)
178 return err;
179 }
180 if (isMapType && !(elmCount % 2)) {
181 printf(": ");
182 } else {
183 printf("\n");
184 }
185 elmCount++;
186 }
187 return CborNoError;
188 }
189
190 int TinyCborInit(uint8_t *data, size_t length, CborValue *cb) {
191 CborParser parser;
192 CborError err = cbor_parser_init(data, length, 0, &parser, cb);
193 if (err)
194 return err;
195
196 return 0;
197 }
198
199 int TinyCborPrintFIDOPackage(uint8_t cmdCode, bool isResponse, uint8_t *data, size_t length) {
200 CborValue cb;
201 int res;
202 res = TinyCborInit(data, length, &cb);
203 if (res)
204 return res;
205
206 CborError err = dumprecursive(cmdCode, isResponse, &cb, false, 0);
207
208 if (err) {
209 fprintf(stderr,
210 #if __WORDSIZE == 64
211 "CBOR parsing failure at offset %" PRId64 " : %s\n",
212 #else
213 "CBOR parsing failure at offset %" PRId32 " : %s\n",
214 #endif
215 cb.ptr - data, cbor_error_string(err));
216 return 1;
217 }
218
219 return 0;
220 }
221
222 int JsonObjElmCount(json_t *elm) {
223 int res = 0;
224 const char *key;
225 json_t *value;
226
227 if (!json_is_object(elm))
228 return 0;
229
230 json_object_foreach(elm, key, value) {
231 if (strlen(key) > 0 && key[0] != '.')
232 res++;
233 }
234
235 return res;
236 }
237
238 int JsonToCbor(json_t *elm, CborEncoder *encoder) {
239 if (!elm || !encoder)
240 return 1;
241
242 int res;
243
244 // CBOR map == JSON object
245 if (json_is_object(elm)) {
246 CborEncoder map;
247 const char *key;
248 json_t *value;
249
250 res = cbor_encoder_create_map(encoder, &map, JsonObjElmCount(elm));
251 cbor_check(res);
252
253 json_object_foreach(elm, key, value) {
254 if (strlen(key) > 0 && key[0] != '.') {
255 res = cbor_encode_text_stringz(&map, key);
256 cbor_check(res);
257
258 // RECURSION!
259 JsonToCbor(value, &map);
260 }
261 }
262
263 res = cbor_encoder_close_container(encoder, &map);
264 cbor_check(res);
265 }
266
267 // CBOR array == JSON array
268 if (json_is_array(elm)) {
269 size_t index;
270 json_t *value;
271 CborEncoder array;
272
273 res = cbor_encoder_create_array(encoder, &array, json_array_size(elm));
274 cbor_check(res);
275
276 json_array_foreach(elm, index, value) {
277 // RECURSION!
278 JsonToCbor(value, &array);
279 }
280
281 res = cbor_encoder_close_container(encoder, &array);
282 cbor_check(res);
283 }
284
285 if (json_is_boolean(elm)) {
286 res = cbor_encode_boolean(encoder, json_is_true(elm));
287 cbor_check(res);
288 }
289
290 if (json_is_integer(elm)) {
291 res = cbor_encode_int(encoder, json_integer_value(elm));
292 cbor_check(res);
293 }
294
295 if (json_is_real(elm)) {
296 res = cbor_encode_float(encoder, json_real_value(elm));
297 cbor_check(res);
298 }
299
300 if (json_is_string(elm)) {
301 const char * val = json_string_value(elm);
302 if (CheckStringIsHEXValue(val)) {
303 size_t datalen = 0;
304 uint8_t data[4096] = {0};
305 res = JsonLoadBufAsHex(elm, "$", data, sizeof(data), &datalen);
306 if (res)
307 return 100;
308
309 res = cbor_encode_byte_string(encoder, data, datalen);
310 cbor_check(res);
311 } else {
312 res = cbor_encode_text_stringz(encoder, val);
313 cbor_check(res);
314 }
315 }
316
317
318
319 return 0;
320 }
321
322 int CborMapGetKeyById(CborParser *parser, CborValue *map, uint8_t *data, size_t dataLen, int key) {
323 CborValue cb;
324
325 CborError err = cbor_parser_init(data, dataLen, 0, parser, &cb);
326 cbor_check(err);
327
328 if (cbor_value_get_type(&cb) != CborMapType)
329 return 1;
330
331 err = cbor_value_enter_container(&cb, map);
332 cbor_check(err);
333
334 int64_t indx;
335 while (!cbor_value_at_end(map)) {
336 // check number
337 if (cbor_value_get_type(map) != CborIntegerType)
338 return 1;
339
340 cbor_value_get_int64(map, &indx);
341
342 err = cbor_value_advance(map);
343 cbor_check(err);
344
345 if (indx == key)
346 return 0;
347
348 // pass value
349 err = cbor_value_advance(map);
350 cbor_check(err);
351 }
352
353 err = cbor_value_leave_container(&cb, map);
354 cbor_check(err);
355
356 return 2;
357 }
358
359 CborError CborGetArrayBinStringValue(CborValue *elm, uint8_t *data, size_t maxdatalen, size_t *datalen) {
360 return CborGetArrayBinStringValueEx(elm, data, maxdatalen, datalen, NULL, 0);
361 }
362
363 CborError CborGetArrayBinStringValueEx(CborValue *elm, uint8_t *data, size_t maxdatalen, size_t *datalen, uint8_t *delimeter, size_t delimeterlen) {
364 CborValue array;
365 if (datalen)
366 *datalen = 0;
367
368 size_t slen = maxdatalen;
369 size_t totallen = 0;
370
371 CborError res = cbor_value_enter_container(elm, &array);
372 cbor_check(res);
373
374 while (!cbor_value_at_end(&array)) {
375 res = cbor_value_copy_byte_string(&array, &data[totallen], &slen, &array);
376 cbor_check(res);
377
378 totallen += slen;
379 if (delimeter) {
380 memcpy(&data[totallen], delimeter, delimeterlen);
381 totallen += delimeterlen;
382 }
383 slen = maxdatalen - totallen;
384 }
385
386 res = cbor_value_leave_container(elm, &array);
387 cbor_check(res);
388
389 if (datalen)
390 *datalen = totallen;
391
392 return CborNoError;
393 };
394
395 CborError CborGetBinStringValue(CborValue *elm, uint8_t *data, size_t maxdatalen, size_t *datalen) {
396 if (datalen)
397 *datalen = 0;
398
399 size_t slen = maxdatalen;
400
401 CborError res = cbor_value_copy_byte_string(elm, data, &slen, elm);
402 cbor_check(res);
403
404 if (datalen)
405 *datalen = slen;
406
407 return CborNoError;
408 };
409
410 CborError CborGetArrayStringValue(CborValue *elm, char *data, size_t maxdatalen, size_t *datalen, char *delimeter) {
411 CborValue array;
412 if (datalen)
413 *datalen = 0;
414
415 size_t slen = maxdatalen;
416 size_t totallen = 0;
417
418 CborError res = cbor_value_enter_container(elm, &array);
419 cbor_check(res);
420
421 while (!cbor_value_at_end(&array)) {
422 res = cbor_value_copy_text_string(&array, &data[totallen], &slen, &array);
423 cbor_check(res);
424
425 totallen += slen;
426 if (delimeter) {
427 strcat(data, delimeter);
428 totallen += strlen(delimeter);
429 }
430 slen = maxdatalen - totallen;
431 data[totallen] = 0x00;
432 }
433
434 res = cbor_value_leave_container(elm, &array);
435 cbor_check(res);
436
437 if (datalen)
438 *datalen = totallen;
439
440 return CborNoError;
441 };
442
443 CborError CborGetStringValue(CborValue *elm, char *data, size_t maxdatalen, size_t *datalen) {
444 if (datalen)
445 *datalen = 0;
446
447 size_t slen = maxdatalen;
448
449 CborError res = cbor_value_copy_text_string(elm, data, &slen, elm);
450 cbor_check(res);
451
452 if (datalen)
453 *datalen = slen;
454
455 return CborNoError;
456 };
457
458 CborError CborGetStringValueBuf(CborValue *elm) {
459 static char stringBuf[2048];
460 memset(stringBuf, 0x00, sizeof(stringBuf));
461
462 return CborGetStringValue(elm, stringBuf, sizeof(stringBuf), NULL);
463 };
464
465 int CBOREncodeElm(json_t *root, char *rootElmId, CborEncoder *encoder) {
466 json_t *elm = NULL;
467 if (rootElmId && strlen(rootElmId) && rootElmId[0] == '$')
468 elm = json_path_get(root, rootElmId);
469 else
470 elm = json_object_get(root, rootElmId);
471
472 if (!elm)
473 return 1;
474
475 int res = JsonToCbor(elm, encoder);
476
477 return res;
478 }
479
480 CborError CBOREncodeClientDataHash(json_t *root, CborEncoder *encoder) {
481 uint8_t buf[100] = {0};
482 size_t jlen;
483
484 JsonLoadBufAsHex(root, "$.ClientDataHash", buf, sizeof(buf), &jlen);
485
486 // fill with 0x00 if not found
487 if (!jlen)
488 jlen = 32;
489
490 int res = cbor_encode_byte_string(encoder, buf, jlen);
491 cbor_check(res);
492
493 return 0;
494 }
Impressum, Datenschutz