diff --git a/Makefile.dep b/Makefile.dep
index 64207bf61bd32145919dbfacdea3a7c2b2329fd1..c07669792825062db4109c818d320bd97a63fc47 100644
--- a/Makefile.dep
+++ b/Makefile.dep
@@ -45,6 +45,10 @@ ifneq (,$(filter uart0,$(USEMODULE)))
 	USEMODULE += posix
 endif
 
+ifneq (,$(filter cbor,$(USEMODULE)))
+	USEMODULE += net_help
+endif
+
 ifneq (,$(filter cc110x%,$(USEMODULE)))
 	USEMODULE += protocol_multiplex
 	USEMODULE += vtimer
diff --git a/sys/Makefile b/sys/Makefile
index d7c973ac1b7f8651e401b67b2ebfa5639cf99269..56549c73b7b0908665c464031068e1f5f26019a1 100644
--- a/sys/Makefile
+++ b/sys/Makefile
@@ -1,6 +1,9 @@
 ifneq (,$(filter auto_init,$(USEMODULE)))
     DIRS += auto_init
 endif
+ifneq (,$(filter cbor,$(USEMODULE)))
+    DIRS += cbor
+endif
 ifneq (,$(filter config,$(USEMODULE)))
     DIRS += config
 endif
diff --git a/sys/cbor/Makefile b/sys/cbor/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..ea880700a74a103ba4f9cdc01935246e5c086a2b
--- /dev/null
+++ b/sys/cbor/Makefile
@@ -0,0 +1,10 @@
+MODULE = cbor
+
+CFLAGS += -DCBOR_NO_PRINT
+
+ifeq (,$(filter native,$(BOARD)))
+	# build the minimal subset for non-native
+	CFLAGS += -DCBOR_NO_FLOAT -DCBOR_NO_PRINT -DCBOR_NO_SEMANTIC_TAGGING
+endif
+
+include $(RIOTBASE)/Makefile.base
diff --git a/sys/cbor/cbor.c b/sys/cbor/cbor.c
new file mode 100644
index 0000000000000000000000000000000000000000..1753dc34115d14dd5807600b0e33a45b528314b2
--- /dev/null
+++ b/sys/cbor/cbor.c
@@ -0,0 +1,1008 @@
+/*
+ * Copyright (C) 2014 Freie Universität Berlin
+ * Copyright (C) 2014 Kevin Funk <kfunk@kde.org>
+ * Copyright (C) 2014 Jana Cavojska <jana.cavojska9@gmail.com>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @author      Kevin Funk <kfunk@kde.org>
+ * @author      Jana Cavojska <jana.cavojska9@gmail.com>
+ */
+
+#include "cbor.h"
+
+#include "net_help.h"
+
+#include <inttypes.h>
+#include <math.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// Automatically enable/disable ENABLE_DEBUG based on CBOR_NO_PRINT
+#ifndef CBOR_NO_PRINT
+#define ENABLE_DEBUG 1
+#include "debug.h"
+#endif
+
+#define CBOR_TYPE_MASK          0xE0    /* top 3 bits */
+#define CBOR_INFO_MASK          0x1F    /* low 5 bits */
+
+#define CBOR_BYTE_FOLLOWS       24      /* indicator that the next byte is part of this item */
+
+/* Jump Table for Initial Byte (cf. table 5) */
+#define CBOR_UINT       0x00            /* type 0 */
+#define CBOR_NEGINT     0x20            /* type 1 */
+#define CBOR_BYTES      0x40            /* type 2 */
+#define CBOR_TEXT       0x60            /* type 3 */
+#define CBOR_ARRAY      0x80            /* type 4 */
+#define CBOR_MAP        0xA0            /* type 5 */
+#define CBOR_TAG        0xC0            /* type 6 */
+#define CBOR_7          0xE0            /* type 7 (float and other types) */
+
+/* Major types (cf. section 2.1) */
+/* Major type 0: Unsigned integers */
+#define CBOR_UINT8_FOLLOWS      24      /* 0x18 */
+#define CBOR_UINT16_FOLLOWS     25      /* 0x19 */
+#define CBOR_UINT32_FOLLOWS     26      /* 0x1a */
+#define CBOR_UINT64_FOLLOWS     27      /* 0x1b */
+
+/* Indefinite Lengths for Some Major types (cf. section 2.2) */
+#define CBOR_VAR_FOLLOWS        31      /* 0x1f */
+
+/* Major type 6: Semantic tagging */
+#define CBOR_DATETIME_STRING_FOLLOWS        0
+#define CBOR_DATETIME_EPOCH_FOLLOWS         1
+
+/* Major type 7: Float and other types */
+#define CBOR_FALSE      (CBOR_7 | 20)
+#define CBOR_TRUE       (CBOR_7 | 21)
+#define CBOR_NULL       (CBOR_7 | 22)
+#define CBOR_UNDEFINED  (CBOR_7 | 23)
+/* CBOR_BYTE_FOLLOWS == 24 */
+#define CBOR_FLOAT16    (CBOR_7 | 25)
+#define CBOR_FLOAT32    (CBOR_7 | 26)
+#define CBOR_FLOAT64    (CBOR_7 | 27)
+#define CBOR_BREAK      (CBOR_7 | 31)
+
+#define CBOR_TYPE(stream, offset) (stream->data[offset] & CBOR_TYPE_MASK)
+#define CBOR_ADDITIONAL_INFO(stream, offset) (stream->data[offset] & CBOR_INFO_MASK)
+
+/* Ensure that @p stream is big enough to fit @p bytes bytes, otherwise return 0 */
+#define CBOR_ENSURE_SIZE(stream, bytes) do { \
+    if (stream->pos + bytes >= stream->size) { return 0; } \
+} while(0)
+
+/* Extra defines not related to the protocol itself */
+#define CBOR_STREAM_PRINT_BUFFERSIZE 1024 /* bytes */
+
+#ifndef INFINITY
+#define INFINITY (1.0/0.0)
+#endif
+#ifndef NAN
+#define NAN (0.0/0.0)
+#endif
+
+/**
+ * Convert long long @p x to network format
+ */
+static uint64_t htonll(uint64_t x)
+{
+    return (((uint64_t)HTONL(x)) << 32) + HTONL(x >> 32);
+}
+
+/**
+ * Convert long long @p x to host format
+ */
+static uint64_t ntohll(uint64_t x)
+{
+    return (((uint64_t)NTOHL(x)) << 32) + NTOHL(x >> 32);
+}
+
+#ifndef CBOR_NO_FLOAT
+/**
+ * Convert float @p x to network format
+ */
+static uint32_t htonf(float x)
+{
+    union u {
+        float f;
+        uint32_t i;
+    } u = { .f = x };
+    return HTONL(u.i);
+}
+
+/**
+ * Convert float @p x to host format
+ */
+static float ntohf(uint32_t x)
+{
+    union u {
+        float f;
+        uint32_t i;
+    } u = { .i = NTOHL(x) };
+    return u.f;
+}
+
+/**
+ * Convert double @p x to network format
+ */
+static uint64_t htond(double x)
+{
+    union u {
+        double d;
+        uint64_t i;
+    } u = { .d = x };
+    return htonll(u.i);
+}
+
+/**
+ * Convert double @p x to host format
+ */
+static double ntohd(uint64_t x)
+{
+    union u {
+        double d;
+        uint64_t i;
+    } u = { .i = ntohll(x) };
+    return u.d;
+}
+
+/**
+ * Source: CBOR RFC reference implementation
+ */
+double decode_float_half(unsigned char *halfp)
+{
+    int half = (halfp[0] << 8) + halfp[1];
+    int exp = (half >> 10) & 0x1f;
+    int mant = half & 0x3ff;
+    double val;
+
+    if (exp == 0) {
+        val = ldexp(mant, -24);
+    }
+    else if (exp != 31) {
+        val = ldexp(mant + 1024, exp - 25);
+    }
+    else {
+        val = mant == 0 ? INFINITY : NAN;
+    }
+
+    return half & 0x8000 ? -val : val;
+}
+
+/**
+ * Source: According to http://gamedev.stackexchange.com/questions/17326/conversion-of-a-number-from-single-precision-floating-point-representation-to-a
+ */
+static uint16_t encode_float_half(float x)
+{
+    union u {
+        float f;
+        uint32_t i;
+    } u = { .f = x };
+
+    uint16_t bits = (u.i >> 16) & 0x8000; /* Get the sign */
+    uint16_t m = (u.i >> 12) & 0x07ff; /* Keep one extra bit for rounding */
+    unsigned int e = (u.i >> 23) & 0xff; /* Using int is faster here */
+
+    /* If zero, or denormal, or exponent underflows too much for a denormal
+     * half, return signed zero. */
+    if (e < 103) {
+        return bits;
+    }
+
+    /* If NaN, return NaN. If Inf or exponent overflow, return Inf. */
+    if (e > 142) {
+        bits |= 0x7c00u;
+        /* If exponent was 0xff and one mantissa bit was set, it means NaN,
+         * not Inf, so make sure we set one mantissa bit too. */
+        bits |= (e == 255) && (u.i & 0x007fffffu);
+        return bits;
+    }
+
+    /* If exponent underflows but not too much, return a denormal */
+    if (e < 113) {
+        m |= 0x0800u;
+        /* Extra rounding may overflow and set mantissa to 0 and exponent
+         * to 1, which is OK. */
+        bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1);
+        return bits;
+    }
+
+    bits |= ((e - 112) << 10) | (m >> 1);
+    /* Extra rounding. An overflow will set mantissa to 0 and increment
+     * the exponent, which is OK. */
+    bits += m & 1;
+    return bits;
+}
+#endif /* CBOR_NO_FLOAT */
+
+#ifndef CBOR_NO_PRINT
+/**
+ * Print @p size bytes at @p data in hexadecimal display format
+ */
+void dump_memory(const unsigned char *data, size_t size)
+{
+    if (!data || !size) {
+        return;
+    }
+
+    DEBUG("0x");
+
+    for (size_t i = 0; i < size; ++i) {
+        DEBUG("%02X", data[i]);
+    }
+}
+#endif /* CBOR_NO_PRINT */
+
+void cbor_init(cbor_stream_t *stream, unsigned char *buffer, size_t size)
+{
+    if (!stream) {
+        return;
+    }
+
+    stream->data = buffer;
+    stream->size = size;
+    stream->pos = 0;
+}
+
+void cbor_clear(cbor_stream_t *stream)
+{
+    if (!stream) {
+        return;
+    }
+
+    stream->pos = 0;
+}
+
+void cbor_destroy(cbor_stream_t *stream)
+{
+    if (!stream) {
+        return;
+    }
+
+    stream->data = 0;
+    stream->size = 0;
+    stream->pos = 0;
+}
+
+/**
+ * Return additional info field value for input value @p val
+ *
+ * @return Byte with the additional info bits set
+ */
+static unsigned char uint_additional_info(uint64_t val)
+{
+    if (val < CBOR_UINT8_FOLLOWS) {
+        return val;
+    }
+    else if (val <= 0xff) {
+        return CBOR_UINT8_FOLLOWS;
+    }
+    else if (val <= 0xffff) {
+        return CBOR_UINT16_FOLLOWS;
+    }
+    else if (val <= 0xffffffffL) {
+        return CBOR_UINT32_FOLLOWS;
+    }
+
+    return CBOR_UINT64_FOLLOWS;
+}
+
+/**
+ * Return the number of bytes that would follow the additional info field @p additional_info
+ *
+ * @param additional_info Must be in the range [CBOR_UINT8_FOLLOWS, CBOR_UINT64_FOLLOWS]
+ */
+static unsigned char uint_bytes_follow(unsigned char additional_info)
+{
+    if (additional_info < CBOR_UINT8_FOLLOWS || additional_info > CBOR_UINT64_FOLLOWS) {
+        return 0;
+    }
+
+    static const unsigned char BYTES_FOLLOW[] = {1, 2, 4, 8};
+    return BYTES_FOLLOW[additional_info - CBOR_UINT8_FOLLOWS];
+}
+
+static size_t encode_int(unsigned char major_type, cbor_stream_t *s, uint64_t val)
+{
+    if (!s) {
+        return 0;
+    }
+
+    unsigned char additional_info = uint_additional_info(val);
+    unsigned char bytes_follow = uint_bytes_follow(additional_info);
+    CBOR_ENSURE_SIZE(s, bytes_follow + 1);
+    s->data[s->pos++] = major_type | additional_info;
+
+    for (int i = bytes_follow - 1; i >= 0; --i) {
+        s->data[s->pos++] = (val >> (8 * i)) & 0xff;
+    }
+
+    return bytes_follow + 1;
+}
+
+static size_t decode_int(const cbor_stream_t *s, size_t offset, uint64_t *val)
+{
+    if (!s) {
+        return 0;
+    }
+
+    *val = 0; /* clear val first */
+
+    unsigned char *in = &s->data[offset];
+    unsigned char additional_info = CBOR_ADDITIONAL_INFO(s, offset);
+    unsigned char bytes_follow = uint_bytes_follow(additional_info);
+
+    switch (bytes_follow) {
+        case 0:
+            *val = (in[0] & CBOR_INFO_MASK);
+            break;
+
+        case 1:
+            *val = in[1];
+            break;
+
+        case 2:
+            *val = HTONS(*((uint16_t *)&in[1]));
+            break;
+
+        case 4:
+            *val = HTONL(*((uint32_t *)&in[1]));
+            break;
+
+        default:
+            *val = htonll(*((uint64_t *)&in[1]));
+            break;
+    }
+
+    return bytes_follow + 1;
+}
+
+static size_t encode_bytes(unsigned char major_type, cbor_stream_t *s, const char *data,
+                           size_t length)
+{
+    size_t length_field_size = uint_bytes_follow(uint_additional_info(length)) + 1;
+    CBOR_ENSURE_SIZE(s, length_field_size + length);
+
+    size_t bytes_start = encode_int(major_type, s, (uint64_t) length);
+
+    if (!bytes_start) {
+        return 0;
+    }
+
+    memcpy(&(s->data[s->pos]), data, length); /* copy byte string into our cbor struct */
+    s->pos += length;
+    return (bytes_start + length);
+}
+
+static size_t decode_bytes(const cbor_stream_t *s, size_t offset, char *out, size_t length)
+{
+    if ((CBOR_TYPE(s, offset) != CBOR_BYTES && CBOR_TYPE(s, offset) != CBOR_TEXT) || !s || !out) {
+        return 0;
+    }
+
+    uint64_t bytes_length;
+    size_t bytes_start = decode_int(s, offset, &bytes_length);
+
+    if (!bytes_start) {
+        return 0;
+    }
+
+    if (length + 1 < bytes_length) {
+        return 0;
+    }
+
+    memcpy(out, &s->data[offset + bytes_start], bytes_length);
+    out[bytes_length] = '\0';
+    return (bytes_start + bytes_length);
+}
+
+size_t cbor_deserialize_int(const cbor_stream_t *stream, size_t offset, int *val)
+{
+    if ((CBOR_TYPE(stream, offset) != CBOR_UINT && CBOR_TYPE(stream, offset) != CBOR_NEGINT) || !val) {
+        return 0;
+    }
+
+    uint64_t buf;
+    size_t read_bytes = decode_int(stream, offset, &buf);
+
+    if (CBOR_TYPE(stream, offset) == CBOR_UINT) {
+        *val = buf; /* resolve as CBOR_UINT */
+    }
+    else {
+        *val = -1 - buf; /* resolve as CBOR_NEGINT */
+    }
+
+    return read_bytes;
+}
+
+size_t cbor_serialize_int(cbor_stream_t *s, int val)
+{
+    if (val >= 0) {
+        /* Major type 0: an unsigned integer */
+        return encode_int(CBOR_UINT, s, val);
+    }
+    else {
+        /* Major type 1: an negative integer */
+        return encode_int(CBOR_NEGINT, s, -1 - val);
+    }
+}
+
+size_t cbor_deserialize_uint64_t(const cbor_stream_t *stream, size_t offset, uint64_t *val)
+{
+    if (CBOR_TYPE(stream, offset) != CBOR_UINT || !val) {
+        return 0;
+    }
+
+    return decode_int(stream, offset, val);
+}
+
+size_t cbor_serialize_uint64_t(cbor_stream_t *s, uint64_t val)
+{
+    return encode_int(CBOR_UINT, s, val);
+}
+
+size_t cbor_deserialize_int64_t(const cbor_stream_t *stream, size_t offset, int64_t *val)
+{
+    if ((CBOR_TYPE(stream, offset) != CBOR_UINT && CBOR_TYPE(stream, offset) != CBOR_NEGINT) || !val) {
+        return 0;
+    }
+
+    uint64_t buf;
+    size_t read_bytes = decode_int(stream, offset, &buf);
+
+    if (CBOR_TYPE(stream, offset) == CBOR_UINT) {
+        *val = buf; /* resolve as CBOR_UINT */
+    }
+    else {
+        *val = -1 - buf; /* resolve as CBOR_NEGINT */
+    }
+
+    return read_bytes;
+}
+
+size_t cbor_serialize_int64_t(cbor_stream_t *s, int64_t val)
+{
+    if (val >= 0) {
+        /* Major type 0: an unsigned integer */
+        return encode_int(CBOR_UINT, s, val);
+    }
+    else {
+        /* Major type 1: an negative integer */
+        return encode_int(CBOR_NEGINT, s, -1 - val);
+    }
+}
+
+size_t cbor_deserialize_bool(const cbor_stream_t *stream, size_t offset, bool *val)
+{
+    if (CBOR_TYPE(stream, offset) != CBOR_7 || !val) {
+        return 0;
+    }
+
+    unsigned char byte = stream->data[offset];
+    *val = (byte == CBOR_TRUE);
+    return 1;
+}
+
+size_t cbor_serialize_bool(cbor_stream_t *s, bool val)
+{
+    CBOR_ENSURE_SIZE(s, 1);
+    s->data[s->pos++] = val ? CBOR_TRUE : CBOR_FALSE;
+    return 1;
+}
+
+#ifndef CBOR_NO_FLOAT
+size_t cbor_deserialize_float_half(const cbor_stream_t *stream, size_t offset, float *val)
+{
+    if (CBOR_TYPE(stream, offset) != CBOR_7 || !val) {
+        return 0;
+    }
+
+    unsigned char *data = &stream->data[offset];
+
+    if (*data == CBOR_FLOAT16) {
+        *val = (float)decode_float_half(data + 1);
+        return 3;
+    }
+
+    return 0;
+}
+
+size_t cbor_serialize_float_half(cbor_stream_t *s, float val)
+{
+    CBOR_ENSURE_SIZE(s, 3);
+    s->data[s->pos++] = CBOR_FLOAT16;
+    uint16_t encoded_val = HTONS(encode_float_half(val));
+    memcpy(s->data + s->pos, &encoded_val, 2);
+    s->pos += 2;
+    return 3;
+}
+
+size_t cbor_deserialize_float(const cbor_stream_t *stream, size_t offset, float *val)
+{
+    if (CBOR_TYPE(stream, offset) != CBOR_7 || !val) {
+        return 0;
+    }
+
+    unsigned char *data = &stream->data[offset];
+
+    if (*data == CBOR_FLOAT32) {
+        *val = ntohf(*(uint32_t *)(data + 1));
+        return 4;
+    }
+
+    return 0;
+}
+
+size_t cbor_serialize_float(cbor_stream_t *s, float val)
+{
+    CBOR_ENSURE_SIZE(s, 5);
+    s->data[s->pos++] = CBOR_FLOAT32;
+    uint32_t encoded_val = htonf(val);
+    memcpy(s->data + s->pos, &encoded_val, 4);
+    s->pos += 4;
+    return 5;
+}
+
+size_t cbor_deserialize_double(const cbor_stream_t *stream, size_t offset, double *val)
+{
+    if (CBOR_TYPE(stream, offset) != CBOR_7 || !val) {
+        return 0;
+    }
+
+    unsigned char *data = &stream->data[offset];
+
+    if (*data == CBOR_FLOAT64) {
+        *val = ntohd(*(uint64_t *)(data + 1));
+        return 9;
+    }
+
+    return 0;
+}
+
+size_t cbor_serialize_double(cbor_stream_t *s, double val)
+{
+    CBOR_ENSURE_SIZE(s, 9);
+    s->data[s->pos++] = CBOR_FLOAT64;
+    uint64_t encoded_val = htond(val);
+    memcpy(s->data + s->pos, &encoded_val, 8);
+    s->pos += 8;
+    return 9;
+}
+#endif /* CBOR_NO_FLOAT */
+
+size_t cbor_deserialize_byte_string(const cbor_stream_t *stream, size_t offset, char *val,
+                                    size_t length)
+{
+    if (CBOR_TYPE(stream, offset) != CBOR_BYTES) {
+        return 0;
+    }
+
+    return decode_bytes(stream, offset, val, length);
+}
+
+size_t cbor_serialize_byte_string(cbor_stream_t *stream, const char *val)
+{
+    return encode_bytes(CBOR_BYTES, stream, val, strlen(val));
+}
+
+size_t cbor_deserialize_unicode_string(const cbor_stream_t *stream, size_t offset, char *val,
+                                       size_t length)
+{
+    if (CBOR_TYPE(stream, offset) != CBOR_TEXT) {
+        return 0;
+    }
+
+    return decode_bytes(stream, offset, val, length);
+}
+
+size_t cbor_serialize_unicode_string(cbor_stream_t *stream, const char *val)
+{
+    return encode_bytes(CBOR_TEXT, stream, val, strlen(val));
+}
+
+size_t cbor_deserialize_array(const cbor_stream_t *s, size_t offset, size_t *array_length)
+{
+    if (CBOR_TYPE(s, offset) != CBOR_ARRAY || !array_length) {
+        return 0;
+    }
+
+    uint64_t val;
+    size_t read_bytes = decode_int(s, offset, &val);
+    *array_length = (size_t)val;
+    return read_bytes;
+}
+
+size_t cbor_serialize_array(cbor_stream_t *s, size_t array_length)
+{
+    /* serialize number of array items */
+    return encode_int(CBOR_ARRAY, s, array_length);
+}
+
+size_t cbor_serialize_array_indefinite(cbor_stream_t *s)
+{
+    CBOR_ENSURE_SIZE(s, 1);
+    s->data[s->pos++] = CBOR_ARRAY | CBOR_VAR_FOLLOWS;
+    return 1;
+
+}
+
+size_t cbor_deserialize_array_indefinite(const cbor_stream_t *s, size_t offset)
+{
+    if (s->data[offset] != (CBOR_ARRAY | CBOR_VAR_FOLLOWS)) {
+        return 0;
+    }
+
+    return 1;
+}
+
+size_t cbor_serialize_map_indefinite(cbor_stream_t *s)
+{
+    CBOR_ENSURE_SIZE(s, 1);
+    s->data[s->pos++] = CBOR_MAP | CBOR_VAR_FOLLOWS;
+    return 1;
+}
+
+size_t cbor_deserialize_map_indefinite(const cbor_stream_t *s, size_t offset)
+{
+    if (s->data[offset] != (CBOR_MAP | CBOR_VAR_FOLLOWS)) {
+        return 0;
+    }
+
+    return 1;
+}
+
+size_t cbor_deserialize_map(const cbor_stream_t *s, size_t offset, size_t *map_length)
+{
+    if (CBOR_TYPE(s, offset) != CBOR_MAP || !map_length) {
+        return 0;
+    }
+
+    uint64_t val;
+    size_t read_bytes = decode_int(s, offset, &val);
+    *map_length = (size_t)val;
+    return read_bytes;
+}
+
+size_t cbor_serialize_map(cbor_stream_t *s, size_t map_length)
+{
+    /* serialize number of item key-value pairs */
+    return encode_int(CBOR_MAP, s, map_length);
+}
+
+#ifndef CBOR_NO_SEMANTIC_TAGGING
+#ifndef CBOR_NO_CTIME
+size_t cbor_deserialize_date_time(const cbor_stream_t *stream, size_t offset, struct tm *val)
+{
+    if ((CBOR_TYPE(stream, offset) != CBOR_TAG)
+        || (CBOR_ADDITIONAL_INFO(stream, offset) != CBOR_DATETIME_STRING_FOLLOWS)) {
+        return 0;
+    }
+
+    char buffer[21];
+    offset++;  /* skip tag byte to decode date_time */
+    size_t read_bytes = cbor_deserialize_unicode_string(stream, offset, buffer, sizeof(buffer));
+    const char *format = "%Y-%m-%dT%H:%M:%SZ";
+
+    if (strptime(buffer, format, val) == 0) {
+        return 0;
+    }
+
+    if (mktime(val) == -1) {
+        return 0;
+    }
+
+    return read_bytes + 1;  /* + 1 tag byte */
+}
+
+size_t cbor_serialize_date_time(cbor_stream_t *stream, struct tm *val)
+{
+    static const int MAX_TIMESTRING_LENGTH = 21;
+    CBOR_ENSURE_SIZE(stream, MAX_TIMESTRING_LENGTH + 1); /* + 1 tag byte */
+
+    char time_str[MAX_TIMESTRING_LENGTH];
+    const char *format = "%Y-%m-%dT%H:%M:%SZ";
+
+    if (strftime(time_str, sizeof(time_str), format, val) == 0) { /* struct tm to string */
+        return 0;
+    }
+
+    if (!cbor_write_tag(stream, CBOR_DATETIME_STRING_FOLLOWS)) {
+        return 0;
+    }
+
+    size_t written_bytes = cbor_serialize_unicode_string(stream, time_str);
+    return written_bytes + 1; /* utf8 time string length + tag length */
+}
+
+size_t cbor_deserialize_date_time_epoch(const cbor_stream_t *stream, size_t offset, time_t *val)
+{
+    if ((CBOR_TYPE(stream, offset) != CBOR_TAG)
+        || (CBOR_ADDITIONAL_INFO(stream, offset) != CBOR_DATETIME_EPOCH_FOLLOWS)) {
+        return 0;
+    }
+
+    offset++; /* skip tag byte */
+    uint64_t epoch;
+    size_t read_bytes = cbor_deserialize_uint64_t(stream, offset, &epoch);
+
+    if (!read_bytes) {
+        return 0;
+    }
+
+    *val = (time_t)epoch;
+    return read_bytes + 1; /* + 1 tag byte */
+}
+
+size_t cbor_serialize_date_time_epoch(cbor_stream_t *stream, time_t val)
+{
+    /* we need at least 2 bytes (tag byte + at least 1 byte for the integer) */
+    CBOR_ENSURE_SIZE(stream, 2);
+
+    if (val < 0) {
+        return 0; /* we currently don't support negative values for the time_t object */
+    }
+
+    if (!cbor_write_tag(stream, CBOR_DATETIME_EPOCH_FOLLOWS)) {
+        return 0;
+    }
+
+
+    uint64_t time = (uint64_t)val;
+    size_t written_bytes = encode_int(CBOR_UINT, stream, time);
+    return written_bytes + 1; /* + 1 tag byte */
+}
+#endif /* CBOR_NO_CTIME */
+
+
+size_t cbor_write_tag(cbor_stream_t *s, unsigned char tag)
+{
+    CBOR_ENSURE_SIZE(s, 1);
+    s->data[s->pos++] = CBOR_TAG | tag;
+    return 1;
+}
+
+bool cbor_at_tag(const cbor_stream_t *s, size_t offset)
+{
+    return cbor_at_end(s, offset) || CBOR_TYPE(s, offset) == CBOR_TAG;
+}
+#endif /* CBOR_NO_SEMANTIC_TAGGING */
+
+size_t cbor_write_break(cbor_stream_t *s)
+{
+    CBOR_ENSURE_SIZE(s, 1);
+    s->data[s->pos++] = CBOR_BREAK;
+    return 1;
+}
+
+bool cbor_at_break(const cbor_stream_t *s, size_t offset)
+{
+    return cbor_at_end(s, offset) || s->data[offset] == CBOR_BREAK;
+}
+
+bool cbor_at_end(const cbor_stream_t *s, size_t offset)
+{
+    /* cbor_stream_t::pos points at the next *free* byte, hence the -1 */
+    return s ? offset >= s->pos - 1 : true;
+}
+
+#ifndef CBOR_NO_PRINT
+/* BEGIN: Printers */
+void cbor_stream_print(const cbor_stream_t *stream)
+{
+    dump_memory(stream->data, stream->pos);
+}
+
+/**
+ * Skip byte(s) at offset @p offset in stream @p stream
+ *
+ * This function can be used as fallback, in case we cannot deserialize the
+ * current byte
+ */
+static size_t cbor_stream_decode_skip(cbor_stream_t *stream, size_t offset)
+{
+    size_t consume_bytes = 0;
+
+    switch (CBOR_ADDITIONAL_INFO(stream, offset)) {
+        case CBOR_BYTE_FOLLOWS:
+            consume_bytes = 2;
+            break;
+
+        default:
+            consume_bytes = 1;
+            break;
+    }
+
+    DEBUG("(unsupported, ");
+    dump_memory(stream->data + offset, consume_bytes);
+    DEBUG(")\n");
+    return consume_bytes;
+}
+
+/**
+ * Decode CBOR data item from @p stream at position @p offset
+ *
+ * @return Amount of bytes consumed
+ */
+static size_t cbor_stream_decode_at(cbor_stream_t *stream, size_t offset, int indent)
+{
+#define DESERIALIZE_AND_PRINT(type, suffix, format_string) { \
+        type val; \
+        size_t read_bytes = cbor_deserialize_##suffix(stream, offset, &val); \
+        DEBUG("("#type", "format_string")\n", val); \
+        return read_bytes; \
+    }
+
+    DEBUG("%*s", indent, "");
+
+    switch (CBOR_TYPE(stream, offset)) {
+        case CBOR_UINT:
+            DESERIALIZE_AND_PRINT(uint64_t, uint64_t, "%" PRIu64)
+        case CBOR_NEGINT:
+            DESERIALIZE_AND_PRINT(int64_t, int64_t, "%" PRId64)
+        case CBOR_BYTES: {
+            char buffer[CBOR_STREAM_PRINT_BUFFERSIZE];
+            size_t read_bytes = cbor_deserialize_byte_string(stream, offset, buffer, sizeof(buffer));
+            DEBUG("(byte string, \"%s\")\n", buffer);
+            return read_bytes;
+        }
+
+        case CBOR_TEXT: {
+            char buffer[CBOR_STREAM_PRINT_BUFFERSIZE];
+            size_t read_bytes = cbor_deserialize_unicode_string(stream, offset, buffer, sizeof(buffer));
+            DEBUG("(unicode string, \"%s\")\n", buffer);
+            return read_bytes;
+        }
+
+        case CBOR_ARRAY: {
+            const bool is_indefinite = (stream->data[offset] == (CBOR_ARRAY | CBOR_VAR_FOLLOWS));
+            uint64_t array_length;
+            size_t read_bytes;
+
+            if (is_indefinite) {
+                offset += read_bytes = cbor_deserialize_array_indefinite(stream, offset);
+                DEBUG("(array, length: [indefinite])\n");
+            }
+            else {
+                offset += read_bytes = decode_int(stream, offset, &array_length);
+                DEBUG("(array, length: %"PRIu64")\n", array_length);
+            }
+
+            size_t i = 0;
+
+            while (is_indefinite ? !cbor_at_break(stream, offset) : i < array_length) {
+                size_t inner_read_bytes;
+                offset += inner_read_bytes = cbor_stream_decode_at(stream, offset, indent + 2);
+
+                if (inner_read_bytes == 0) {
+                    DEBUG("Failed to read array item at position %d", i);
+                    break;
+                }
+
+                read_bytes += inner_read_bytes;
+                ++i;
+            }
+
+            read_bytes += cbor_at_break(stream, offset);
+            return read_bytes;
+        }
+
+        case CBOR_MAP: {
+            const bool is_indefinite = (stream->data[offset] == (CBOR_MAP | CBOR_VAR_FOLLOWS));
+            uint64_t map_length;
+            size_t read_bytes;
+
+            if (is_indefinite) {
+                offset += read_bytes = cbor_deserialize_map_indefinite(stream, offset);
+                DEBUG("(map, length: [indefinite])\n");
+            }
+            else {
+                offset += read_bytes = decode_int(stream, offset, &map_length);
+                DEBUG("(map, length: %"PRIu64")\n", map_length);
+            }
+
+            size_t i = 0;
+
+            while (is_indefinite ? !cbor_at_break(stream, offset) : i < map_length) {
+                size_t key_read_bytes, value_read_bytes;
+                offset += key_read_bytes = cbor_stream_decode_at(stream, offset, indent + 1); /* key */
+                offset += value_read_bytes = cbor_stream_decode_at(stream, offset, indent + 2); /* value */
+
+                if (key_read_bytes == 0 || value_read_bytes == 0) {
+                    DEBUG("Failed to read key-value pair at position %d", i);
+                    break;
+                }
+
+                read_bytes += key_read_bytes + value_read_bytes;
+                ++i;
+            }
+
+            read_bytes += cbor_at_break(stream, offset);
+            return read_bytes;
+        }
+
+        case CBOR_TAG: {
+            unsigned char tag = CBOR_ADDITIONAL_INFO(stream, offset);
+
+            switch (tag) {
+                    // Non-native builds likely don't have support for ctime (hence disable it there)
+                    // TODO: Better check for availability of ctime functions?
+#ifndef CBOR_NO_CTIME
+                case CBOR_DATETIME_STRING_FOLLOWS: {
+                    char buf[64];
+                    struct tm timeinfo;
+                    size_t read_bytes = cbor_deserialize_date_time(stream, offset, &timeinfo);
+                    strftime(buf, sizeof(buf), "%c", &timeinfo);
+                    DEBUG("(tag: %u, date/time string: \"%s\")\n", tag, buf);
+                    return read_bytes;
+                }
+
+                case CBOR_DATETIME_EPOCH_FOLLOWS: {
+                    time_t time;
+                    size_t read_bytes = cbor_deserialize_date_time_epoch(stream, offset, &time);
+                    DEBUG("(tag: %u, date/time epoch: %d)\n", tag, (int)time);
+                    return read_bytes;
+                }
+
+#endif /* CBOR_NO_CTIME */
+
+                default:
+                    break;
+            }
+        }
+
+        case CBOR_7: {
+            switch (stream->data[offset]) {
+                case CBOR_FALSE:
+                case CBOR_TRUE:
+                    DESERIALIZE_AND_PRINT(bool, bool, "%d")
+#ifndef CBOR_NO_FLOAT
+                case CBOR_FLOAT16:
+                    DESERIALIZE_AND_PRINT(float, float_half, "%f")
+                case CBOR_FLOAT32:
+                    DESERIALIZE_AND_PRINT(float, float, "%f")
+                case CBOR_FLOAT64:
+                    DESERIALIZE_AND_PRINT(double, double, "%lf")
+#endif /* CBOR_NO_FLOAT */
+                default:
+                    break;
+            }
+        }
+    }
+
+    // if we end up here, we weren't able to parse the current byte
+    // let's just skip this (and the next one as well if required)
+    return cbor_stream_decode_skip(stream, offset);
+
+#undef DESERIALIZE_AND_PRINT
+}
+
+void cbor_stream_decode(cbor_stream_t *stream)
+{
+    DEBUG("Data:\n");
+    size_t offset = 0;
+
+    while (offset < stream->pos) {
+        size_t read_bytes = cbor_stream_decode_at(stream, offset, 0);
+
+        if (read_bytes == 0) {
+            DEBUG("Failed to read from stream at offset %d, start byte 0x%02X\n", offset, stream->data[offset]);
+            cbor_stream_print(stream);
+            return;
+        }
+
+        offset += read_bytes;
+    }
+
+    DEBUG("\n");
+}
+
+#endif /* CBOR_NO_PRINT */
+
+/* END: Printers */
diff --git a/sys/include/cbor.h b/sys/include/cbor.h
new file mode 100644
index 0000000000000000000000000000000000000000..c86addef7ffdcf97119e494f9eaff2cc5b5bf683
--- /dev/null
+++ b/sys/include/cbor.h
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2014 Freie Universität Berlin
+ * Copyright (C) 2014 Kevin Funk <kfunk@kde.org>
+ * Copyright (C) 2014 Jana Cavojska <jana.cavojska9@gmail.com>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup     cbor
+ * @{
+ */
+
+/**
+ * @file
+ * @brief       Implementation of a CBOR serializer/deserializer in C
+ *
+ * @author      Kevin Funk <kfunk@kde.org>
+ * @author      Jana Cavojska <jana.cavojska9@gmail.com>
+ *
+ * This is an implementation suited for constrained devices
+ * Characteristics:
+ * - No dynamic memory allocation (i.e. no calls to @e malloc, @e free) used throughout the implementation
+ * - User may allocate static buffers, this implementation uses the space provided by them (cf. @ref cbor_stream_t)
+ *
+ * @par Supported types (categorized by major type (MT)):
+ *
+ * - Major type 0 (unsigned integer): Full support. Relevant functions:
+ *   - cbor_serialize_int(), cbor_deserialize_int()
+ *   - cbor_serialize_uint64_t(), cbor_deserialize_uint64_t()
+ *
+ * - Major type 1 (negative integer): Full support. Relevant functions:
+ *   - cbor_serialize_int(), cbor_deserialize_int()
+ *   - cbor_serialize_int64_t(), cbor_deserialize_int64_t()
+ *
+ * - Major type 2 (byte string): Full support. Relevant functions:
+ *   - cbor_serialize_byte_string(), cbor_deserialize_byte_string()
+ *
+ * - Major type 3 (unicode string): Basic support (see below). Relevant functions:
+ *   - cbor_serialize_unicode_string(), cbor_deserialize_unicode_string()
+ *
+ * - Major type 4 (array of data items): Full support. Relevant functions:
+ *   - cbor_serialize_array(), cbor_deserialize_array()
+ *   - cbor_serialize_indefinite_array(), cbor_deserialize_indefinite_array(), cbor_at_break()
+ *
+ * - Major type 5 (map of pairs of data items): Full support. Relevant functions:
+ *   - cbor_serialize_map(), cbor_deserialize_map()
+ *   - cbor_serialize_indefinite_map(), cbor_deserialize_indefinite_map(), cbor_at_break()
+ *
+ * - Major type 6 (optional semantic tagging of other major types): Basic support (see below). Relevant functions:
+ *   - cbor_write_tag()
+ *   - cbor_deserialize_date_time()
+ *   - cbor_serialize_date_time()
+ *
+ * - Major type 7 (floating-point numbers and values with no content): Basic support (see below). Relevant functions:
+ *   - cbor_serialize_float_half(), cbor_deserialize_float_half()
+ *   - cbor_serialize_float(), cbor_deserialize_float()
+ *   - cbor_serialize_double(), cbor_deserialize_double()
+ *   - cbor_serialize_bool(), cbor_deserialize_bool()
+ *
+ * @par Notes about major type 3:
+ * Since we do not have a standardised C type for representing Unicode code points,
+ * we just provide API to serialize/deserialize @e char* arrays. The user then
+ * has to transform that into a meaningful representation
+ *
+ * @par Notes about major type 6 (cf. https://tools.ietf.org/html/rfc7049#section-2.4):
+ * Encoding date and time: date/time strings that follow the standard format described in Section 3.3 of [RFC3339]:
+ *   2003-12-13T18:30:02Z          - supported
+ *   2003-12-13T18:30:02.25Z       - not supported
+ *   2003-12-13T18:30:02+01:00     - not supported
+ *   2003-12-13T18:30:02.25+01:00  - not supported
+ * Since we do not have C types for representing bignums/bigfloats/decimal-fraction
+ * we do not provide API to serialize/deserialize them at all.
+ * You can still read out the actual data item behind the tag (via cbor_deserialize_byte_string())
+ * and interpret it yourself.
+ *
+ * @par Notes about major type 7 and simple values (cf. https://tools.ietf.org/html/rfc7049#section-2.3)
+ * Simple values:
+ * -   0-19: (Unassigned)    - No support
+ * -  20,21: True, False     - Supported (see cbor_serialize_bool(), cbor_deserialize_bool())
+ * -  22,23: Null, Undefined - No support (what's the use-case?)
+ * -  24-31: (Reserved)      - No support
+ * - 32-255: (Unassigned)    - No support
+ *
+ * TODO: API for Indefinite-Length Byte Strings and Text Strings
+ *       (see https://tools.ietf.org/html/rfc7049#section-2.2.2)
+ */
+
+#ifndef CBOR_H
+#define CBOR_H
+
+#ifndef CBOR_NO_CTIME
+/* 'strptime' is only declared when this macro is defined */
+#define _XOPEN_SOURCE
+#endif
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#ifndef CBOR_NO_CTIME
+#include <time.h>
+#endif /* CBOR_NO_CTIME */
+
+/**
+ * @brief Struct containing CBOR-encoded data
+ *
+ * A typical usage of CBOR looks like:
+ * @code
+ * unsigned char data[1024];
+ * cbor_stream_t stream;
+ * cbor_init(&stream, data, sizeof(data));
+ *
+ * cbor_serialize_int(&stream, 5);
+ * (...)
+ * <data contains CBOR encoded items now>
+ *
+ * cbor_destroy(&stream);
+ * @endcode
+ *
+ * @sa cbor_init
+ * @sa cbor_clear
+ * @sa cbor_destroy
+ */
+typedef struct cbor_stream_t {
+    /* Array containing CBOR encoded data */
+    unsigned char *data;
+    /* Size of the array */
+    size_t size;
+    /* Index to the next free byte */
+    size_t pos;
+} cbor_stream_t;
+
+/**
+ * Initialize cbor struct
+ *
+ * @note Does *not* take ownership of @p buffer
+ *
+ * @param buffer The buffer used for storing CBOR-encoded data
+ * @param size The size of buffer @p buffer
+ */
+void cbor_init(cbor_stream_t *stream, unsigned char *buffer, size_t size);
+
+/**
+ * Clear cbor struct
+ *
+ * Sets pos to zero
+ */
+void cbor_clear(cbor_stream_t *stream);
+
+/**
+ * Destroy the cbor struct
+ *
+ * @note Does *not* free data
+ */
+void cbor_destroy(cbor_stream_t *stream);
+
+#ifndef CBOR_NO_PRINT
+/**
+ * Print @p stream in hex representation
+ */
+void cbor_stream_print(const cbor_stream_t *stream);
+
+/**
+ * Decode CBOR from @p stream
+ *
+ * This method interprets the data and prints each item in its natural representation
+ *
+ * Example output:
+ * @code
+ * Data:
+ * (int, 1)
+ * (bool, 1)
+ * (float, 1.099609)
+ * (tag: 0, date/time string: "Mon Jul 14 19:07:40 2014")
+ * (tag: 1, date/time epoch: 1405357660)
+ * @endcode
+ */
+void cbor_stream_decode(cbor_stream_t *stream);
+#endif /* CBOR_NO_PRINT */
+
+size_t cbor_serialize_int(cbor_stream_t *s, int val);
+size_t cbor_deserialize_int(const cbor_stream_t *stream, size_t offset, int *val);
+size_t cbor_serialize_uint64_t(cbor_stream_t *s, uint64_t val);
+size_t cbor_deserialize_uint64_t(const cbor_stream_t *stream, size_t offset, uint64_t *val);
+size_t cbor_serialize_int64_t(cbor_stream_t *s, int64_t val);
+size_t cbor_deserialize_int64_t(const cbor_stream_t *stream, size_t offset, int64_t *val);
+size_t cbor_serialize_bool(cbor_stream_t *s, bool val);
+size_t cbor_deserialize_bool(const cbor_stream_t *stream, size_t offset, bool *val);
+#ifndef CBOR_NO_FLOAT
+size_t cbor_serialize_float_half(cbor_stream_t *s, float val);
+size_t cbor_deserialize_float_half(const cbor_stream_t *stream, size_t offset, float *val);
+size_t cbor_serialize_float(cbor_stream_t *s, float val);
+size_t cbor_deserialize_float(const cbor_stream_t *stream, size_t offset, float *val);
+size_t cbor_serialize_double(cbor_stream_t *s, double val);
+size_t cbor_deserialize_double(const cbor_stream_t *stream, size_t offset, double *val);
+#endif /* CBOR_NO_FLOAT */
+
+size_t cbor_serialize_byte_string(cbor_stream_t *s, const char *val);
+/**
+ * Deserialize bytes from @p stream to @p val
+ *
+ * @param val Pointer to destination array
+ * @param length Length of destination array
+ * @return Number of bytes written into @p val
+ */
+size_t cbor_deserialize_byte_string(const cbor_stream_t *stream, size_t offset, char *val, size_t length);
+size_t cbor_serialize_unicode_string(cbor_stream_t *s, const char *val);
+/**
+ * Deserialize unicode string from @p stream to @p val
+ *
+ * @param val Pointer to destination array
+ * @param length Length of destination array
+ * @return Number of bytes written into @p val
+ */
+size_t cbor_deserialize_unicode_string(const cbor_stream_t *stream, size_t offset, char *val, size_t length);
+
+/**
+ * Serialize array of length @p array_length
+ *
+ * Basic usage:
+ * @code
+ * cbor_serialize_array(&stream, 2); // array of length 2 follows
+ * cbor_serialize_int(&stream, 1)); // write item 1
+ * cbor_serialize_int(&stream, 2)); // write item 2
+ * @endcode
+ *
+ * @note You have to make sure to serialize the correct amount of items.
+ * If you exceed the length @p array_length, items will just be appened as normal
+ *
+ * @param array_length Length of the array of items which follows
+ *
+ * @return Number of bytes written to stream @p s
+ */
+size_t cbor_serialize_array(cbor_stream_t *s, size_t array_length);
+/**
+ * Deserialize array of items
+ *
+ * Basic usage:
+ * @code
+ * size_t array_length;
+ * size_t offset = cbor_deserialize_array(&stream, 0, &array_length); // read out length of the array
+ * int i1, i2;
+ * offset += cbor_deserialize_int(&stream, offset, &i1); // read item 1
+ * offset += cbor_deserialize_int(&stream, offset, &i2); // read item 2
+ * @endcode
+ *
+ * @param array_length Where the array length is stored
+ */
+size_t cbor_deserialize_array(const cbor_stream_t *s, size_t offset, size_t *array_length);
+
+size_t cbor_serialize_array_indefinite(cbor_stream_t *s);
+size_t cbor_deserialize_array_indefinite(const cbor_stream_t *s, size_t offset);
+
+/**
+ * Serialize map of length @p map_length
+ *
+ * Basic usage:
+ * @code
+ * cbor_serialize_map(&stream, 2); // map of length 2 follows
+ * cbor_serialize_int(&stream, 1)); // write key 1
+ * cbor_serialize_byte_string(&stream, "1")); // write value 1
+ * cbor_serialize_int(&stream, 2)); // write key 2
+ * cbor_serialize_byte_string(&stream, "2")); // write value 2
+ * @endcode
+ *
+ * @param map_length Length of the map of items which follows
+ */
+size_t cbor_serialize_map(cbor_stream_t *s, size_t map_length);
+/**
+ * Deserialize map of items
+ *
+ * Basic usage:
+ * @code
+ * size_t map_length;
+ * size_t offset = cbor_deserialize_map(&stream, 0, &map_length); // read out length of the map
+ * int key1, key1;
+ * char value1[8], value2[8];
+ * offset += cbor_deserialize_int(&stream, offset, &key1); // read key 1
+ * offset += cbor_deserialize_byte_string(&stream, offset, value1, sizeof(value)); // read value 1
+ * offset += cbor_deserialize_int(&stream, offset, &key2); // read key 2
+ * offset += cbor_deserialize_byte_string(&stream, offset, value2, sizeof(value)); // read value 2
+ * @endcode
+ *
+ * @param array_length Where the array length is stored
+ */
+size_t cbor_deserialize_map(const cbor_stream_t *s, size_t offset, size_t *map_length);
+
+size_t cbor_serialize_map_indefinite(cbor_stream_t *s);
+size_t cbor_deserialize_map_indefinite(const cbor_stream_t *s, size_t offset);
+
+#ifndef CBOR_NO_SEMANTIC_TAGGING
+#ifndef CBOR_NO_CTIME
+/**
+ * Serialize date and time
+ *
+ * Basic usage:
+ * @code
+ * struct tm val;
+ * val.tm_year = 114;
+ * val.tm_mon = 6;
+ * val.tm_mday = 1;
+ * val.tm_hour = 15;
+ * val.tm_min = 0;
+ * val.tm_sec = 0;
+ * mktime(&val);
+ * cbor_serialize_date_time(&stream, &val);
+ * @endcode
+ *
+ * @param val  tm struct containing the date/time info to be encoded
+ */
+size_t cbor_serialize_date_time(cbor_stream_t *stream, struct tm *val);
+/**
+ * Deserialize date and time
+ *
+ * Basic usage:
+ * @code
+ * struct tm val;
+ * cbor_deserialize_date_time(&stream, 0, &val);
+ * @endcode
+ *
+ * @param val  tm struct where the decoded date/time will be stored
+ */
+size_t cbor_deserialize_date_time(const cbor_stream_t *stream, size_t offset, struct tm *val);
+
+size_t cbor_serialize_date_time_epoch(cbor_stream_t *stream, time_t val);
+size_t cbor_deserialize_date_time_epoch(const cbor_stream_t *stream, size_t offset, time_t *val);
+#endif /* CBOR_NO_CTIME */
+
+/**
+ * Write a tag to give the next CBOR item additional semantics
+ *
+ * Also see https://tools.ietf.org/html/rfc7049#section-2.4 (Optional Tagging of Items)
+ */
+size_t cbor_write_tag(cbor_stream_t *s, unsigned char tag);
+/**
+ * Whether we are at a tag symbol in stream @p s at offset @p offset
+ *
+ * @return True in case there is a tag symbol at the current offset
+ */
+bool cbor_at_tag(const cbor_stream_t *s, size_t offset);
+/**
+ * Write a break symbol at the current offset in stream @p s
+ *
+ * Used for marking the end of indefinite length CBOR items
+ */
+#endif /* CBOR_NO_SEMANTIC_TAGGING */
+
+size_t cbor_write_break(cbor_stream_t *s);
+/**
+ * Whether we are at a break symbol in stream @p s at offset @p offset
+ *
+ * @return True in case the there is a break symbol at the current offset
+ */
+bool cbor_at_break(const cbor_stream_t *s, size_t offset);
+/**
+ * Whether we are at the end of the stream @p s at offset @p offset
+ *
+ * Useful for abort conditions in loops while deserializing CBOR items
+ *
+ * @return True in case @p offset marks the end of the stream
+ */
+bool cbor_at_end(const cbor_stream_t *s, size_t offset);
+
+#endif
+
+/** @} */
diff --git a/tests/unittests/Makefile b/tests/unittests/Makefile
index 60e2b84606602f991db8f9e5f90959b2d81b6ecd..6258351271b241de83f194a9e2bc0c73106aec52 100644
--- a/tests/unittests/Makefile
+++ b/tests/unittests/Makefile
@@ -1,6 +1,8 @@
 APPLICATION = unittests
 include ../Makefile.tests_common
 
+BOARD_INSUFFICIENT_RAM := chronos redbee-econotag stm32f0discovery
+
 USEMODULE += embunit
 
 INCLUDES += -I$(RIOTBASE)/tests/unittests/embunit
diff --git a/tests/unittests/tests-cbor/Makefile b/tests/unittests/tests-cbor/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..a129232f923b8e2f5dbc1c751d5ee431e1ea99bb
--- /dev/null
+++ b/tests/unittests/tests-cbor/Makefile
@@ -0,0 +1,9 @@
+MODULE = tests-cbor
+
+CFLAGS += -DCBOR_NO_PRINT
+
+ifeq (,$(filter native,$(BOARD)))
+	CFLAGS += -DCBOR_NO_FLOAT -DCBOR_NO_PRINT -DCBOR_NO_SEMANTIC_TAGGING
+endif
+
+include $(RIOTBASE)/Makefile.base
diff --git a/tests/unittests/tests-cbor/Makefile.include b/tests/unittests/tests-cbor/Makefile.include
new file mode 100644
index 0000000000000000000000000000000000000000..292ca1d0af87a8e563212a843c78629cc8314cc0
--- /dev/null
+++ b/tests/unittests/tests-cbor/Makefile.include
@@ -0,0 +1 @@
+USEMODULE += cbor
diff --git a/tests/unittests/tests-cbor/tests-cbor.c b/tests/unittests/tests-cbor/tests-cbor.c
new file mode 100644
index 0000000000000000000000000000000000000000..cb5aee970a72f51d213766b7e26b29f69a21d0d8
--- /dev/null
+++ b/tests/unittests/tests-cbor/tests-cbor.c
@@ -0,0 +1,790 @@
+/*
+ * Copyright (C) 2014 Freie Universität Berlin
+ * Copyright (C) 2014 Kevin Funk <kfunk@kde.org>
+ * Copyright (C) 2014 Jana Cavojska <jana.cavojska9@gmail.com>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @author      Kevin Funk <kfunk@kde.org>
+ * @author      Jana Cavojska <jana.cavojska9@gmail.com>
+ */
+
+#include "../unittests.h"
+
+#include "bitarithm.h"
+#include "cbor.h"
+
+#include <float.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#ifndef CBOR_NO_CTIME
+#include <time.h>
+#endif /* CBOR_NO_CTIME */
+
+static void my_cbor_print(const cbor_stream_t *stream)
+{
+#ifndef CBOR_NO_PRINT
+    cbor_stream_print(stream);
+#else
+    printf("<no print support>");
+#endif
+}
+
+#define CBOR_CHECK_SERIALIZED(stream, expected_value, expected_value_size) do { \
+    if (memcmp(stream.data, expected_value, expected_value_size) != 0) { \
+        printf("\n"); \
+        printf("  CBOR encoded data: "); my_cbor_print(&stream); printf("\n"); \
+        cbor_stream_t tmp = {expected_value, expected_value_size, expected_value_size}; \
+        printf("  Expected data    : "); my_cbor_print(&tmp); printf("\n"); \
+        TEST_FAIL("Test failed"); \
+    } \
+} while(0)
+
+#define CBOR_CHECK_DESERIALIZED(expected_value, actual_value, comparator_function) do { \
+    TEST_ASSERT(comparator_function(expected_value, actual_value)); \
+} while(0)
+
+/* Macro for checking PODs (int, float, ...) */
+#define CBOR_CHECK(type, function_suffix, stream, input, expected_value, comparator) do { \
+    type buffer; \
+    unsigned char data[] = expected_value; \
+    cbor_clear(&stream); \
+    TEST_ASSERT(cbor_serialize_##function_suffix(&stream, input)); \
+    CBOR_CHECK_SERIALIZED(stream, data, sizeof(data)); \
+    cbor_stream_t tmp = {data, sizeof(data), sizeof(data)}; \
+    TEST_ASSERT(cbor_deserialize_##function_suffix(&tmp, 0, &buffer)); \
+    CBOR_CHECK_DESERIALIZED(input, buffer, comparator); \
+} while(0)
+
+#define HEX_LITERAL(...) {__VA_ARGS__}
+
+/* BEGIN: Comparator functions */
+#define EQUAL_INT(a, b) \
+    (a == b)
+#define EQUAL_FLOAT(a, b) ( \
+    (isinf(a) && isinf(b)) || \
+    (isnan(a) && isnan(b)) || \
+    (fabs(a - b) < 0.00001))
+#define EQUAL_STRING(a, b) \
+    (strcmp(a, b) == 0)
+#define EQUAL_DATE_TIME(a, b) ( \
+    (a.tm_isdst == b.tm_isdst) && \
+    (a.tm_yday == b.tm_yday) && \
+    (a.tm_wday == b.tm_wday) && \
+    (a.tm_year == b.tm_year) && \
+    (a.tm_mon == b.tm_mon) && \
+    (a.tm_mday == b.tm_mday) && \
+    (a.tm_hour == b.tm_hour) && \
+    (a.tm_min == b.tm_min) && \
+    (a.tm_sec == b.tm_sec))
+/* END: Comparator functions */
+
+#ifndef INFINITY
+#define INFINITY (1.0/0.0)
+#endif
+#ifndef NAN
+#define NAN (0.0/0.0)
+#endif
+
+static unsigned char stream_data[1024];
+cbor_stream_t stream = {stream_data, sizeof(stream_data), 0};
+
+cbor_stream_t empty_stream = {NULL, 0, 0}; /* stream that is not large enough */
+
+unsigned char invalid_stream_data[] = {0x40}; /* empty string encoded in CBOR */
+cbor_stream_t invalid_stream = {invalid_stream_data, sizeof(invalid_stream_data),
+                                sizeof(invalid_stream_data)
+                               };
+
+static void setUp(void)
+{
+    cbor_clear(&stream);
+}
+
+static void tearDown(void)
+{
+}
+
+static void test_int(void)
+{
+    /* positive values */
+    CBOR_CHECK(int, int, stream, 0,  HEX_LITERAL(0x00), EQUAL_INT);
+    CBOR_CHECK(int, int, stream, 23, HEX_LITERAL(0x17), EQUAL_INT);
+
+    CBOR_CHECK(int, int, stream, 24,   HEX_LITERAL(0x18, 0x18), EQUAL_INT);
+    CBOR_CHECK(int, int, stream, 0xff, HEX_LITERAL(0x18, 0xff), EQUAL_INT);
+
+    CBOR_CHECK(int, int, stream, 0xff + 1, HEX_LITERAL(0x19, 0x01, 0x00), EQUAL_INT);
+    CBOR_CHECK(int, int, stream, 0xffff, HEX_LITERAL(0x19, 0xff, 0xff), EQUAL_INT);
+
+    CBOR_CHECK(int, int, stream, 0xffff + 1,
+               HEX_LITERAL(0x1a, 0x00, 0x01, 0x00, 0x00), EQUAL_INT);
+#if ARCH_32_BIT
+    CBOR_CHECK(int, int, stream, 0x7fffffff,
+               HEX_LITERAL(0x1a, 0x7f, 0xff, 0xff, 0xff), EQUAL_INT);
+#endif
+
+    /* negative values */
+    CBOR_CHECK(int, int, stream, -1,  HEX_LITERAL(0x20), EQUAL_INT);
+    CBOR_CHECK(int, int, stream, -24, HEX_LITERAL(0x37), EQUAL_INT);
+
+    CBOR_CHECK(int, int, stream, -25,     HEX_LITERAL(0x38, 0x18), EQUAL_INT);
+    CBOR_CHECK(int, int, stream, -0xff - 1, HEX_LITERAL(0x38, 0xff), EQUAL_INT);
+
+    CBOR_CHECK(int, int, stream, -0xff - 2,   HEX_LITERAL(0x39, 0x01, 0x00), EQUAL_INT);
+    CBOR_CHECK(int, int, stream, -0xffff - 1, HEX_LITERAL(0x39, 0xff, 0xff), EQUAL_INT);
+
+    CBOR_CHECK(int, int, stream, -0xffff - 2,
+               HEX_LITERAL(0x3a, 0x00, 0x01, 0x00, 0x00), EQUAL_INT);
+#if ARCH_32_BIT
+    CBOR_CHECK(int, int, stream, -0x7fffffff - 1,
+               HEX_LITERAL(0x3a, 0x7f, 0xff, 0xff, 0xff), EQUAL_INT);
+#endif
+}
+
+static void test_uint64_t(void)
+{
+    CBOR_CHECK(uint64_t, uint64_t, stream, 0x0,
+               HEX_LITERAL(0x00), EQUAL_INT);
+    CBOR_CHECK(uint64_t, uint64_t, stream, 0xff,
+               HEX_LITERAL(0x18, 0xff), EQUAL_INT);
+    CBOR_CHECK(uint64_t, uint64_t, stream, 0xffff,
+               HEX_LITERAL(0x19, 0xff, 0xff), EQUAL_INT);
+
+    CBOR_CHECK(uint64_t, uint64_t, stream, 0xffffffffull,
+               HEX_LITERAL(0x1a, 0xff, 0xff, 0xff, 0xff), EQUAL_INT);
+    CBOR_CHECK(uint64_t, uint64_t, stream, 0xffffffffffffffffull,
+               HEX_LITERAL(0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff), EQUAL_INT);
+}
+
+static void test_int_invalid(void)
+{
+    {
+        /* check writing to stream that is not large enough */
+        /* basically tests internal 'encode_int' function */
+
+        cbor_stream_t stream;
+        cbor_init(&stream, 0, 0);
+
+        /* check each possible branch in 'encode_int' */
+        /* (value in first byte, uint8 follows, uint16 follows, uint64 follows) */
+        TEST_ASSERT_EQUAL_INT(0, cbor_serialize_int(&stream, 0));
+        TEST_ASSERT_EQUAL_INT(0, stream.pos);
+        TEST_ASSERT_EQUAL_INT(0, cbor_serialize_int(&stream, 24));
+        TEST_ASSERT_EQUAL_INT(0, stream.pos);
+        TEST_ASSERT_EQUAL_INT(0, cbor_serialize_int(&stream, 0xff + 1));
+        TEST_ASSERT_EQUAL_INT(0, stream.pos);
+        TEST_ASSERT_EQUAL_INT(0, cbor_serialize_int(&stream, 0xffff + 1));
+        TEST_ASSERT_EQUAL_INT(0, stream.pos);
+    }
+
+    {
+        /* check reading from stream that contains other type of data */
+
+        int val_int = 0;
+        TEST_ASSERT_EQUAL_INT(0, cbor_deserialize_int(&invalid_stream, 0, &val_int));
+    }
+}
+
+static void test_uint64_t_invalid(void)
+{
+    {
+        cbor_stream_t stream;
+        cbor_init(&stream, 0, 0);
+
+        /* let's do this for 'cbor_serialize_int64_t', too */
+        /* this uses 'encode_int' internally, as well, so let's just test if the */
+        /* 'cbor_serialize_int64_t' wrapper is sane */
+        TEST_ASSERT_EQUAL_INT(0, cbor_serialize_uint64_t(&stream, 0));
+        TEST_ASSERT_EQUAL_INT(0, stream.pos);
+    }
+
+    {
+        /* check reading from stream that contains other type of data */
+        unsigned char data[] = {0x40}; /* empty string encoded in CBOR */
+        cbor_stream_t stream = {data, 1, 1};
+        uint64_t val_uint64_t = 0;
+        TEST_ASSERT_EQUAL_INT(0, cbor_deserialize_uint64_t(&stream, 0, &val_uint64_t));
+    }
+}
+
+static void test_int64_t(void)
+{
+    CBOR_CHECK(int64_t, int64_t, stream, -1,
+               HEX_LITERAL(0x20), EQUAL_INT);
+    CBOR_CHECK(int64_t, int64_t, stream, -0xff - 1,
+               HEX_LITERAL(0x38, 0xff), EQUAL_INT);
+    CBOR_CHECK(int64_t, int64_t, stream, -0xffff - 1,
+               HEX_LITERAL(0x39, 0xff, 0xff), EQUAL_INT);
+    CBOR_CHECK(int64_t, int64_t, stream, -0xffffffffll - 1,
+               HEX_LITERAL(0x3a, 0xff, 0xff, 0xff, 0xff), EQUAL_INT);
+    CBOR_CHECK(int64_t, int64_t, stream, -0x7fffffffffffffffll - 1,
+               HEX_LITERAL(0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff), EQUAL_INT);
+}
+
+static void test_int64_t_invalid(void)
+{
+    {
+        /* check writing to stream that is not large enough (also see test_major_type_0_invalid) */
+
+        cbor_stream_t stream;
+        cbor_init(&stream, 0, 0);
+
+        TEST_ASSERT_EQUAL_INT(0, cbor_serialize_int64_t(&stream, 0));
+        TEST_ASSERT_EQUAL_INT(0, stream.pos);
+    }
+
+    {
+        /* check reading from stream that contains other type of data */
+
+        unsigned char data[] = {0x40}; /* empty string encoded in CBOR */
+        cbor_stream_t stream = {data, 1, 1};
+
+        int64_t val = 0;
+        TEST_ASSERT_EQUAL_INT(0, cbor_deserialize_int64_t(&stream, 0, &val));
+    }
+}
+
+static void test_byte_string(void)
+{
+    char buffer[128];
+
+    {
+        const char *input = "";
+        unsigned char data[] = {0x40};
+        TEST_ASSERT(cbor_serialize_byte_string(&stream, input));
+        CBOR_CHECK_SERIALIZED(stream, data, sizeof(data));
+        TEST_ASSERT(cbor_deserialize_byte_string(&stream, 0, buffer, sizeof(buffer)));
+        CBOR_CHECK_DESERIALIZED(input, buffer, EQUAL_STRING);
+    }
+
+    cbor_clear(&stream);
+
+    {
+        const char *input = "a";
+        unsigned char data[] = {0x41, 0x61};
+        TEST_ASSERT(cbor_serialize_byte_string(&stream, input));
+        CBOR_CHECK_SERIALIZED(stream, data, sizeof(data));
+        TEST_ASSERT(cbor_deserialize_byte_string(&stream, 0, buffer, sizeof(buffer)));
+        CBOR_CHECK_DESERIALIZED(input, buffer, EQUAL_STRING);
+    }
+}
+
+static void test_byte_string_invalid(void)
+{
+    {
+        /* check writing to stream that is not large enough */
+        cbor_stream_t stream;
+        cbor_init(&stream, 0, 0);
+
+        TEST_ASSERT_EQUAL_INT(0, cbor_serialize_byte_string(&stream, "foo"));
+
+        cbor_destroy(&stream);
+    }
+}
+
+
+static void test_unicode_string(void)
+{
+    char buffer[128];
+
+    {
+        const char *input = "";
+        unsigned char data[] = {0x60};
+        TEST_ASSERT(cbor_serialize_unicode_string(&stream, input));
+        CBOR_CHECK_SERIALIZED(stream, data, sizeof(data));
+        TEST_ASSERT(cbor_deserialize_unicode_string(&stream, 0, buffer, sizeof(buffer)));
+        CBOR_CHECK_DESERIALIZED(input, buffer, EQUAL_STRING);
+    }
+
+    cbor_clear(&stream);
+
+    {
+        const char *input = "a";
+        unsigned char data[] = {0x61, 0x61};
+        TEST_ASSERT(cbor_serialize_unicode_string(&stream, input));
+        CBOR_CHECK_SERIALIZED(stream, data, sizeof(data));
+        TEST_ASSERT(cbor_deserialize_unicode_string(&stream, 0, buffer, sizeof(buffer)));
+        CBOR_CHECK_DESERIALIZED(input, buffer, EQUAL_STRING);
+    }
+}
+
+static void test_unicode_string_invalid(void)
+{
+    {
+        /* check writing to stream that is not large enough */
+        cbor_stream_t stream;
+        cbor_init(&stream, 0, 0);
+
+        TEST_ASSERT_EQUAL_INT(0, cbor_serialize_unicode_string(&stream, "foo"));
+
+        cbor_destroy(&stream);
+    }
+}
+
+static void test_array(void)
+{
+    /* uniform types */
+    {
+        /* serialization */
+        TEST_ASSERT(cbor_serialize_array(&stream, 2));
+        TEST_ASSERT(cbor_serialize_int(&stream, 1));
+        TEST_ASSERT(cbor_serialize_int(&stream, 2));
+        unsigned char data[] = {0x82, 0x01, 0x02};
+        CBOR_CHECK_SERIALIZED(stream, data, sizeof(data));
+
+        /* deserialization */
+        size_t array_length;
+        size_t offset = cbor_deserialize_array(&stream, 0, &array_length);
+        TEST_ASSERT_EQUAL_INT(2, array_length);
+        int i;
+        offset += cbor_deserialize_int(&stream, offset, &i);
+        TEST_ASSERT_EQUAL_INT(1, i);
+        offset += cbor_deserialize_int(&stream, offset, &i);
+        TEST_ASSERT_EQUAL_INT(2, i);
+    }
+
+    cbor_clear(&stream);
+
+    /* mixed types */
+    {
+        TEST_ASSERT(cbor_serialize_array(&stream, 2));
+        TEST_ASSERT(cbor_serialize_int(&stream, 1));
+        TEST_ASSERT(cbor_serialize_byte_string(&stream, "a"));
+        unsigned char data[] = {0x82, 0x01, 0x41, 0x61};
+        CBOR_CHECK_SERIALIZED(stream, data, sizeof(data));
+
+        /* deserialization */
+        size_t array_length;
+        size_t offset = cbor_deserialize_array(&stream, 0, &array_length);
+        TEST_ASSERT(offset);
+        TEST_ASSERT_EQUAL_INT(2, array_length);
+        int i;
+        offset += cbor_deserialize_int(&stream, offset, &i);
+        TEST_ASSERT_EQUAL_INT(1, i);
+        char buffer[1024];
+        offset += cbor_deserialize_byte_string(&stream, offset, buffer, sizeof(buffer));
+        TEST_ASSERT_EQUAL_STRING("a", buffer);
+    }
+}
+
+static void test_array_indefinite(void)
+{
+    {
+        /* serialization */
+        TEST_ASSERT(cbor_serialize_array_indefinite(&stream));
+        TEST_ASSERT(cbor_serialize_int(&stream, 1));
+        TEST_ASSERT(cbor_serialize_int(&stream, 2));
+        TEST_ASSERT(cbor_write_break(&stream));
+        unsigned char data[] = {0x9f, 0x01, 0x02, 0xff};
+        CBOR_CHECK_SERIALIZED(stream, data, sizeof(data));
+
+        /* deserialization */
+        size_t offset = cbor_deserialize_array_indefinite(&stream, 0);
+        int count = 0;
+
+        while (!cbor_at_break(&stream, offset)) {
+            int val;
+            size_t read_bytes = cbor_deserialize_int(&stream, offset, &val);
+            TEST_ASSERT(read_bytes);
+            offset += read_bytes;
+            ++count;
+        }
+
+        TEST_ASSERT_EQUAL_INT(2, count);
+        TEST_ASSERT(cbor_at_end(&stream, offset));
+    }
+}
+
+static void test_array_invalid(void)
+{
+    TEST_ASSERT_EQUAL_INT(0, cbor_serialize_array(&empty_stream, 1));
+
+    size_t array_length;
+    TEST_ASSERT_EQUAL_INT(0, cbor_deserialize_array(&invalid_stream, 0, &array_length));
+}
+
+static void test_map(void)
+{
+    {
+        /* serialization */
+        TEST_ASSERT(cbor_serialize_map(&stream, 2));
+        TEST_ASSERT(cbor_serialize_int(&stream, 1));
+        TEST_ASSERT(cbor_serialize_byte_string(&stream, "1"));
+        TEST_ASSERT(cbor_serialize_int(&stream, 2));
+        TEST_ASSERT(cbor_serialize_byte_string(&stream, "2"));
+        unsigned char data[] = {0xa2,
+                                0x01, 0x41, 0x31, /* kv-pair 1 */
+                                0x02, 0x41, 0x32, /* kv-pair 2 */
+                               };
+        CBOR_CHECK_SERIALIZED(stream, data, sizeof(data));
+
+        /* deserialization */
+        size_t map_length;
+        size_t offset = cbor_deserialize_map(&stream, 0, &map_length);
+        TEST_ASSERT_EQUAL_INT(2, map_length);
+        int key;
+        char value[8];
+        offset += cbor_deserialize_int(&stream, offset, &key);
+        TEST_ASSERT_EQUAL_INT(1, key);
+        offset += cbor_deserialize_byte_string(&stream, offset, value, sizeof(value));
+        TEST_ASSERT_EQUAL_STRING("1", value);
+        offset += cbor_deserialize_int(&stream, offset, &key);
+        TEST_ASSERT_EQUAL_INT(2, key);
+        offset += cbor_deserialize_byte_string(&stream, offset, value, sizeof(value));
+        TEST_ASSERT_EQUAL_STRING("2", value);
+    }
+}
+
+static void test_map_indefinite(void)
+{
+    {
+        /* serialization */
+        TEST_ASSERT(cbor_serialize_map_indefinite(&stream));
+        TEST_ASSERT(cbor_serialize_int(&stream, 1));
+        TEST_ASSERT(cbor_serialize_byte_string(&stream, "1"));
+        TEST_ASSERT(cbor_serialize_int(&stream, 2));
+        TEST_ASSERT(cbor_serialize_byte_string(&stream, "2"));
+        TEST_ASSERT(cbor_write_break(&stream));
+        unsigned char data[] = {0xbf,
+                                0x01, 0x41, 0x31, /* kv-pair 1 */
+                                0x02, 0x41, 0x32, /* kv-pair 2 */
+                                0xff
+                               };
+        CBOR_CHECK_SERIALIZED(stream, data, sizeof(data));
+
+        /* deserialization */
+        size_t offset = cbor_deserialize_map_indefinite(&stream, 0);
+        int count = 0;
+
+        while (!cbor_at_break(&stream, offset)) {
+            int key;
+            char value[16];
+            size_t read_bytes;
+            offset += read_bytes = cbor_deserialize_int(&stream, offset, &key);
+            TEST_ASSERT(read_bytes);
+            offset += read_bytes = cbor_deserialize_byte_string(&stream, offset,
+                                   value, sizeof(value));
+            TEST_ASSERT(read_bytes);
+            ++count;
+        }
+
+        TEST_ASSERT_EQUAL_INT(2, count);
+        TEST_ASSERT(cbor_at_end(&stream, offset));
+    }
+}
+
+static void test_map_invalid(void)
+{
+    {
+        /* check writing to stream that is not large enough */
+        cbor_stream_t stream;
+        cbor_init(&stream, 0, 0);
+
+        TEST_ASSERT_EQUAL_INT(0, cbor_serialize_map(&stream, 1));
+
+        cbor_destroy(&stream);
+    }
+    {
+        /* check reading from stream that contains other type of data */
+        unsigned char data[] = {0x40}; /* empty string encoded in CBOR */
+        cbor_stream_t stream = {data, 1, 1};
+
+        size_t map_length;
+        TEST_ASSERT_EQUAL_INT(0, cbor_deserialize_map(&stream, 0, &map_length));
+    }
+}
+
+#ifndef CBOR_NO_SEMANTIC_TAGGING
+static void test_semantic_tagging(void)
+{
+    char buffer[128];
+    {
+        const char *input = "1";
+        /* CBOR: byte string of length 1 marked with a tag to indicate it is a positive bignum */
+        /* byte 1: (major type 6, additional information */
+        /* byte 2: (major type 2, additional 1 for the length) */
+        /* byte 3: bytes representing the bignum */
+        unsigned char data[] = {0xc2, 0x41, 0x31};
+        TEST_ASSERT(cbor_write_tag(&stream, 2)); /* write byte 1 */
+        TEST_ASSERT(cbor_serialize_byte_string(&stream, input)); /* write byte 2 and 3 */
+        CBOR_CHECK_SERIALIZED(stream, data, sizeof(data));
+        TEST_ASSERT(cbor_at_tag(&stream, 0));
+        TEST_ASSERT(cbor_deserialize_byte_string(&stream, 1, buffer, sizeof(buffer)));
+        CBOR_CHECK_DESERIALIZED(input, buffer, EQUAL_STRING);
+    }
+}
+
+#ifndef CBOR_NO_CTIME
+static void test_date_time(void)
+{
+    /* CBOR: UTF-8 string marked with a tag 0 to indicate it is a standard date/time string */
+    /* byte 1: (major type 6, additional information */
+    /* byte 2: (major type 2, additional 23 for the length) */
+    /* bytes 3 to 23: bytes representing the date/time UTF-8 string */
+    unsigned char data[] = {0xC0, 0x74, 0x32, 0x30, 0x31, 0x34, 0x2D, 0x30, 0x37, 0x2D, 0x30, 0x31,
+                            0x54, 0x31, 0x35, 0x3A, 0x30, 0x30, 0x3A, 0x30, 0x30, 0x5A
+                           };
+    struct tm val;
+    val.tm_year = 114;
+    val.tm_mon = 6;
+    val.tm_mday = 1;
+    val.tm_hour = 15;
+    val.tm_min = 0;
+    val.tm_sec = 0;
+    mktime(&val);
+    TEST_ASSERT(cbor_serialize_date_time(&stream, &val));
+    CBOR_CHECK_SERIALIZED(stream, data, sizeof(data));
+
+    TEST_ASSERT(cbor_at_tag(&stream, 0));
+    struct tm val2;
+    TEST_ASSERT(cbor_deserialize_date_time(&stream, 0, &val2));
+    CBOR_CHECK_DESERIALIZED(val, val2, EQUAL_DATE_TIME);
+}
+
+static void test_date_time_epoch(void)
+{
+    /*
+     CBOR: unsigned integer marked with a tag 1 to indicate it is a
+     standard date/time epoch (similar to time_t)
+     */
+    unsigned char data[] = {0xC1, 0x01};
+    time_t val = 1;
+    TEST_ASSERT(cbor_serialize_date_time_epoch(&stream, val));
+    CBOR_CHECK_SERIALIZED(stream, data, sizeof(data));
+    time_t val2 = 0;
+    TEST_ASSERT(cbor_deserialize_date_time_epoch(&stream, 0, &val2));
+    CBOR_CHECK_DESERIALIZED(val, val2, EQUAL_INT);
+}
+#endif /* CBOR_NO_CTIME */
+#endif /* CBOR_NO_SEMANTIC_TAGGING */
+
+static void test_bool(void)
+{
+    CBOR_CHECK(bool, bool, stream, false, HEX_LITERAL(0xf4), EQUAL_INT);
+    CBOR_CHECK(bool, bool, stream, true,  HEX_LITERAL(0xf5), EQUAL_INT);
+}
+
+static void test_bool_invalid(void)
+{
+    TEST_ASSERT_EQUAL_INT(0, cbor_serialize_bool(&empty_stream, true));
+    TEST_ASSERT_EQUAL_INT(0, empty_stream.pos);
+
+    bool val_bool = 0;
+    TEST_ASSERT_EQUAL_INT(0, cbor_deserialize_bool(&invalid_stream, 0, &val_bool));
+}
+
+#ifndef CBOR_NO_FLOAT
+static void test_float_half(void)
+{
+    /* check border conditions */
+    CBOR_CHECK(float, float_half, stream, -.0f, HEX_LITERAL(0xf9, 0x80, 0x00), EQUAL_FLOAT);
+    CBOR_CHECK(float, float_half, stream, .0f, HEX_LITERAL(0xf9, 0x00, 0x00), EQUAL_FLOAT);
+    CBOR_CHECK(float, float_half, stream, INFINITY, HEX_LITERAL(0xf9, 0x7c, 0x00), EQUAL_FLOAT);
+    /* TODO: Broken: encode_float_half issue? */
+    /*CBOR_CHECK(float, float_half, stream, NAN, HEX_LITERAL(0xf9, 0x7e, 0x00), EQUAL_FLOAT);*/
+    CBOR_CHECK(float, float_half, stream, -INFINITY, HEX_LITERAL(0xf9, 0xfc, 0x00), EQUAL_FLOAT);
+
+    /* check examples from the CBOR RFC */
+    CBOR_CHECK(float, float_half, stream, -4.f, HEX_LITERAL(0xf9, 0xc4, 0x00), EQUAL_FLOAT);
+    CBOR_CHECK(float, float_half, stream, 1.f, HEX_LITERAL(0xf9, 0x3c, 0x00), EQUAL_FLOAT);
+    CBOR_CHECK(float, float_half, stream, 1.5f, HEX_LITERAL(0xf9, 0x3e, 0x00), EQUAL_FLOAT);
+    CBOR_CHECK(float, float_half, stream, 5.960464477539063e-8,
+               HEX_LITERAL(0xf9, 0x00, 0x01), EQUAL_FLOAT);
+}
+
+static void test_float_half_invalid(void)
+{
+    TEST_ASSERT_EQUAL_INT(0, cbor_serialize_float_half(&empty_stream, 0.f));
+    TEST_ASSERT_EQUAL_INT(0, empty_stream.pos);
+
+    float val_float_half = 0;
+    TEST_ASSERT_EQUAL_INT(0, cbor_deserialize_float_half(&invalid_stream, 0, &val_float_half));
+}
+
+
+static void test_float(void)
+
+{
+    /* check border conditions */
+    CBOR_CHECK(float, float, stream, .0f,
+               HEX_LITERAL(0xfa, 0x00, 0x00, 0x00, 0x00), EQUAL_FLOAT);
+    CBOR_CHECK(float, float, stream, INFINITY,
+               HEX_LITERAL(0xfa, 0x7f, 0x80, 0x00, 0x00), EQUAL_FLOAT);
+    CBOR_CHECK(float, float, stream, NAN,
+               HEX_LITERAL(0xfa, 0x7f, 0xc0, 0x00, 0x00), EQUAL_FLOAT);
+    CBOR_CHECK(float, float, stream, -INFINITY,
+               HEX_LITERAL(0xfa, 0xff, 0x80, 0x00, 0x00), EQUAL_FLOAT);
+
+    /* check examples from the CBOR RFC */
+    CBOR_CHECK(float, float, stream, 100000.f,
+               HEX_LITERAL(0xfa, 0x47, 0xc3, 0x50, 0x00), EQUAL_FLOAT);
+    CBOR_CHECK(float, float, stream, 3.4028234663852886e+38,
+               HEX_LITERAL(0xfa, 0x7f, 0x7f, 0xff, 0xff), EQUAL_FLOAT);
+}
+
+static void test_float_invalid(void)
+{
+    TEST_ASSERT_EQUAL_INT(0, cbor_serialize_float(&empty_stream, 0.f));
+    TEST_ASSERT_EQUAL_INT(0, empty_stream.pos);
+
+    float val_float = 0;
+    TEST_ASSERT_EQUAL_INT(0, cbor_deserialize_float(&invalid_stream, 0, &val_float));
+}
+
+static void test_double(void)
+{
+    /* check border conditions */
+    CBOR_CHECK(double, double, stream, .0f,
+               HEX_LITERAL(0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), EQUAL_FLOAT);
+    CBOR_CHECK(double, double, stream, INFINITY,
+               HEX_LITERAL(0xfb, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), EQUAL_FLOAT);
+    CBOR_CHECK(double, double, stream, NAN,
+               HEX_LITERAL(0xfb, 0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), EQUAL_FLOAT);
+    CBOR_CHECK(double, double, stream, -INFINITY,
+               HEX_LITERAL(0xfb, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), EQUAL_FLOAT);
+
+    /* check examples from the CBOR RFC */
+    CBOR_CHECK(double, double, stream, 1.1,
+               HEX_LITERAL(0xfb, 0x3f, 0xf1, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a), EQUAL_FLOAT);
+    CBOR_CHECK(double, double, stream, -4.1,
+               HEX_LITERAL(0xfb, 0xc0, 0x10, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66), EQUAL_FLOAT);
+#if ARCH_32_BIT
+    CBOR_CHECK(double, double, stream, 1.e+300,
+               HEX_LITERAL(0xfb, 0x7e, 0x37, 0xe4, 0x3c, 0x88, 0x00, 0x75, 0x9c), EQUAL_FLOAT);
+#endif
+}
+
+static void test_double_invalid(void)
+{
+    TEST_ASSERT_EQUAL_INT(0, cbor_serialize_double(&empty_stream, 0));
+    TEST_ASSERT_EQUAL_INT(0, empty_stream.pos);
+
+
+    double val_double = 0;
+    TEST_ASSERT_EQUAL_INT(0, cbor_deserialize_double(&invalid_stream, 0, &val_double));
+}
+#endif /* CBOR_NO_FLOAT */
+
+#ifndef CBOR_NO_PRINT
+/**
+ * Manual test for testing the cbor_stream_decode function
+ */
+void test_stream_decode(void)
+{
+    cbor_clear(&stream);
+
+    cbor_serialize_int(&stream, 1);
+    cbor_serialize_uint64_t(&stream, 2llu);
+    cbor_serialize_int64_t(&stream, 3);
+    cbor_serialize_int64_t(&stream, -5);
+    cbor_serialize_bool(&stream, true);
+#ifndef CBOR_NO_FLOAT
+    cbor_serialize_float_half(&stream, 1.1f);
+    cbor_serialize_float(&stream, 1.5f);
+    cbor_serialize_double(&stream, 2.0);
+#endif /* CBOR_NO_FLOAT */
+    cbor_serialize_byte_string(&stream, "abc");
+    cbor_serialize_unicode_string(&stream, "def");
+
+    cbor_serialize_array(&stream, 2);
+    cbor_serialize_int(&stream, 0);
+    cbor_serialize_int(&stream, 1);
+
+    cbor_serialize_array_indefinite(&stream);
+    cbor_serialize_int(&stream, 10);
+    cbor_serialize_int(&stream, 11);
+    cbor_write_break(&stream);
+
+    cbor_serialize_map(&stream, 2);
+    cbor_serialize_int(&stream, 1);
+    cbor_serialize_byte_string(&stream, "1");
+    cbor_serialize_int(&stream, 2);
+    cbor_serialize_byte_string(&stream, "2");
+
+    cbor_serialize_map_indefinite(&stream);
+    cbor_serialize_int(&stream, 10);
+    cbor_serialize_byte_string(&stream, "10");
+    cbor_serialize_int(&stream, 11);
+    cbor_serialize_byte_string(&stream, "11");
+    cbor_write_break(&stream);
+
+#ifndef CBOR_NO_SEMANTIC_TAGGING
+#ifndef CBOR_NO_CTIME
+    time_t rawtime;
+    time(&rawtime);
+    struct tm *timeinfo = localtime(&rawtime);
+    cbor_serialize_date_time(&stream, timeinfo);
+    cbor_serialize_date_time_epoch(&stream, rawtime);
+#endif /* CBOR_NO_CTIME */
+
+    // decoder should skip the tag and print 'unsupported' here
+    cbor_write_tag(&stream, 2);
+    cbor_serialize_byte_string(&stream, "1");
+#endif /* CBOR_NO_SEMANTIC_TAGGING */
+
+    cbor_stream_decode(&stream);
+}
+#endif /* CBOR_NO_PRINT */
+
+/**
+ * See examples from CBOR RFC (cf. Appendix A. Examples)
+ */
+TestRef tests_cbor_all(void)
+{
+    EMB_UNIT_TESTFIXTURES(fixtures) {
+        new_TestFixture(test_int),
+                        new_TestFixture(test_int_invalid),
+                        new_TestFixture(test_uint64_t),
+                        new_TestFixture(test_uint64_t_invalid),
+                        new_TestFixture(test_int64_t),
+                        new_TestFixture(test_int64_t_invalid),
+                        new_TestFixture(test_byte_string),
+                        new_TestFixture(test_byte_string_invalid),
+                        new_TestFixture(test_unicode_string),
+                        new_TestFixture(test_unicode_string_invalid),
+                        new_TestFixture(test_array),
+                        new_TestFixture(test_array_indefinite),
+                        new_TestFixture(test_array_invalid),
+                        new_TestFixture(test_map),
+                        new_TestFixture(test_map_indefinite),
+                        new_TestFixture(test_map_invalid),
+#ifndef CBOR_NO_SEMANTIC_TAGGING
+                        new_TestFixture(test_semantic_tagging),
+#ifndef CBOR_NO_CTIME
+                        new_TestFixture(test_date_time),
+                        new_TestFixture(test_date_time_epoch),
+#endif /* CBOR_NO_CTIME */
+#endif /* CBOR_NO_SEMANTIC_TAGGING */
+                        new_TestFixture(test_bool),
+                        new_TestFixture(test_bool_invalid),
+#ifndef CBOR_NO_FLOAT
+                        new_TestFixture(test_float_half),
+                        new_TestFixture(test_float_half_invalid),
+                        new_TestFixture(test_float),
+                        new_TestFixture(test_float_invalid),
+                        new_TestFixture(test_double),
+                        new_TestFixture(test_double_invalid),
+#endif /* CBOR_NO_FLOAT */
+    };
+
+    EMB_UNIT_TESTCALLER(CborTest, setUp, tearDown, fixtures);
+    return (TestRef)&CborTest;
+}
+
+void tests_cbor(void)
+{
+#ifndef CBOR_NO_PRINT
+    test_stream_decode();
+#endif /* CBOR_NO_PRINT */
+
+    TESTS_RUN(tests_cbor_all());
+}