]> git.zerfleddert.de Git - proxmark3-svn/blobdiff - client/fido/cbortools.c
Fido2 (#727)
[proxmark3-svn] / client / fido / cbortools.c
diff --git a/client/fido/cbortools.c b/client/fido/cbortools.c
new file mode 100644 (file)
index 0000000..01691da
--- /dev/null
@@ -0,0 +1,491 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2018 Merlok
+//
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//-----------------------------------------------------------------------------
+// Tools for work with CBOR format http://cbor.io/spec.html
+// via Intel tinycbor (https://github.com/intel/tinycbor) library
+//-----------------------------------------------------------------------------
+//
+
+#include "cbortools.h"
+#include <stdlib.h>
+#include "emv/emvjson.h"
+#include "util.h"
+#include "fidocore.h"
+
+static void indent(int nestingLevel) {
+       while (nestingLevel--)
+               printf("  ");
+}
+
+static CborError dumpelm(CborValue *it, bool *got_next, int nestingLevel) {
+       CborError err;
+       *got_next = false;
+
+       CborType type = cbor_value_get_type(it);
+       indent(nestingLevel);
+       switch (type) {
+       case CborMapType: 
+       case CborArrayType: {
+               printf(type == CborArrayType ? "Array[" : "Map[");
+               break;
+       }
+
+       case CborIntegerType: {
+               int64_t val;
+               cbor_value_get_int64(it, &val);     // can't fail
+               printf("%lld", (long long)val);
+               break;
+       }
+
+       case CborByteStringType: {
+               uint8_t *buf;
+               size_t n;
+               err = cbor_value_dup_byte_string(it, &buf, &n, it);
+               *got_next = true;
+               if (err)
+                       return err;     // parse error
+               printf("%s", sprint_hex(buf, n));
+               free(buf);
+               break;
+       }
+
+       case CborTextStringType: {
+               char *buf;
+               size_t n;
+               err = cbor_value_dup_text_string(it, &buf, &n, it);
+               *got_next = true;
+               if (err)
+                       return err;     // parse error
+               printf("%s", buf);
+               free(buf);
+               break;
+       }
+
+       case CborTagType: {
+               CborTag tag;
+               cbor_value_get_tag(it, &tag);     
+               printf("Tag(%lld)", (long long)tag);
+               break;
+       }
+
+       case CborSimpleType: {
+               uint8_t type;
+               cbor_value_get_simple_type(it, &type); 
+               printf("simple(%u)", type);
+               break;
+       }
+
+       case CborNullType:
+               printf("null");
+               break;
+
+       case CborUndefinedType:
+               printf("undefined");
+               break;
+
+       case CborBooleanType: {
+               bool val;
+               cbor_value_get_boolean(it, &val);       // can't fail
+               printf("%s", val ? "true" : "false");
+               break;
+       }
+
+       case CborDoubleType: {
+               double val;
+               if (false) {
+                       float f;
+       case CborFloatType:
+                       cbor_value_get_float(it, &f);
+                       val = f;
+               } else {
+                       cbor_value_get_double(it, &val);
+               }
+               printf("%g", val);
+               break;
+       }
+       case CborHalfFloatType: {
+               uint16_t val;
+               cbor_value_get_half_float(it, &val);
+               printf("__f16(%04x)", val);
+               break;
+       }
+
+       case CborInvalidType:
+               printf("CborInvalidType!!!");
+               break;
+       }
+       
+       return CborNoError;
+}
+
+static CborError dumprecursive(uint8_t cmdCode, bool isResponse, CborValue *it, bool isMapType, int nestingLevel) {
+       int elmCount = 0;
+       while (!cbor_value_at_end(it)) {
+               CborError err;
+               CborType type = cbor_value_get_type(it);
+//printf("^%x^", type);
+               bool got_next;
+
+               switch (type) {
+               case CborMapType: 
+               case CborArrayType: {
+                       // recursive type
+                       CborValue recursed;
+                       assert(cbor_value_is_container(it));
+                       if (!(isMapType && (elmCount % 2)))
+                               indent(nestingLevel);
+                       printf(type == CborArrayType ? "Array[\n" : "Map[\n");
+                       err = cbor_value_enter_container(it, &recursed);
+                       if (err)
+                               return err;       // parse error
+                       err = dumprecursive(cmdCode, isResponse, &recursed, (type == CborMapType), nestingLevel + 1);
+                       if (err)
+                               return err;       // parse error
+                       err = cbor_value_leave_container(it, &recursed);
+                       if (err)
+                               return err;       // parse error
+                       indent(nestingLevel);
+                       printf("]");
+                       got_next = true;
+                       break;
+               }
+
+               default: {
+                       err = dumpelm(it, &got_next, (isMapType && (elmCount % 2)) ? 0 : nestingLevel);
+                       if (err)
+                               return err;
+                       if (cmdCode > 0 && nestingLevel == 1 && isMapType && !(elmCount % 2)) {
+                               int64_t val;
+                               cbor_value_get_int64(it, &val);
+                               char *desc = fido2GetCmdMemberDescription(cmdCode, isResponse, val);
+                               if (desc)
+                                       printf(" (%s)", desc);
+                       }
+                       break;
+               }
+               }
+
+               if (!got_next) {
+                       err = cbor_value_advance_fixed(it);
+                       if (err)
+                               return err;
+               }
+               if (isMapType && !(elmCount % 2)) {
+                       printf(": ");
+               } else {
+                       printf("\n");
+               }
+               elmCount++;
+       }
+       return CborNoError;
+}
+
+int TinyCborInit(uint8_t *data, size_t length, CborValue *cb) {
+       CborParser parser;
+       CborError err = cbor_parser_init(data, length, 0, &parser, cb);
+    if (err)
+               return err;
+       
+       return 0;
+}
+
+int TinyCborPrintFIDOPackage(uint8_t cmdCode, bool isResponse, uint8_t *data, size_t length) {
+       CborValue cb;
+       int res;
+       res = TinyCborInit(data, length, &cb);
+       if (res)
+               return res;
+               
+    CborError err = dumprecursive(cmdCode, isResponse, &cb, false, 0);
+
+       if (err) {
+               fprintf(stderr,
+#if __WORDSIZE == 64           
+               "CBOR parsing failure at offset %" PRId64 " : %s\n",
+#else
+               "CBOR parsing failure at offset %" PRId32 " : %s\n",    
+#endif
+               cb.ptr - data, cbor_error_string(err));
+               return 1;
+       }       
+       
+       return 0;
+}
+
+int JsonObjElmCount(json_t *elm) {
+       int res = 0;
+       const char *key;
+       json_t *value;
+       
+       if (!json_is_object(elm))
+               return 0;
+       
+       json_object_foreach(elm, key, value) {
+               if (strlen(key) > 0 && key[0] != '.')
+                       res++;          
+       }
+       
+       return res;
+}
+
+int JsonToCbor(json_t *elm, CborEncoder *encoder) {
+       if (!elm || !encoder)
+               return 1;
+
+       int res;
+       
+       // CBOR map == JSON object
+       if (json_is_object(elm)) {
+               CborEncoder map;
+               const char *key;
+               json_t *value;
+
+               res = cbor_encoder_create_map(encoder, &map, JsonObjElmCount(elm));
+               cbor_check(res);
+               
+               json_object_foreach(elm, key, value) {
+                       if (strlen(key) > 0 && key[0] != '.') {
+                               res = cbor_encode_text_stringz(&map, key);              
+                               cbor_check(res);
+                               
+                               // RECURSION!
+                               JsonToCbor(value, &map);
+                       }
+               }
+               
+               res = cbor_encoder_close_container(encoder, &map);
+               cbor_check(res);
+       }
+
+       // CBOR array == JSON array
+       if (json_is_array(elm)) {
+               size_t index;
+               json_t *value;
+               CborEncoder array;
+               
+               res = cbor_encoder_create_array(encoder, &array, json_array_size(elm));
+               cbor_check(res);
+               
+               json_array_foreach(elm, index, value) {
+                       // RECURSION!
+                       JsonToCbor(value, &array);
+               }
+               
+               res = cbor_encoder_close_container(encoder, &array);
+               cbor_check(res);
+       }
+
+       if (json_is_boolean(elm)) {
+               res = cbor_encode_boolean(encoder, json_is_true(elm));
+               cbor_check(res);
+       }
+
+       if (json_is_integer(elm)) {
+               res = cbor_encode_int(encoder, json_integer_value(elm));
+               cbor_check(res);
+       }
+
+       if (json_is_real(elm)) {
+               res = cbor_encode_float(encoder, json_real_value(elm));
+               cbor_check(res);
+       }
+
+       if (json_is_string(elm)) {
+               const char * val = json_string_value(elm);
+               if (CheckStringIsHEXValue(val)) {
+                       size_t datalen = 0;
+                       uint8_t data[4096] = {0};
+                       res = JsonLoadBufAsHex(elm, "$", data, sizeof(data), &datalen);
+                       if (res)
+                               return 100;
+
+                       res = cbor_encode_byte_string(encoder, data, datalen);
+                       cbor_check(res);                        
+               } else {
+                       res = cbor_encode_text_stringz(encoder, val);
+                       cbor_check(res);
+               }
+       }
+       
+       
+       
+       return 0;
+}
+
+int CborMapGetKeyById(CborParser *parser, CborValue *map, uint8_t *data, size_t dataLen, int key) {
+       CborValue cb;
+
+       CborError err = cbor_parser_init(data, dataLen, 0, parser, &cb);
+       cbor_check(err);
+
+       if (cbor_value_get_type(&cb) != CborMapType)
+               return 1;
+               
+       err = cbor_value_enter_container(&cb, map);
+       cbor_check(err);
+
+       int64_t indx;
+       while (!cbor_value_at_end(map)) {
+               // check number
+               if (cbor_value_get_type(map) != CborIntegerType)
+                       return 1;
+
+               cbor_value_get_int64(map, &indx);
+               
+               err = cbor_value_advance(map);
+               cbor_check(err);
+               
+               if (indx == key)
+                       return 0;
+
+               // pass value
+               err = cbor_value_advance(map);
+               cbor_check(err);
+       }
+
+       err = cbor_value_leave_container(&cb, map);
+       cbor_check(err);
+
+       return 2;
+}
+
+CborError CborGetArrayBinStringValue(CborValue *elm, uint8_t *data, size_t maxdatalen, size_t *datalen) {
+       return CborGetArrayBinStringValueEx(elm, data, maxdatalen, datalen, NULL, 0);
+}
+
+CborError CborGetArrayBinStringValueEx(CborValue *elm, uint8_t *data, size_t maxdatalen, size_t *datalen, uint8_t *delimeter, size_t delimeterlen) {
+       CborValue array;
+       if (datalen)
+               *datalen = 0;
+       
+       size_t slen = maxdatalen;
+       size_t totallen = 0;
+
+       CborError res = cbor_value_enter_container(elm, &array);
+       cbor_check(res);
+       
+       while (!cbor_value_at_end(&array)) {
+               res = cbor_value_copy_byte_string(&array, &data[totallen], &slen, &array);
+               cbor_check(res);
+               
+               totallen += slen;
+               if (delimeter) {
+                       memcpy(&data[totallen], delimeter, delimeterlen);
+                       totallen += delimeterlen;
+               }
+               slen = maxdatalen - totallen;
+       }
+
+       res = cbor_value_leave_container(elm, &array);
+       cbor_check(res);
+
+       if (datalen)
+               *datalen = totallen;
+
+       return CborNoError;     
+};
+
+CborError CborGetBinStringValue(CborValue *elm, uint8_t *data, size_t maxdatalen, size_t *datalen) {
+       if (datalen)
+               *datalen = 0;
+       
+       size_t slen = maxdatalen;
+
+       CborError res = cbor_value_copy_byte_string(elm, data, &slen, elm);
+       cbor_check(res);
+
+       if (datalen)
+               *datalen = slen;
+
+       return CborNoError;     
+};
+
+CborError CborGetArrayStringValue(CborValue *elm, char *data, size_t maxdatalen, size_t *datalen, char *delimeter) {
+       CborValue array;
+       if (datalen)
+               *datalen = 0;
+       
+       size_t slen = maxdatalen;
+       size_t totallen = 0;
+
+       CborError res = cbor_value_enter_container(elm, &array);
+       cbor_check(res);
+       
+       while (!cbor_value_at_end(&array)) {
+               res = cbor_value_copy_text_string(&array, &data[totallen], &slen, &array);
+               cbor_check(res);
+               
+               totallen += slen;
+               if (delimeter) {
+                       strcat(data, delimeter);
+                       totallen += strlen(delimeter);
+               }
+               slen = maxdatalen - totallen;
+               data[totallen] = 0x00;
+       }
+
+       res = cbor_value_leave_container(elm, &array);
+       cbor_check(res);
+
+       if (datalen)
+               *datalen = totallen;
+
+       return CborNoError;     
+};
+
+CborError CborGetStringValue(CborValue *elm, char *data, size_t maxdatalen, size_t *datalen) {
+       if (datalen)
+               *datalen = 0;
+       
+       size_t slen = maxdatalen;
+
+       CborError res = cbor_value_copy_text_string(elm, data, &slen, elm);
+       cbor_check(res);
+
+       if (datalen)
+               *datalen = slen;
+
+       return CborNoError;     
+};
+
+CborError CborGetStringValueBuf(CborValue *elm) {
+       static char stringBuf[2048];
+       memset(stringBuf, 0x00, sizeof(stringBuf));
+       
+       return CborGetStringValue(elm, stringBuf, sizeof(stringBuf), NULL);
+};
+
+int CBOREncodeElm(json_t *root, char *rootElmId, CborEncoder *encoder) {
+       json_t *elm = NULL;
+       if (rootElmId && strlen(rootElmId) && rootElmId[0] == '$')
+               elm = json_path_get(root, rootElmId);
+       else
+               elm = json_object_get(root, rootElmId);
+       
+       if (!elm)
+               return 1;
+       
+       int res = JsonToCbor(elm, encoder);
+
+       return res;
+}
+
+CborError CBOREncodeClientDataHash(json_t *root, CborEncoder *encoder) {
+       uint8_t buf[100] = {0};
+       size_t jlen;
+
+       JsonLoadBufAsHex(root, "$.ClientDataHash", buf, sizeof(buf), &jlen);
+       
+       // fill with 0x00 if not found
+       if (!jlen)
+               jlen = 32;
+       
+       int res = cbor_encode_byte_string(encoder, buf, jlen);
+       cbor_check(res);
+
+       return 0;
+}
Impressum, Datenschutz