• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 
3 /*
4  * Copyright (c) 2018, SICS, RISE AB
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the Institute nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  */
32 
33 /**
34  * @file oscore_cbor.c
35  * @brief An implementation of the Concise Binary Object Representation (RFC).
36  *
37  * \author
38  *      Martin Gunnarsson  <martin.gunnarsson@ri.se>
39  * extended for libcoap by Peter van der Stok
40  *                         <consultancy@vanderstok.org>
41  * on request of Fairhair alliance.
42  * adapted for libcoap integration
43  *      Jon Shallow <supjps-libcoap@jpshallow.com>
44  *
45  */
46 
47 #include "coap3/coap_internal.h"
48 #include <string.h>
49 
50 static inline void
util_write_byte(uint8_t ** buffer,size_t * buf_size,uint8_t value)51 util_write_byte(uint8_t **buffer, size_t *buf_size, uint8_t value) {
52   assert(*buf_size >= 1);
53   (*buf_size)--;
54   **buffer = value;
55   (*buffer)++;
56 }
57 
58 size_t
oscore_cbor_put_nil(uint8_t ** buffer,size_t * buf_size)59 oscore_cbor_put_nil(uint8_t **buffer, size_t *buf_size) {
60   util_write_byte(buffer, buf_size, 0xF6);
61   return 1;
62 }
63 
64 size_t
oscore_cbor_put_true(uint8_t ** buffer,size_t * buf_size)65 oscore_cbor_put_true(uint8_t **buffer, size_t *buf_size) {
66   util_write_byte(buffer, buf_size, 0xF5);
67   return 1;
68 }
69 
70 size_t
oscore_cbor_put_false(uint8_t ** buffer,size_t * buf_size)71 oscore_cbor_put_false(uint8_t **buffer, size_t *buf_size) {
72   util_write_byte(buffer, buf_size, 0xF4);
73   return 1;
74 }
75 
76 size_t
oscore_cbor_put_text(uint8_t ** buffer,size_t * buf_size,const char * text,size_t text_len)77 oscore_cbor_put_text(uint8_t **buffer,
78                      size_t *buf_size,
79                      const char *text,
80                      size_t text_len) {
81   uint8_t *pt = *buffer;
82   size_t nb = oscore_cbor_put_unsigned(buffer, buf_size, text_len);
83   assert(*buf_size >= text_len);
84   (*buf_size) -= text_len;
85   *pt = (*pt | 0x60);
86   memcpy(*buffer, text, text_len);
87   (*buffer) += text_len;
88   return nb + text_len;
89 }
90 
91 size_t
oscore_cbor_put_array(uint8_t ** buffer,size_t * buf_size,size_t elements)92 oscore_cbor_put_array(uint8_t **buffer, size_t *buf_size, size_t elements) {
93   uint8_t *pt = *buffer;
94   size_t nb = oscore_cbor_put_unsigned(buffer, buf_size, elements);
95   *pt = (*pt | 0x80);
96   return nb;
97 }
98 
99 size_t
oscore_cbor_put_bytes(uint8_t ** buffer,size_t * buf_size,const uint8_t * bytes,size_t bytes_len)100 oscore_cbor_put_bytes(uint8_t **buffer,
101                       size_t *buf_size,
102                       const uint8_t *bytes,
103                       size_t bytes_len) {
104   uint8_t *pt = *buffer;
105   size_t nb = oscore_cbor_put_unsigned(buffer, buf_size, bytes_len);
106   assert(*buf_size >= bytes_len);
107   (*buf_size) -= bytes_len;
108   *pt = (*pt | 0x40);
109   memcpy(*buffer, bytes, bytes_len);
110   (*buffer) += bytes_len;
111   return nb + bytes_len;
112 }
113 
114 size_t
oscore_cbor_put_map(uint8_t ** buffer,size_t * buf_size,size_t elements)115 oscore_cbor_put_map(uint8_t **buffer, size_t *buf_size, size_t elements) {
116   uint8_t *pt = *buffer;
117   size_t nb = oscore_cbor_put_unsigned(buffer, buf_size, elements);
118   *pt = (*pt | 0xa0);
119   return nb;
120 }
121 
122 size_t
oscore_cbor_put_number(uint8_t ** buffer,size_t * buf_size,int64_t value)123 oscore_cbor_put_number(uint8_t **buffer, size_t *buf_size, int64_t value) {
124   if (value < 0)
125     return oscore_cbor_put_negative(buffer, buf_size, -value);
126   else
127     return oscore_cbor_put_unsigned(buffer, buf_size, value);
128 }
129 
130 size_t
oscore_cbor_put_simple_value(uint8_t ** buffer,size_t * buf_size,uint8_t value)131 oscore_cbor_put_simple_value(uint8_t **buffer,
132                              size_t *buf_size,
133                              uint8_t value) {
134   uint8_t *pt = *buffer;
135   size_t nb = oscore_cbor_put_unsigned(buffer, buf_size, value);
136   *pt = (*pt | 0xe0);
137   return nb;
138 }
139 
140 size_t
oscore_cbor_put_tag(uint8_t ** buffer,size_t * buf_size,uint64_t value)141 oscore_cbor_put_tag(uint8_t **buffer, size_t *buf_size, uint64_t value) {
142   uint8_t *pt = *buffer;
143   size_t nb = oscore_cbor_put_unsigned(buffer, buf_size, value);
144   *pt = (*pt | 0xc0);
145   return nb;
146 }
147 
148 size_t
oscore_cbor_put_negative(uint8_t ** buffer,size_t * buf_size,int64_t value)149 oscore_cbor_put_negative(uint8_t **buffer, size_t *buf_size, int64_t value) {
150   value--;
151   uint8_t *pt = *buffer;
152   size_t nb = oscore_cbor_put_unsigned(buffer, buf_size, value);
153   *pt = (*pt | 0x20);
154   return nb;
155 }
156 
157 static void
put_b_f(uint8_t ** buffer,uint64_t value,uint8_t nr)158 put_b_f(uint8_t **buffer, uint64_t value, uint8_t nr) {
159   uint8_t *pt = *buffer - 1;
160   uint64_t vv = value;
161   for (int q = nr; q > -1; q--) {
162     (*pt--) = (uint8_t)(vv & 0xff);
163     vv = (vv >> 8);
164   }
165 }
166 
167 size_t
oscore_cbor_put_unsigned(uint8_t ** buffer,size_t * buf_size,uint64_t value)168 oscore_cbor_put_unsigned(uint8_t **buffer, size_t *buf_size, uint64_t value) {
169   if (value < 0x18) { /* small value half a byte */
170     assert(*buf_size >= 1);
171     (*buf_size)--;
172     (**buffer) = (uint8_t)value;
173     (*buffer)++;
174     return 1;
175   } else if ((value > 0x17) && (value < 0x100)) {
176     /* one byte uint8_t  */
177     assert(*buf_size >= 2);
178     (*buf_size) -= 2;
179     (**buffer) = (0x18);
180     *buffer = (*buffer) + 2;
181     put_b_f(buffer, value, 0);
182     return 2;
183   } else if ((value > 0xff) && (value < 0x10000)) {
184     /* 2 bytes uint16_t     */
185     assert(*buf_size >= 3);
186     (*buf_size) -= 3;
187     (**buffer) = (0x19);
188     *buffer = (*buffer) + 3;
189     put_b_f(buffer, value, 1);
190     return 3;
191   } else if ((value > 0xffff) && (value < 0x100000000)) {
192     /* 4 bytes uint32_t   */
193     assert(*buf_size >= 5);
194     (*buf_size) -= 5;
195     (**buffer) = (0x1a);
196     *buffer = (*buffer) + 5;
197     put_b_f(buffer, value, 3);
198     return 5;
199   } else { /*if(value > 0xffffffff)*/
200     /* 8 bytes uint64_t  */
201     assert(*buf_size >= 9);
202     (*buf_size) -= 9;
203     (**buffer) = (0x1b);
204     *buffer = (*buffer) + 9;
205     put_b_f(buffer, value, 7);
206     return 9;
207   }
208 }
209 
210 static inline uint8_t
get_byte(const uint8_t ** buffer,size_t * buf_len)211 get_byte(const uint8_t **buffer, size_t *buf_len) {
212 #if NDEBUG
213   (void)buf_len;
214 #endif /* NDEBUG */
215   assert((*buf_len) > 0);
216   return (*buffer)[0];
217 }
218 
219 static inline uint8_t
get_byte_inc(const uint8_t ** buffer,size_t * buf_len)220 get_byte_inc(const uint8_t **buffer, size_t *buf_len) {
221   assert((*buf_len) > 0);
222   (*buf_len)--;
223   return ((*buffer)++)[0];
224 }
225 
226 uint8_t
oscore_cbor_get_next_element(const uint8_t ** buffer,size_t * buf_len)227 oscore_cbor_get_next_element(const uint8_t **buffer, size_t *buf_len) {
228   uint8_t element = get_byte(buffer, buf_len);
229   return element >> 5;
230 }
231 
232 /* oscore_cbor_get_element_size returns
233  *   - size of byte strings of character strings
234  *   - size of array
235  *   - size of map
236  *   - value of unsigned integer
237  */
238 
239 size_t
oscore_cbor_get_element_size(const uint8_t ** buffer,size_t * buf_len)240 oscore_cbor_get_element_size(const uint8_t **buffer, size_t *buf_len) {
241   uint8_t control = get_byte(buffer, buf_len) & 0x1f;
242   size_t size = get_byte_inc(buffer, buf_len);
243 
244   if (control < 0x18) {
245     size = (uint64_t)control;
246   } else {
247     control = control & 0x3;
248     int num = 1 << control;
249     size = 0;
250     size_t getal;
251     for (int i = 0; i < num; i++) {
252       getal = get_byte_inc(buffer, buf_len);
253       size = (size << 8) + getal;
254     }
255   }
256   return size;
257 }
258 
259 uint8_t
oscore_cbor_elem_contained(const uint8_t * data,size_t * buf_len,uint8_t * end)260 oscore_cbor_elem_contained(const uint8_t *data, size_t *buf_len, uint8_t *end) {
261   const uint8_t *buf = data;
262   const uint8_t *last = data + oscore_cbor_get_element_size(&buf, buf_len);
263   if (last > end) {
264     coap_log_err("oscore_cbor_elem_contained returns 1 \n");
265     return 1;
266   } else
267     return 0;
268 }
269 
270 int64_t
oscore_cbor_get_negative_integer(const uint8_t ** buffer,size_t * buf_len)271 oscore_cbor_get_negative_integer(const uint8_t **buffer, size_t *buf_len) {
272   return -(int64_t)(oscore_cbor_get_element_size(buffer, buf_len) + 1);
273 }
274 
275 uint64_t
oscore_cbor_get_unsigned_integer(const uint8_t ** buffer,size_t * buf_len)276 oscore_cbor_get_unsigned_integer(const uint8_t **buffer, size_t *buf_len) {
277   return oscore_cbor_get_element_size(buffer, buf_len);
278 }
279 
280 /*
281  * oscore_cbor_get_number
282  *
283  * gets a negative or positive number from data
284  * OK: return 0 ; NOK: return 1
285  */
286 uint8_t
oscore_cbor_get_number(const uint8_t ** data,size_t * buf_len,int64_t * value)287 oscore_cbor_get_number(const uint8_t **data, size_t *buf_len, int64_t *value) {
288   uint8_t elem = oscore_cbor_get_next_element(data, buf_len);
289   if (elem == CBOR_UNSIGNED_INTEGER) {
290     *value = oscore_cbor_get_unsigned_integer(data, buf_len);
291     return 0;
292   } else if (elem == CBOR_NEGATIVE_INTEGER) {
293     *value = oscore_cbor_get_negative_integer(data, buf_len);
294     return 0;
295   } else
296     return 1;
297 }
298 
299 /*
300  * oscore_cbor_get_simple_value
301  *
302  * gets a simple value from data
303  * OK: return 0 ; NOK: return 1
304  */
305 uint8_t
oscore_cbor_get_simple_value(const uint8_t ** data,size_t * buf_len,uint8_t * value)306 oscore_cbor_get_simple_value(const uint8_t **data, size_t *buf_len, uint8_t *value) {
307   uint8_t elem = oscore_cbor_get_next_element(data, buf_len);
308   if (elem == CBOR_SIMPLE_VALUE) {
309     *value = get_byte_inc(data, buf_len) & 0x1f;
310     return 0;
311   } else
312     return 1;
313 }
314 
315 void
oscore_cbor_get_string(const uint8_t ** buffer,size_t * buf_len,char * str,size_t size)316 oscore_cbor_get_string(const uint8_t **buffer, size_t *buf_len, char *str, size_t size) {
317   (void)buf_len;
318   for (size_t i = 0; i < size; i++) {
319     *str++ = (char)get_byte_inc(buffer, buf_len);
320   }
321 }
322 
323 void
oscore_cbor_get_array(const uint8_t ** buffer,size_t * buf_len,uint8_t * arr,size_t size)324 oscore_cbor_get_array(const uint8_t **buffer, size_t *buf_len, uint8_t *arr, size_t size) {
325   (void)buf_len;
326   for (size_t i = 0; i < size; i++) {
327     *arr++ = get_byte_inc(buffer, buf_len);
328   }
329 }
330 
331 /* oscore_cbor_get_string_array
332  * fills the the size and the array from the cbor element
333  */
334 uint8_t
oscore_cbor_get_string_array(const uint8_t ** data,size_t * buf_len,uint8_t ** result,size_t * len)335 oscore_cbor_get_string_array(const uint8_t **data, size_t *buf_len,
336                              uint8_t **result,
337                              size_t *len) {
338 
339   uint8_t elem = oscore_cbor_get_next_element(data, buf_len);
340   *len = oscore_cbor_get_element_size(data, buf_len);
341   *result = NULL;
342   void *rs = coap_malloc_type(COAP_STRING, *len);
343   *result = (uint8_t *)rs;
344   if (elem == CBOR_TEXT_STRING) {
345     oscore_cbor_get_string(data, buf_len, (char *)*result, *len);
346     return 0;
347   } else if (elem == CBOR_BYTE_STRING) {
348     oscore_cbor_get_array(data, buf_len, *result, *len);
349     return 0; /* all is well */
350   } else {
351     free(*result);
352     *result = NULL;
353     return 1; /* failure */
354   }
355 }
356 
357 /* oscore_cbor_skip value
358  *  returns number of CBOR bytes
359  */
360 static size_t
oscore_cbor_skip_value(const uint8_t ** data,size_t * buf_len)361 oscore_cbor_skip_value(const uint8_t **data, size_t *buf_len) {
362   uint8_t elem = oscore_cbor_get_next_element(data, buf_len);
363   uint8_t control = get_byte(data, buf_len) & 0x1f;
364   size_t nb = 0;   /* number of elements in array or map */
365   size_t num = 0;  /* number of bytes of length or number */
366   size_t size = 0; /* size of value to be skipped */
367   if (control < 0x18) {
368     num = 1;
369   } else {
370     control = control & 0x3;
371     num = 1 + (1 << control);
372   }
373   switch (elem) {
374   case CBOR_UNSIGNED_INTEGER:
375   case CBOR_NEGATIVE_INTEGER:
376     assert((*buf_len) >= num);
377     *buf_len -= num;
378     *data = *data + num;
379     size = num;
380     break;
381   case CBOR_BYTE_STRING:
382   case CBOR_TEXT_STRING:
383     size = num;
384     size += oscore_cbor_get_element_size(data, buf_len);
385     assert((*buf_len) >= (size - num));
386     *buf_len -= (size - num);
387     (*data) = (*data) + size - num;
388     break;
389   case CBOR_ARRAY:
390     nb = oscore_cbor_get_element_size(data, buf_len);
391     size = num;
392     for (uint16_t qq = 0; qq < nb; qq++)
393       size += oscore_cbor_skip_value(data, buf_len);
394     break;
395   case CBOR_MAP:
396     nb = oscore_cbor_get_element_size(data, buf_len);
397     size = num;
398     for (uint16_t qq = 0; qq < nb; qq++) {
399       size += oscore_cbor_skip_value(data, buf_len);
400       size += oscore_cbor_skip_value(data, buf_len);
401     }
402     break;
403   case CBOR_TAG:
404     assert((*buf_len) >= 1);
405     *buf_len -= 1;
406     (*data)++;
407     size = 1;
408     break;
409   default:
410     return 0;
411     break;
412   } /* switch */
413   return size;
414 }
415 
416 /* oscore_cbor_strip value
417  * strips the value of the cbor element into result
418  *  and returns size
419  */
420 uint8_t
oscore_cbor_strip_value(const uint8_t ** data,size_t * buf_len,uint8_t ** result,size_t * len)421 oscore_cbor_strip_value(const uint8_t **data, size_t *buf_len, uint8_t **result, size_t *len) {
422   const uint8_t *st_data = *data;
423   size_t size = oscore_cbor_skip_value(data, buf_len);
424   *result = coap_malloc_type(COAP_STRING, size);
425   for (uint16_t qq = 0; qq < size; qq++)
426     (*result)[qq] = st_data[qq];
427   *len = size;
428   return 0;
429 }
430