]>
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"
18 #include "emv/emvjson.h"
22 static void indent(int nestingLevel
) {
23 while (nestingLevel
--)
27 static CborError
dumpelm(CborValue
*it
, bool *got_next
, int nestingLevel
) {
31 CborType type
= cbor_value_get_type(it
);
36 printf(type
== CborArrayType
? "Array[" : "Map[");
40 case CborIntegerType
: {
42 cbor_value_get_int64(it
, &val
); // can't fail
43 printf("%lld", (long long)val
);
47 case CborByteStringType
: {
50 err
= cbor_value_dup_byte_string(it
, &buf
, &n
, it
);
53 return err
; // parse error
54 printf("%s", sprint_hex(buf
, n
));
59 case CborTextStringType
: {
62 err
= cbor_value_dup_text_string(it
, &buf
, &n
, it
);
65 return err
; // parse error
73 cbor_value_get_tag(it
, &tag
);
74 printf("Tag(%lld)", (long long)tag
);
78 case CborSimpleType
: {
80 cbor_value_get_simple_type(it
, &type
);
81 printf("simple(%u)", type
);
89 case CborUndefinedType
:
93 case CborBooleanType
: {
95 cbor_value_get_boolean(it
, &val
); // can't fail
96 printf("%s", val
? "true" : "false");
100 case CborDoubleType
: {
105 cbor_value_get_float(it
, &f
);
108 cbor_value_get_double(it
, &val
);
113 case CborHalfFloatType
: {
115 cbor_value_get_half_float(it
, &val
);
116 printf("__f16(%04x)", val
);
120 case CborInvalidType
:
121 printf("CborInvalidType!!!");
128 static CborError
dumprecursive(uint8_t cmdCode
, bool isResponse
, CborValue
*it
, bool isMapType
, int nestingLevel
) {
130 while (!cbor_value_at_end(it
)) {
132 CborType type
= cbor_value_get_type(it
);
133 //printf("^%x^", type);
138 case CborArrayType
: {
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
);
147 return err
; // parse error
148 err
= dumprecursive(cmdCode
, isResponse
, &recursed
, (type
== CborMapType
), nestingLevel
+ 1);
150 return err
; // parse error
151 err
= cbor_value_leave_container(it
, &recursed
);
153 return err
; // parse error
154 indent(nestingLevel
);
161 err
= dumpelm(it
, &got_next
, (isMapType
&& (elmCount
% 2)) ? 0 : nestingLevel
);
164 if (cmdCode
> 0 && nestingLevel
== 1 && isMapType
&& !(elmCount
% 2)) {
166 cbor_value_get_int64(it
, &val
);
167 char *desc
= fido2GetCmdMemberDescription(cmdCode
, isResponse
, val
);
169 printf(" (%s)", desc
);
176 err
= cbor_value_advance_fixed(it
);
180 if (isMapType
&& !(elmCount
% 2)) {
190 int TinyCborInit(uint8_t *data
, size_t length
, CborValue
*cb
) {
192 CborError err
= cbor_parser_init(data
, length
, 0, &parser
, cb
);
199 int TinyCborPrintFIDOPackage(uint8_t cmdCode
, bool isResponse
, uint8_t *data
, size_t length
) {
202 res
= TinyCborInit(data
, length
, &cb
);
206 CborError err
= dumprecursive(cmdCode
, isResponse
, &cb
, false, 0);
211 "CBOR parsing failure at offset %" PRId64
" : %s\n",
213 "CBOR parsing failure at offset %" PRId32
" : %s\n",
215 cb
.ptr
- data
, cbor_error_string(err
));
222 int JsonObjElmCount(json_t
*elm
) {
227 if (!json_is_object(elm
))
230 json_object_foreach(elm
, key
, value
) {
231 if (strlen(key
) > 0 && key
[0] != '.')
238 int JsonToCbor(json_t
*elm
, CborEncoder
*encoder
) {
239 if (!elm
|| !encoder
)
244 // CBOR map == JSON object
245 if (json_is_object(elm
)) {
250 res
= cbor_encoder_create_map(encoder
, &map
, JsonObjElmCount(elm
));
253 json_object_foreach(elm
, key
, value
) {
254 if (strlen(key
) > 0 && key
[0] != '.') {
255 res
= cbor_encode_text_stringz(&map
, key
);
259 JsonToCbor(value
, &map
);
263 res
= cbor_encoder_close_container(encoder
, &map
);
267 // CBOR array == JSON array
268 if (json_is_array(elm
)) {
273 res
= cbor_encoder_create_array(encoder
, &array
, json_array_size(elm
));
276 json_array_foreach(elm
, index
, value
) {
278 JsonToCbor(value
, &array
);
281 res
= cbor_encoder_close_container(encoder
, &array
);
285 if (json_is_boolean(elm
)) {
286 res
= cbor_encode_boolean(encoder
, json_is_true(elm
));
290 if (json_is_integer(elm
)) {
291 res
= cbor_encode_int(encoder
, json_integer_value(elm
));
295 if (json_is_real(elm
)) {
296 res
= cbor_encode_float(encoder
, json_real_value(elm
));
300 if (json_is_string(elm
)) {
301 const char * val
= json_string_value(elm
);
302 if (CheckStringIsHEXValue(val
)) {
304 uint8_t data
[4096] = {0};
305 res
= JsonLoadBufAsHex(elm
, "$", data
, sizeof(data
), &datalen
);
309 res
= cbor_encode_byte_string(encoder
, data
, datalen
);
312 res
= cbor_encode_text_stringz(encoder
, val
);
322 int CborMapGetKeyById(CborParser
*parser
, CborValue
*map
, uint8_t *data
, size_t dataLen
, int key
) {
325 CborError err
= cbor_parser_init(data
, dataLen
, 0, parser
, &cb
);
328 if (cbor_value_get_type(&cb
) != CborMapType
)
331 err
= cbor_value_enter_container(&cb
, map
);
335 while (!cbor_value_at_end(map
)) {
337 if (cbor_value_get_type(map
) != CborIntegerType
)
340 cbor_value_get_int64(map
, &indx
);
342 err
= cbor_value_advance(map
);
349 err
= cbor_value_advance(map
);
353 err
= cbor_value_leave_container(&cb
, map
);
359 CborError
CborGetArrayBinStringValue(CborValue
*elm
, uint8_t *data
, size_t maxdatalen
, size_t *datalen
) {
360 return CborGetArrayBinStringValueEx(elm
, data
, maxdatalen
, datalen
, NULL
, 0);
363 CborError
CborGetArrayBinStringValueEx(CborValue
*elm
, uint8_t *data
, size_t maxdatalen
, size_t *datalen
, uint8_t *delimeter
, size_t delimeterlen
) {
368 size_t slen
= maxdatalen
;
371 CborError res
= cbor_value_enter_container(elm
, &array
);
374 while (!cbor_value_at_end(&array
)) {
375 res
= cbor_value_copy_byte_string(&array
, &data
[totallen
], &slen
, &array
);
380 memcpy(&data
[totallen
], delimeter
, delimeterlen
);
381 totallen
+= delimeterlen
;
383 slen
= maxdatalen
- totallen
;
386 res
= cbor_value_leave_container(elm
, &array
);
395 CborError
CborGetBinStringValue(CborValue
*elm
, uint8_t *data
, size_t maxdatalen
, size_t *datalen
) {
399 size_t slen
= maxdatalen
;
401 CborError res
= cbor_value_copy_byte_string(elm
, data
, &slen
, elm
);
410 CborError
CborGetArrayStringValue(CborValue
*elm
, char *data
, size_t maxdatalen
, size_t *datalen
, char *delimeter
) {
415 size_t slen
= maxdatalen
;
418 CborError res
= cbor_value_enter_container(elm
, &array
);
421 while (!cbor_value_at_end(&array
)) {
422 res
= cbor_value_copy_text_string(&array
, &data
[totallen
], &slen
, &array
);
427 strcat(data
, delimeter
);
428 totallen
+= strlen(delimeter
);
430 slen
= maxdatalen
- totallen
;
431 data
[totallen
] = 0x00;
434 res
= cbor_value_leave_container(elm
, &array
);
443 CborError
CborGetStringValue(CborValue
*elm
, char *data
, size_t maxdatalen
, size_t *datalen
) {
447 size_t slen
= maxdatalen
;
449 CborError res
= cbor_value_copy_text_string(elm
, data
, &slen
, elm
);
458 CborError
CborGetStringValueBuf(CborValue
*elm
) {
459 static char stringBuf
[2048];
460 memset(stringBuf
, 0x00, sizeof(stringBuf
));
462 return CborGetStringValue(elm
, stringBuf
, sizeof(stringBuf
), NULL
);
465 int CBOREncodeElm(json_t
*root
, char *rootElmId
, CborEncoder
*encoder
) {
467 if (rootElmId
&& strlen(rootElmId
) && rootElmId
[0] == '$')
468 elm
= json_path_get(root
, rootElmId
);
470 elm
= json_object_get(root
, rootElmId
);
475 int res
= JsonToCbor(elm
, encoder
);
480 CborError
CBOREncodeClientDataHash(json_t
*root
, CborEncoder
*encoder
) {
481 uint8_t buf
[100] = {0};
484 JsonLoadBufAsHex(root
, "$.ClientDataHash", buf
, sizeof(buf
), &jlen
);
486 // fill with 0x00 if not found
490 int res
= cbor_encode_byte_string(encoder
, buf
, jlen
);