1 /*
2  * This file has been copied from the cddl-gen submodule.
3  * Commit 9f77837f9950da1633d22abf6181a830521a6688
4  */
5 
6 /*
7  * Copyright (c) 2020 Nordic Semiconductor ASA
8  *
9  * SPDX-License-Identifier: Apache-2.0
10  */
11 
12 #include <stdint.h>
13 #include <stdbool.h>
14 #include <stddef.h>
15 #include <string.h>
16 #include "cbor_encode.h"
17 #include "cbor_common.h"
18 
19 _Static_assert((sizeof(size_t) == sizeof(void *)),
20 	"This code needs size_t to be the same length as pointers.");
21 
get_additional(uint32_t len,uint8_t value0)22 uint8_t get_additional(uint32_t len, uint8_t value0)
23 {
24 	switch(len) {
25 		case 0: return value0;
26 		case 1: return 24;
27 		case 2: return 25;
28 		case 3: return 25;
29 		case 4: return 26;
30 		case 5: return 26;
31 		case 6: return 26;
32 		case 7: return 26;
33 		case 8: return 27;
34 	}
35 
36 	cbor_assert(false, NULL);
37 	return 0;
38 }
39 
encode_header_byte(cbor_state_t * state,cbor_major_type_t major_type,uint8_t additional)40 static bool encode_header_byte(cbor_state_t *state,
41 	cbor_major_type_t major_type, uint8_t additional)
42 {
43 	if ((state->payload + 1) > state->payload_end) {
44 		FAIL();
45 	}
46 
47 	cbor_assert(additional < 32, NULL);
48 
49 	*(state->payload_mut++) = (major_type << 5) | (additional & 0x1F);
50 	return true;
51 }
52 
53 /** Encode a single value.
54  */
value_encode_len(cbor_state_t * state,cbor_major_type_t major_type,const void * const input,uint32_t result_len)55 static bool value_encode_len(cbor_state_t *state, cbor_major_type_t major_type,
56 		const void *const input, uint32_t result_len)
57 {
58 	uint8_t *u8_result  = (uint8_t *)input;
59 
60 	if ((state->payload + 1 + result_len) > state->payload_end) {
61 		FAIL();
62 	}
63 
64 	if (!encode_header_byte(state, major_type,
65 				get_additional(result_len, u8_result[0]))) {
66 		FAIL();
67 	}
68 	state->payload_mut--;
69 	cbor_trace();
70 	state->payload_mut++;
71 
72 #ifdef CONFIG_BIG_ENDIAN
73 	memcpy(state->payload_mut, u8_result, result_len);
74 	state->payload_mut += result_len;
75 #else
76 	for (; result_len > 0; result_len--) {
77 		*(state->payload_mut++) = u8_result[result_len - 1];
78 	}
79 #endif
80 
81 	state->elem_count++;
82 	return true;
83 }
84 
85 
get_result_len(const void * const input,uint32_t max_result_len)86 static uint32_t get_result_len(const void *const input, uint32_t max_result_len)
87 {
88 	uint8_t *u8_result  = (uint8_t *)input;
89 	size_t i;
90 
91 	for (i = 0; i < max_result_len; i++) {
92 #ifdef CONFIG_BIG_ENDIAN
93 		size_t idx = i;
94 #else
95 		size_t idx = max_result_len - 1 - i;
96 #endif
97 		if (u8_result[idx] != 0) {
98 			break;
99 		}
100 	}
101 	max_result_len -= i;
102 
103 	/* According to specification result length can be encoded on 1, 2, 4
104 	 * or 8 bytes.
105 	 */
106 	cbor_assert(max_result_len <= 8, "Up to 8 bytes can be used to encode length.\n");
107 	size_t encode_byte_cnt = 1;
108 
109 	for (size_t i = 0; i <= 3; i++) {
110 		if (max_result_len <= encode_byte_cnt) {
111 			max_result_len = encode_byte_cnt;
112 			break;
113 		}
114 
115 		encode_byte_cnt *= 2;
116 	}
117 
118 	if ((max_result_len == 1) && (u8_result[0] <= VALUE_IN_HEADER)) {
119 		max_result_len = 0;
120 	}
121 
122 	return max_result_len;
123 }
124 
125 
value_encode(cbor_state_t * state,cbor_major_type_t major_type,const void * const input,uint32_t max_result_len)126 static bool value_encode(cbor_state_t *state, cbor_major_type_t major_type,
127 		const void *const input, uint32_t max_result_len)
128 {
129 	cbor_assert(max_result_len != 0, "0-length result not supported.\n");
130 	return value_encode_len(state, major_type, input,
131 				get_result_len(input, max_result_len));
132 }
133 
134 
intx32_put(cbor_state_t * state,int32_t input)135 bool intx32_put(cbor_state_t *state, int32_t input)
136 {
137 	cbor_major_type_t major_type;
138 
139 	if (input < 0) {
140 		major_type = CBOR_MAJOR_TYPE_NINT;
141 		/* Convert from CBOR's representation. */
142 		input = -1 - input;
143 	} else {
144 		major_type = CBOR_MAJOR_TYPE_PINT;
145 		input = input;
146 	}
147 
148 	if (!value_encode(state, major_type, &input, 4)) {
149 		FAIL();
150 	}
151 
152 	return true;
153 }
154 
intx32_encode(cbor_state_t * state,const int32_t * input)155 bool intx32_encode(cbor_state_t *state, const int32_t *input)
156 {
157 	return intx32_put(state, *input);
158 }
159 
160 
uint32_encode(cbor_state_t * state,const uint32_t * input,cbor_major_type_t major_type)161 static bool uint32_encode(cbor_state_t *state, const uint32_t *input,
162 		cbor_major_type_t major_type)
163 {
164 	if (!value_encode(state, major_type, input, 4)) {
165 		FAIL();
166 	}
167 	return true;
168 }
169 
170 
uintx32_encode(cbor_state_t * state,const uint32_t * input)171 bool uintx32_encode(cbor_state_t *state, const uint32_t *input)
172 {
173 	if (!uint32_encode(state, input, CBOR_MAJOR_TYPE_PINT)) {
174 		FAIL();
175 	}
176 	return true;
177 }
178 
179 
uintx32_put(cbor_state_t * state,uint32_t input)180 bool uintx32_put(cbor_state_t *state, uint32_t input)
181 {
182 	if (!uint32_encode(state, &input, CBOR_MAJOR_TYPE_PINT)) {
183 		FAIL();
184 	}
185 	return true;
186 }
187 
188 
strx_start_encode(cbor_state_t * state,const cbor_string_type_t * input,cbor_major_type_t major_type)189 static bool strx_start_encode(cbor_state_t *state,
190 		const cbor_string_type_t *input, cbor_major_type_t major_type)
191 {
192 	if (input->value && ((get_result_len(&input->len, sizeof(input->len))
193 			+ 1 + input->len + (size_t)state->payload)
194 			> (size_t)state->payload_end)) {
195 		FAIL();
196 	}
197 	if (!uint32_encode(state, &input->len, major_type)) {
198 		FAIL();
199 	}
200 
201 	return true;
202 }
203 
204 
primx_encode(cbor_state_t * state,uint32_t input)205 static bool primx_encode(cbor_state_t *state, uint32_t input)
206 {
207 	if (!uint32_encode(state, &input, CBOR_MAJOR_TYPE_PRIM)) {
208 		FAIL();
209 	}
210 	return true;
211 }
212 
213 
remaining_str_len(cbor_state_t * state)214 static uint32_t remaining_str_len(cbor_state_t *state)
215 {
216 	uint32_t max_len = (size_t)state->payload_end - (size_t)state->payload;
217 	uint32_t result_len = get_result_len(&max_len, sizeof(uint32_t));
218 	return max_len - result_len - 1;
219 }
220 
221 
bstrx_cbor_start_encode(cbor_state_t * state,const cbor_string_type_t * result)222 bool bstrx_cbor_start_encode(cbor_state_t *state, const cbor_string_type_t *result)
223 {
224 	if (!new_backup(state, 0)) {
225 		FAIL();
226 	}
227 
228 	uint32_t max_len = remaining_str_len(state);
229 
230 	/* Encode a dummy header */
231 	if (!uint32_encode(state, &max_len,
232 			CBOR_MAJOR_TYPE_BSTR)) {
233 		FAIL();
234 	}
235 	return true;
236 }
237 
238 
bstrx_cbor_end_encode(cbor_state_t * state)239 bool bstrx_cbor_end_encode(cbor_state_t *state)
240 {
241 	const uint8_t *payload = state->payload;
242 
243 	if (!restore_backup(state, FLAG_RESTORE | FLAG_DISCARD, 0xFFFFFFFF)) {
244 		FAIL();
245 	}
246 	cbor_string_type_t value;
247 
248 	value.value = state->payload_end - remaining_str_len(state);
249 	value.len = (size_t)payload - (size_t)value.value;
250 
251 	/* Reencode header of list now that we know the number of elements. */
252 	if (!bstrx_encode(state, &value)) {
253 		FAIL();
254 	}
255 	return true;
256 }
257 
258 
strx_encode(cbor_state_t * state,const cbor_string_type_t * input,cbor_major_type_t major_type)259 static bool strx_encode(cbor_state_t *state,
260 		const cbor_string_type_t *input, cbor_major_type_t major_type)
261 {
262 	if (!strx_start_encode(state, input, major_type)) {
263 		FAIL();
264 	}
265 	if (input->len > (state->payload_end - state->payload)) {
266 		FAIL();
267 	}
268 	if (state->payload_mut != input->value) {
269 		memmove(state->payload_mut, input->value, input->len);
270 	}
271 	state->payload += input->len;
272 	return true;
273 }
274 
275 
bstrx_encode(cbor_state_t * state,const cbor_string_type_t * input)276 bool bstrx_encode(cbor_state_t *state, const cbor_string_type_t *input)
277 {
278 	return strx_encode(state, input, CBOR_MAJOR_TYPE_BSTR);
279 }
280 
281 
tstrx_encode(cbor_state_t * state,const cbor_string_type_t * input)282 bool tstrx_encode(cbor_state_t *state, const cbor_string_type_t *input)
283 {
284 	return strx_encode(state, input, CBOR_MAJOR_TYPE_TSTR);
285 }
286 
287 
list_map_start_encode(cbor_state_t * state,uint32_t max_num,cbor_major_type_t major_type)288 static bool list_map_start_encode(cbor_state_t *state, uint32_t max_num,
289 		cbor_major_type_t major_type)
290 {
291 #ifdef CDDL_CBOR_CANONICAL
292 	if (!new_backup(state, 0)) {
293 		FAIL();
294 	}
295 
296 	/* Encode dummy header with max number of elements. */
297 	if (!uint32_encode(state, &max_num, major_type)) {
298 		FAIL();
299 	}
300 	state->elem_count--; /* Because of dummy header. */
301 #else
302 	if (!encode_header_byte(state, major_type, 31)) {
303 		FAIL();
304 	}
305 #endif
306 	return true;
307 }
308 
309 
list_start_encode(cbor_state_t * state,uint32_t max_num)310 bool list_start_encode(cbor_state_t *state, uint32_t max_num)
311 {
312 	return list_map_start_encode(state, max_num, CBOR_MAJOR_TYPE_LIST);
313 }
314 
315 
map_start_encode(cbor_state_t * state,uint32_t max_num)316 bool map_start_encode(cbor_state_t *state, uint32_t max_num)
317 {
318 	return list_map_start_encode(state, max_num, CBOR_MAJOR_TYPE_MAP);
319 }
320 
321 
list_map_end_encode(cbor_state_t * state,uint32_t max_num,cbor_major_type_t major_type)322 bool list_map_end_encode(cbor_state_t *state, uint32_t max_num,
323 			cbor_major_type_t major_type)
324 {
325 #ifdef CDDL_CBOR_CANONICAL
326 	uint32_t list_count = ((major_type == CBOR_MAJOR_TYPE_LIST) ?
327 					state->elem_count
328 					: (state->elem_count / 2));
329 
330 	const uint8_t *payload = state->payload;
331 	uint32_t max_header_len = get_result_len(&max_num, 4);
332 	uint32_t header_len = get_result_len(&list_count, 4);
333 
334 	if (!restore_backup(state, FLAG_RESTORE | FLAG_DISCARD, 0xFFFFFFFF)) {
335 		FAIL();
336 	}
337 
338 	cbor_print("list_count: %d\r\n", list_count);
339 
340 	/* Reencode header of list now that we know the number of elements. */
341 	if (!(uint32_encode(state, &list_count, major_type))) {
342 		FAIL();
343 	}
344 
345 	if (max_header_len != header_len) {
346 		const uint8_t *start = state->payload + max_header_len - header_len;
347 		uint32_t body_size = payload - start;
348 		memmove(state->payload_mut,
349 			state->payload + max_header_len - header_len,
350 			body_size);
351 		/* Reset payload pointer to end of list */
352 		state->payload += body_size;
353 	} else {
354 		/* Reset payload pointer to end of list */
355 		state->payload = payload;
356 	}
357 #else
358 	if (!encode_header_byte(state, CBOR_MAJOR_TYPE_PRIM, 31)) {
359 		FAIL();
360 	}
361 #endif
362 	return true;
363 }
364 
365 
list_end_encode(cbor_state_t * state,uint32_t max_num)366 bool list_end_encode(cbor_state_t *state, uint32_t max_num)
367 {
368 	return list_map_end_encode(state, max_num, CBOR_MAJOR_TYPE_LIST);
369 }
370 
371 
map_end_encode(cbor_state_t * state,uint32_t max_num)372 bool map_end_encode(cbor_state_t *state, uint32_t max_num)
373 {
374 	return list_map_end_encode(state, max_num, CBOR_MAJOR_TYPE_MAP);
375 }
376 
377 
nilx_put(cbor_state_t * state,const void * input)378 bool nilx_put(cbor_state_t *state, const void *input)
379 {
380 	(void)input;
381 	return primx_encode(state, 22);
382 }
383 
384 
boolx_encode(cbor_state_t * state,const bool * input)385 bool boolx_encode(cbor_state_t *state, const bool *input)
386 {
387 	if (!primx_encode(state, *input + BOOL_TO_PRIM)) {
388 		FAIL();
389 	}
390 	return true;
391 }
392 
393 
boolx_put(cbor_state_t * state,bool input)394 bool boolx_put(cbor_state_t *state, bool input)
395 {
396 	if (!primx_encode(state, input + BOOL_TO_PRIM)) {
397 		FAIL();
398 	}
399 	return true;
400 }
401 
402 
double_encode(cbor_state_t * state,double * input)403 bool double_encode(cbor_state_t *state, double *input)
404 {
405 	if (!value_encode(state, CBOR_MAJOR_TYPE_PRIM, input,
406 			sizeof(*input))) {
407 		FAIL();
408 	}
409 
410 	return true;
411 }
412 
413 
double_put(cbor_state_t * state,double input)414 bool double_put(cbor_state_t *state, double input)
415 {
416 	return double_encode(state, &input);
417 }
418 
419 
any_encode(cbor_state_t * state,void * input)420 bool any_encode(cbor_state_t *state, void *input)
421 {
422 	return nilx_put(state, input);
423 }
424 
425 
tag_encode(cbor_state_t * state,uint32_t tag)426 bool tag_encode(cbor_state_t *state, uint32_t tag)
427 {
428 	if (!value_encode(state, CBOR_MAJOR_TYPE_TAG, &tag, sizeof(tag))) {
429 		FAIL();
430 	}
431 	state->elem_count--;
432 
433 	return true;
434 }
435 
436 
multi_encode(uint32_t min_encode,uint32_t max_encode,const uint32_t * num_encode,cbor_encoder_t encoder,cbor_state_t * state,const void * input,uint32_t result_len)437 bool multi_encode(uint32_t min_encode,
438 		uint32_t max_encode,
439 		const uint32_t *num_encode,
440 		cbor_encoder_t encoder,
441 		cbor_state_t *state,
442 		const void *input,
443 		uint32_t result_len)
444 {
445 	if (!PTR_VALUE_IN_RANGE(uint32_t, num_encode, NULL, &max_encode)) {
446 		FAIL();
447 	}
448 	for (uint32_t i = 0; i < *num_encode; i++) {
449 		if (!encoder(state, (const uint8_t *)input + i*result_len)) {
450 			FAIL();
451 		}
452 	}
453 	cbor_print("Found %zu elements.\n", *num_encode);
454 	return true;
455 }
456 
457 
present_encode(const uint32_t * present,cbor_encoder_t encoder,cbor_state_t * state,const void * input)458 bool present_encode(const uint32_t *present,
459 		cbor_encoder_t encoder,
460 		cbor_state_t *state,
461 		const void *input)
462 {
463 	uint32_t num_encode = *present;
464 	bool retval = multi_encode(0, 1, &num_encode, encoder, state, input, 0);
465 	return retval;
466 }
467