]> git.zerfleddert.de Git - proxmark3-svn/blame - client/fido/cbortools.c
Merge pull request #969 from pwpiwi/gcc10_fixes
[proxmark3-svn] / client / fido / cbortools.c
CommitLineData
0bb51450
OM
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"
41bdfce3 14
0bb51450 15#include <stdlib.h>
41bdfce3 16#include <inttypes.h>
17
0bb51450
OM
18#include "emv/emvjson.h"
19#include "util.h"
20#include "fidocore.h"
21
22static void indent(int nestingLevel) {
23 while (nestingLevel--)
24 printf(" ");
25}
26
27static 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
98a67bc9 43 printf("%" PRIi64, val);
0bb51450
OM
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);
98a67bc9 74 printf("Tag(%" PRIu64, tag);
0bb51450
OM
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
128static 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
190int 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
199int 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) {
98a67bc9 209 fprintf(stderr, "CBOR parsing failure at offset %td : %s\n", cb.ptr - data, cbor_error_string(err));
0bb51450
OM
210 return 1;
211 }
212
213 return 0;
214}
215
216int JsonObjElmCount(json_t *elm) {
217 int res = 0;
218 const char *key;
219 json_t *value;
220
221 if (!json_is_object(elm))
222 return 0;
223
224 json_object_foreach(elm, key, value) {
225 if (strlen(key) > 0 && key[0] != '.')
226 res++;
227 }
228
229 return res;
230}
231
232int JsonToCbor(json_t *elm, CborEncoder *encoder) {
233 if (!elm || !encoder)
234 return 1;
235
236 int res;
237
238 // CBOR map == JSON object
239 if (json_is_object(elm)) {
240 CborEncoder map;
241 const char *key;
242 json_t *value;
243
244 res = cbor_encoder_create_map(encoder, &map, JsonObjElmCount(elm));
245 cbor_check(res);
246
247 json_object_foreach(elm, key, value) {
248 if (strlen(key) > 0 && key[0] != '.') {
249 res = cbor_encode_text_stringz(&map, key);
250 cbor_check(res);
251
252 // RECURSION!
253 JsonToCbor(value, &map);
254 }
255 }
256
257 res = cbor_encoder_close_container(encoder, &map);
258 cbor_check(res);
259 }
260
261 // CBOR array == JSON array
262 if (json_is_array(elm)) {
263 size_t index;
264 json_t *value;
265 CborEncoder array;
266
267 res = cbor_encoder_create_array(encoder, &array, json_array_size(elm));
268 cbor_check(res);
269
270 json_array_foreach(elm, index, value) {
271 // RECURSION!
272 JsonToCbor(value, &array);
273 }
274
275 res = cbor_encoder_close_container(encoder, &array);
276 cbor_check(res);
277 }
278
279 if (json_is_boolean(elm)) {
280 res = cbor_encode_boolean(encoder, json_is_true(elm));
281 cbor_check(res);
282 }
283
284 if (json_is_integer(elm)) {
285 res = cbor_encode_int(encoder, json_integer_value(elm));
286 cbor_check(res);
287 }
288
289 if (json_is_real(elm)) {
290 res = cbor_encode_float(encoder, json_real_value(elm));
291 cbor_check(res);
292 }
293
294 if (json_is_string(elm)) {
295 const char * val = json_string_value(elm);
296 if (CheckStringIsHEXValue(val)) {
297 size_t datalen = 0;
298 uint8_t data[4096] = {0};
299 res = JsonLoadBufAsHex(elm, "$", data, sizeof(data), &datalen);
300 if (res)
301 return 100;
302
303 res = cbor_encode_byte_string(encoder, data, datalen);
304 cbor_check(res);
305 } else {
306 res = cbor_encode_text_stringz(encoder, val);
307 cbor_check(res);
308 }
309 }
310
311
312
313 return 0;
314}
315
316int CborMapGetKeyById(CborParser *parser, CborValue *map, uint8_t *data, size_t dataLen, int key) {
317 CborValue cb;
318
319 CborError err = cbor_parser_init(data, dataLen, 0, parser, &cb);
320 cbor_check(err);
321
322 if (cbor_value_get_type(&cb) != CborMapType)
323 return 1;
324
325 err = cbor_value_enter_container(&cb, map);
326 cbor_check(err);
327
328 int64_t indx;
329 while (!cbor_value_at_end(map)) {
330 // check number
331 if (cbor_value_get_type(map) != CborIntegerType)
332 return 1;
333
334 cbor_value_get_int64(map, &indx);
335
336 err = cbor_value_advance(map);
337 cbor_check(err);
338
339 if (indx == key)
340 return 0;
341
342 // pass value
343 err = cbor_value_advance(map);
344 cbor_check(err);
345 }
346
347 err = cbor_value_leave_container(&cb, map);
348 cbor_check(err);
349
350 return 2;
351}
352
353CborError CborGetArrayBinStringValue(CborValue *elm, uint8_t *data, size_t maxdatalen, size_t *datalen) {
354 return CborGetArrayBinStringValueEx(elm, data, maxdatalen, datalen, NULL, 0);
355}
356
357CborError CborGetArrayBinStringValueEx(CborValue *elm, uint8_t *data, size_t maxdatalen, size_t *datalen, uint8_t *delimeter, size_t delimeterlen) {
358 CborValue array;
359 if (datalen)
360 *datalen = 0;
361
362 size_t slen = maxdatalen;
363 size_t totallen = 0;
364
365 CborError res = cbor_value_enter_container(elm, &array);
366 cbor_check(res);
367
368 while (!cbor_value_at_end(&array)) {
369 res = cbor_value_copy_byte_string(&array, &data[totallen], &slen, &array);
370 cbor_check(res);
371
372 totallen += slen;
373 if (delimeter) {
374 memcpy(&data[totallen], delimeter, delimeterlen);
375 totallen += delimeterlen;
376 }
377 slen = maxdatalen - totallen;
378 }
379
380 res = cbor_value_leave_container(elm, &array);
381 cbor_check(res);
382
383 if (datalen)
384 *datalen = totallen;
385
386 return CborNoError;
387};
388
389CborError CborGetBinStringValue(CborValue *elm, uint8_t *data, size_t maxdatalen, size_t *datalen) {
390 if (datalen)
391 *datalen = 0;
392
393 size_t slen = maxdatalen;
394
395 CborError res = cbor_value_copy_byte_string(elm, data, &slen, elm);
396 cbor_check(res);
397
398 if (datalen)
399 *datalen = slen;
400
401 return CborNoError;
402};
403
404CborError CborGetArrayStringValue(CborValue *elm, char *data, size_t maxdatalen, size_t *datalen, char *delimeter) {
405 CborValue array;
406 if (datalen)
407 *datalen = 0;
408
409 size_t slen = maxdatalen;
410 size_t totallen = 0;
411
412 CborError res = cbor_value_enter_container(elm, &array);
413 cbor_check(res);
414
415 while (!cbor_value_at_end(&array)) {
416 res = cbor_value_copy_text_string(&array, &data[totallen], &slen, &array);
417 cbor_check(res);
418
419 totallen += slen;
420 if (delimeter) {
421 strcat(data, delimeter);
422 totallen += strlen(delimeter);
423 }
424 slen = maxdatalen - totallen;
425 data[totallen] = 0x00;
426 }
427
428 res = cbor_value_leave_container(elm, &array);
429 cbor_check(res);
430
431 if (datalen)
432 *datalen = totallen;
433
434 return CborNoError;
435};
436
437CborError CborGetStringValue(CborValue *elm, char *data, size_t maxdatalen, size_t *datalen) {
438 if (datalen)
439 *datalen = 0;
440
441 size_t slen = maxdatalen;
442
443 CborError res = cbor_value_copy_text_string(elm, data, &slen, elm);
444 cbor_check(res);
445
446 if (datalen)
447 *datalen = slen;
448
449 return CborNoError;
450};
451
452CborError CborGetStringValueBuf(CborValue *elm) {
453 static char stringBuf[2048];
454 memset(stringBuf, 0x00, sizeof(stringBuf));
455
456 return CborGetStringValue(elm, stringBuf, sizeof(stringBuf), NULL);
457};
458
459int CBOREncodeElm(json_t *root, char *rootElmId, CborEncoder *encoder) {
460 json_t *elm = NULL;
461 if (rootElmId && strlen(rootElmId) && rootElmId[0] == '$')
462 elm = json_path_get(root, rootElmId);
463 else
464 elm = json_object_get(root, rootElmId);
465
466 if (!elm)
467 return 1;
468
469 int res = JsonToCbor(elm, encoder);
470
471 return res;
472}
473
474CborError CBOREncodeClientDataHash(json_t *root, CborEncoder *encoder) {
475 uint8_t buf[100] = {0};
476 size_t jlen;
477
478 JsonLoadBufAsHex(root, "$.ClientDataHash", buf, sizeof(buf), &jlen);
479
480 // fill with 0x00 if not found
481 if (!jlen)
482 jlen = 32;
483
484 int res = cbor_encode_byte_string(encoder, buf, jlen);
485 cbor_check(res);
486
487 return 0;
488}
Impressum, Datenschutz