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