]>
git.zerfleddert.de Git - proxmark3-svn/blob - client/fido/cbortools.c
1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2018 Merlok
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
7 //-----------------------------------------------------------------------------
8 // Tools for work with CBOR format http://cbor.io/spec.html
9 // via Intel tinycbor (https://github.com/intel/tinycbor) library
10 //-----------------------------------------------------------------------------
13 #include "cbortools.h"
15 #include "emv/emvjson.h"
19 static void indent(int nestingLevel
) {
20 while (nestingLevel
--)
24 static CborError
dumpelm(CborValue
*it
, bool *got_next
, int nestingLevel
) {
28 CborType type
= cbor_value_get_type(it
);
33 printf(type
== CborArrayType
? "Array[" : "Map[");
37 case CborIntegerType
: {
39 cbor_value_get_int64(it
, &val
); // can't fail
40 printf("%lld", (long long)val
);
44 case CborByteStringType
: {
47 err
= cbor_value_dup_byte_string(it
, &buf
, &n
, it
);
50 return err
; // parse error
51 printf("%s", sprint_hex(buf
, n
));
56 case CborTextStringType
: {
59 err
= cbor_value_dup_text_string(it
, &buf
, &n
, it
);
62 return err
; // parse error
70 cbor_value_get_tag(it
, &tag
);
71 printf("Tag(%lld)", (long long)tag
);
75 case CborSimpleType
: {
77 cbor_value_get_simple_type(it
, &type
);
78 printf("simple(%u)", type
);
86 case CborUndefinedType
:
90 case CborBooleanType
: {
92 cbor_value_get_boolean(it
, &val
); // can't fail
93 printf("%s", val
? "true" : "false");
97 case CborDoubleType
: {
102 cbor_value_get_float(it
, &f
);
105 cbor_value_get_double(it
, &val
);
110 case CborHalfFloatType
: {
112 cbor_value_get_half_float(it
, &val
);
113 printf("__f16(%04x)", val
);
117 case CborInvalidType
:
118 printf("CborInvalidType!!!");
125 static CborError
dumprecursive(uint8_t cmdCode
, bool isResponse
, CborValue
*it
, bool isMapType
, int nestingLevel
) {
127 while (!cbor_value_at_end(it
)) {
129 CborType type
= cbor_value_get_type(it
);
130 //printf("^%x^", type);
135 case CborArrayType
: {
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
);
144 return err
; // parse error
145 err
= dumprecursive(cmdCode
, isResponse
, &recursed
, (type
== CborMapType
), nestingLevel
+ 1);
147 return err
; // parse error
148 err
= cbor_value_leave_container(it
, &recursed
);
150 return err
; // parse error
151 indent(nestingLevel
);
158 err
= dumpelm(it
, &got_next
, (isMapType
&& (elmCount
% 2)) ? 0 : nestingLevel
);
161 if (cmdCode
> 0 && nestingLevel
== 1 && isMapType
&& !(elmCount
% 2)) {
163 cbor_value_get_int64(it
, &val
);
164 char *desc
= fido2GetCmdMemberDescription(cmdCode
, isResponse
, val
);
166 printf(" (%s)", desc
);
173 err
= cbor_value_advance_fixed(it
);
177 if (isMapType
&& !(elmCount
% 2)) {
187 int TinyCborInit(uint8_t *data
, size_t length
, CborValue
*cb
) {
189 CborError err
= cbor_parser_init(data
, length
, 0, &parser
, cb
);
196 int TinyCborPrintFIDOPackage(uint8_t cmdCode
, bool isResponse
, uint8_t *data
, size_t length
) {
199 res
= TinyCborInit(data
, length
, &cb
);
203 CborError err
= dumprecursive(cmdCode
, isResponse
, &cb
, false, 0);
208 "CBOR parsing failure at offset %" PRId64
" : %s\n",
210 "CBOR parsing failure at offset %" PRId32
" : %s\n",
212 cb
.ptr
- data
, cbor_error_string(err
));
219 int JsonObjElmCount(json_t
*elm
) {
224 if (!json_is_object(elm
))
227 json_object_foreach(elm
, key
, value
) {
228 if (strlen(key
) > 0 && key
[0] != '.')
235 int JsonToCbor(json_t
*elm
, CborEncoder
*encoder
) {
236 if (!elm
|| !encoder
)
241 // CBOR map == JSON object
242 if (json_is_object(elm
)) {
247 res
= cbor_encoder_create_map(encoder
, &map
, JsonObjElmCount(elm
));
250 json_object_foreach(elm
, key
, value
) {
251 if (strlen(key
) > 0 && key
[0] != '.') {
252 res
= cbor_encode_text_stringz(&map
, key
);
256 JsonToCbor(value
, &map
);
260 res
= cbor_encoder_close_container(encoder
, &map
);
264 // CBOR array == JSON array
265 if (json_is_array(elm
)) {
270 res
= cbor_encoder_create_array(encoder
, &array
, json_array_size(elm
));
273 json_array_foreach(elm
, index
, value
) {
275 JsonToCbor(value
, &array
);
278 res
= cbor_encoder_close_container(encoder
, &array
);
282 if (json_is_boolean(elm
)) {
283 res
= cbor_encode_boolean(encoder
, json_is_true(elm
));
287 if (json_is_integer(elm
)) {
288 res
= cbor_encode_int(encoder
, json_integer_value(elm
));
292 if (json_is_real(elm
)) {
293 res
= cbor_encode_float(encoder
, json_real_value(elm
));
297 if (json_is_string(elm
)) {
298 const char * val
= json_string_value(elm
);
299 if (CheckStringIsHEXValue(val
)) {
301 uint8_t data
[4096] = {0};
302 res
= JsonLoadBufAsHex(elm
, "$", data
, sizeof(data
), &datalen
);
306 res
= cbor_encode_byte_string(encoder
, data
, datalen
);
309 res
= cbor_encode_text_stringz(encoder
, val
);
319 int CborMapGetKeyById(CborParser
*parser
, CborValue
*map
, uint8_t *data
, size_t dataLen
, int key
) {
322 CborError err
= cbor_parser_init(data
, dataLen
, 0, parser
, &cb
);
325 if (cbor_value_get_type(&cb
) != CborMapType
)
328 err
= cbor_value_enter_container(&cb
, map
);
332 while (!cbor_value_at_end(map
)) {
334 if (cbor_value_get_type(map
) != CborIntegerType
)
337 cbor_value_get_int64(map
, &indx
);
339 err
= cbor_value_advance(map
);
346 err
= cbor_value_advance(map
);
350 err
= cbor_value_leave_container(&cb
, map
);
356 CborError
CborGetArrayBinStringValue(CborValue
*elm
, uint8_t *data
, size_t maxdatalen
, size_t *datalen
) {
357 return CborGetArrayBinStringValueEx(elm
, data
, maxdatalen
, datalen
, NULL
, 0);
360 CborError
CborGetArrayBinStringValueEx(CborValue
*elm
, uint8_t *data
, size_t maxdatalen
, size_t *datalen
, uint8_t *delimeter
, size_t delimeterlen
) {
365 size_t slen
= maxdatalen
;
368 CborError res
= cbor_value_enter_container(elm
, &array
);
371 while (!cbor_value_at_end(&array
)) {
372 res
= cbor_value_copy_byte_string(&array
, &data
[totallen
], &slen
, &array
);
377 memcpy(&data
[totallen
], delimeter
, delimeterlen
);
378 totallen
+= delimeterlen
;
380 slen
= maxdatalen
- totallen
;
383 res
= cbor_value_leave_container(elm
, &array
);
392 CborError
CborGetBinStringValue(CborValue
*elm
, uint8_t *data
, size_t maxdatalen
, size_t *datalen
) {
396 size_t slen
= maxdatalen
;
398 CborError res
= cbor_value_copy_byte_string(elm
, data
, &slen
, elm
);
407 CborError
CborGetArrayStringValue(CborValue
*elm
, char *data
, size_t maxdatalen
, size_t *datalen
, char *delimeter
) {
412 size_t slen
= maxdatalen
;
415 CborError res
= cbor_value_enter_container(elm
, &array
);
418 while (!cbor_value_at_end(&array
)) {
419 res
= cbor_value_copy_text_string(&array
, &data
[totallen
], &slen
, &array
);
424 strcat(data
, delimeter
);
425 totallen
+= strlen(delimeter
);
427 slen
= maxdatalen
- totallen
;
428 data
[totallen
] = 0x00;
431 res
= cbor_value_leave_container(elm
, &array
);
440 CborError
CborGetStringValue(CborValue
*elm
, char *data
, size_t maxdatalen
, size_t *datalen
) {
444 size_t slen
= maxdatalen
;
446 CborError res
= cbor_value_copy_text_string(elm
, data
, &slen
, elm
);
455 CborError
CborGetStringValueBuf(CborValue
*elm
) {
456 static char stringBuf
[2048];
457 memset(stringBuf
, 0x00, sizeof(stringBuf
));
459 return CborGetStringValue(elm
, stringBuf
, sizeof(stringBuf
), NULL
);
462 int CBOREncodeElm(json_t
*root
, char *rootElmId
, CborEncoder
*encoder
) {
464 if (rootElmId
&& strlen(rootElmId
) && rootElmId
[0] == '$')
465 elm
= json_path_get(root
, rootElmId
);
467 elm
= json_object_get(root
, rootElmId
);
472 int res
= JsonToCbor(elm
, encoder
);
477 CborError
CBOREncodeClientDataHash(json_t
*root
, CborEncoder
*encoder
) {
478 uint8_t buf
[100] = {0};
481 JsonLoadBufAsHex(root
, "$.ClientDataHash", buf
, sizeof(buf
), &jlen
);
483 // fill with 0x00 if not found
487 int res
= cbor_encode_byte_string(encoder
, buf
, jlen
);