1 /*
2    Copyright (c) 2021 Fraunhofer AISEC. See the COPYRIGHT
3    file at the top-level directory of this distribution.
4 
5    Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6    http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7    <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8    option. This file may not be copied, modified, or distributed
9    except according to those terms.
10 */
11 
12 #include <stdint.h>
13 #include <stdio.h>
14 #include <string.h>
15 
16 #include "oscore.h"
17 
18 #include "oscore/oscore_coap.h"
19 #include "oscore/option.h"
20 
21 #include "common/oscore_edhoc_error.h"
22 #include "common/memcpy_s.h"
23 #include "common/print_util.h"
24 #include "common/unit_test.h"
25 
26 #define OSCORE_OBSERVE_REGISTRATION_VALUE 0
27 #define OSCORE_OBSERVE_CANCELLATION_VALUE 1
28 
opt_extra_bytes(uint16_t delta_or_len)29 uint8_t opt_extra_bytes(uint16_t delta_or_len)
30 {
31 	if (delta_or_len < 13) {
32 		return 0;
33 	}
34 
35 	if (delta_or_len < 269) {
36 		return 1;
37 	}
38 
39 	return 2;
40 }
41 
options_serialize(struct o_coap_option * options,uint8_t options_cnt,struct byte_array * out)42 enum err options_serialize(struct o_coap_option *options, uint8_t options_cnt,
43 			   struct byte_array *out)
44 {
45 	uint8_t delta_extra_byte = 0;
46 	uint8_t len_extra_byte = 0;
47 	uint8_t *temp_ptr = out->ptr;
48 	uint8_t *header_byte;
49 
50 	/* Reset length */
51 	uint32_t out_capacity = out->len;
52 	out->len = 0;
53 
54 	for (uint8_t i = 0; i < options_cnt; i++) {
55 		delta_extra_byte = opt_extra_bytes(options[i].delta);
56 		len_extra_byte = opt_extra_bytes(options[i].len);
57 
58 		header_byte = temp_ptr;
59 		*header_byte = 0;
60 
61 		switch (delta_extra_byte) {
62 		case 0:
63 			*(header_byte) = (uint8_t)(options[i].delta << 4);
64 			break;
65 		case 1:
66 			*(header_byte) = (uint8_t)(13 << 4);
67 			*(temp_ptr + 1) = (uint8_t)(options[i].delta - 13);
68 			break;
69 		case 2:
70 			*(header_byte) = (uint8_t)(14 << 4);
71 			uint16_t temp_delta =
72 				(uint16_t)(options[i].delta - 269);
73 			*(temp_ptr + 1) = (uint8_t)((temp_delta & 0xFF00) >> 8);
74 			*(temp_ptr + 2) = (uint8_t)((temp_delta & 0x00FF) >> 0);
75 			break;
76 		}
77 
78 		switch (len_extra_byte) {
79 		case 0:
80 			*(header_byte) |= (uint8_t)(options[i].len);
81 			break;
82 		case 1:
83 			*(header_byte) |= 13;
84 			*(temp_ptr + delta_extra_byte + 1) =
85 				(uint8_t)(options[i].len - 13);
86 			break;
87 		case 2:
88 			*(header_byte) |= 14;
89 			uint16_t temp_len = (uint16_t)(options[i].len - 269);
90 			*(temp_ptr + delta_extra_byte + 1) =
91 				(uint8_t)((temp_len & 0xFF00) >> 8);
92 			*(temp_ptr + delta_extra_byte + 2) =
93 				(uint8_t)((temp_len & 0x00FF) >> 0);
94 			break;
95 		}
96 
97 		/* Move to the position, where option value begins */
98 		temp_ptr += 1 + delta_extra_byte + len_extra_byte;
99 		/* Add length of current option*/
100 		out->len = (uint32_t)(out->len + 1 + delta_extra_byte +
101 				      len_extra_byte + options[i].len);
102 		/* Copy the byte string of current option into output*/
103 		if (0 != options[i].len) {
104 			uint32_t dest_size =
105 				out_capacity - (uint32_t)(temp_ptr - out->ptr);
106 			TRY(_memcpy_s(temp_ptr, dest_size, options[i].value,
107 				      options[i].len));
108 
109 			temp_ptr += options[i].len;
110 		}
111 	}
112 	return ok;
113 }
114 
options_deserialize(struct byte_array * in_data,struct o_coap_option * opt,uint8_t * opt_cnt,struct byte_array * payload)115 enum err options_deserialize(struct byte_array *in_data,
116 			     struct o_coap_option *opt, uint8_t *opt_cnt,
117 			     struct byte_array *payload)
118 {
119 	uint8_t *temp_options_ptr = in_data->ptr;
120 	uint8_t temp_options_count = 0;
121 	uint8_t temp_option_header_len = 0;
122 	uint16_t temp_option_delta = 0;
123 	uint16_t temp_option_len = 0;
124 	uint16_t temp_option_number = 0;
125 
126 	if (0 == in_data->len) {
127 		payload->len = 0;
128 		payload->ptr = NULL;
129 		*opt_cnt = 0;
130 		return ok;
131 	}
132 
133 	/* Go through the in_data to find out how many options are there */
134 	uint16_t i = 0;
135 	while (i < in_data->len) {
136 		if (OPTION_PAYLOAD_MARKER == in_data->ptr[i]) {
137 			if ((in_data->len - i) < 2) {
138 				return not_valid_input_packet;
139 			}
140 			i++;
141 			payload->len = (uint32_t)in_data->len - i;
142 			payload->ptr = &in_data->ptr[i];
143 			return ok;
144 		}
145 
146 		temp_option_header_len = 1;
147 		/* Parser first byte,lower 4 bits for option value length and higher 4 bits for option delta*/
148 		temp_option_delta = ((*temp_options_ptr) & 0xF0) >> 4;
149 		temp_option_len = (*temp_options_ptr) & 0x0F;
150 
151 		temp_options_ptr++;
152 
153 		/* Special cases for extended option delta: 13 - 1 extra delta byte, 14 - 2 extra delta bytes, 15 - reserved */
154 		switch (temp_option_delta) {
155 		case 13:
156 			temp_option_header_len =
157 				(uint8_t)(temp_option_header_len + 1);
158 			temp_option_delta = (uint8_t)(*temp_options_ptr + 13);
159 			temp_options_ptr += 1;
160 			break;
161 		case 14:
162 			temp_option_header_len =
163 				(uint8_t)(temp_option_header_len + 2);
164 			temp_option_delta =
165 				(uint16_t)(((*temp_options_ptr) << 8) |
166 					   *(temp_options_ptr + 1)) +
167 				269;
168 			temp_options_ptr += 2;
169 			break;
170 		case 15:
171 			// ERROR
172 			return oscore_inpkt_invalid_option_delta;
173 			break;
174 		default:
175 			break;
176 		}
177 
178 		/* Special cases for extended option value length: 13 - 1 extra length byte, 14 - 2 extra length bytes, 15 - reserved */
179 		switch (temp_option_len) {
180 		case 13:
181 			temp_option_header_len =
182 				(uint8_t)(temp_option_header_len + 1);
183 			temp_option_len = (uint8_t)(*temp_options_ptr + 13);
184 			temp_options_ptr += 1;
185 			break;
186 		case 14:
187 			temp_option_header_len =
188 				(uint8_t)(temp_option_header_len + 2);
189 			temp_option_len =
190 				(uint16_t)(((*temp_options_ptr) << 8) |
191 					   (*(temp_options_ptr + 1) + 269));
192 			temp_options_ptr += 2;
193 			break;
194 		case 15:
195 			/* ERROR */
196 			return oscore_inpkt_invalid_optionlen;
197 			break;
198 		default:
199 			break;
200 		}
201 
202 		temp_option_number = temp_option_number + temp_option_delta;
203 		/* Update in output options */
204 		opt[temp_options_count].delta = temp_option_delta;
205 		opt[temp_options_count].len = temp_option_len;
206 		opt[temp_options_count].option_number = temp_option_number;
207 		if (temp_option_len == 0)
208 			opt[temp_options_count].value = NULL;
209 		else
210 			opt[temp_options_count].value = temp_options_ptr;
211 
212 		/* Update parameters*/
213 		i = (uint16_t)(i + temp_option_header_len + temp_option_len);
214 		temp_options_ptr += temp_option_len;
215 		if (MAX_OPTION_COUNT > temp_options_count) {
216 			temp_options_count++;
217 		} else {
218 			return too_many_options;
219 		}
220 		*opt_cnt = temp_options_count;
221 	}
222 	return ok;
223 }
224 
coap_deserialize(struct byte_array * in,struct o_coap_packet * out)225 enum err coap_deserialize(struct byte_array *in, struct o_coap_packet *out)
226 {
227 	uint8_t *tmp_p = in->ptr;
228 	uint32_t payload_len = in->len;
229 
230 	/* Read CoAP/OSCORE header (4 bytes)*/
231 	if (payload_len < HEADER_LEN) {
232 		return not_valid_input_packet;
233 	}
234 	out->options_cnt = 0;
235 	out->header.ver =
236 		((*tmp_p) & HEADER_VERSION_MASK) >> HEADER_VERSION_OFFSET;
237 	out->header.type = ((*tmp_p) & HEADER_TYPE_MASK) >> HEADER_TYPE_OFFSET;
238 	out->header.TKL = ((*tmp_p) & HEADER_TKL_MASK) >> HEADER_TKL_OFFSET;
239 	out->header.code = *(tmp_p + 1);
240 	uint16_t mid_l = *(tmp_p + 3);
241 	uint16_t mid_h = *(tmp_p + 2);
242 	out->header.MID = (uint16_t)(mid_h << 8 | mid_l);
243 
244 	/* Update pointer and length*/
245 	tmp_p += 4;
246 	payload_len -= 4;
247 
248 	/*Read the token, if it exists*/
249 	if (out->header.TKL == 0) {
250 		out->token = NULL;
251 	} else if (out->header.TKL <= 8) {
252 		if (out->header.TKL <= payload_len) {
253 			out->token = tmp_p;
254 		} else {
255 			return oscore_inpkt_invalid_tkl;
256 		}
257 	} else {
258 		/* ERROR: CoAP token length maximal 8 bytes */
259 		return oscore_inpkt_invalid_tkl;
260 	}
261 	/* Update pointer and length */
262 	tmp_p += out->header.TKL;
263 	payload_len -= out->header.TKL;
264 
265 	struct byte_array remaining_bytes = BYTE_ARRAY_INIT(tmp_p, payload_len);
266 	TRY(options_deserialize(&remaining_bytes,
267 				(struct o_coap_option *)&out->options,
268 				&out->options_cnt, &out->payload));
269 
270 	return ok;
271 }
272 
coap_serialize(struct o_coap_packet * in,uint8_t * out_byte_string,uint32_t * out_byte_string_len)273 enum err coap_serialize(struct o_coap_packet *in, uint8_t *out_byte_string,
274 			uint32_t *out_byte_string_len)
275 {
276 	uint8_t *temp_out_ptr = out_byte_string;
277 
278 	/* First byte in header (version + type + token length) */
279 	*temp_out_ptr = (uint8_t)((in->header.ver << HEADER_VERSION_OFFSET) |
280 				  (in->header.type << HEADER_TYPE_OFFSET) |
281 				  (in->header.TKL));
282 	/* Following 3 bytes in header (1 byte code + 2 bytes message ID)*/
283 	*(temp_out_ptr + 1) = in->header.code;
284 	uint16_t temp_MID = in->header.MID;
285 	*(temp_out_ptr + 2) = (uint8_t)((temp_MID & 0xFF00) >> 8);
286 	*(temp_out_ptr + 3) = (uint8_t)(temp_MID & 0x00FF);
287 
288 	temp_out_ptr += 4;
289 	/* Copy token */
290 	if (in->header.TKL > 0) {
291 		uint32_t dest_size = *out_byte_string_len -
292 				     (uint32_t)(temp_out_ptr - out_byte_string);
293 		TRY(_memcpy_s(temp_out_ptr, dest_size, in->token,
294 			      in->header.TKL));
295 
296 		temp_out_ptr += in->header.TKL;
297 	}
298 
299 	/* Calculate the maximal length of all options, i.e. all options have two bytes extra delta and length*/
300 	uint32_t opt_bytes_len = 0;
301 	for (uint8_t i = 0; i < in->options_cnt; i++) {
302 		opt_bytes_len += OPT_SERIAL_OVERHEAD + in->options[i].len;
303 	}
304 
305 	BYTE_ARRAY_NEW(option_byte_string, MAX_COAP_OPTIONS_LEN, opt_bytes_len);
306 
307 	/* Convert all OSCORE U-options structure into byte string*/
308 	TRY(options_serialize(in->options, in->options_cnt,
309 			      &option_byte_string));
310 
311 	/* Copy options byte string into output*/
312 
313 	uint32_t dest_size = *out_byte_string_len -
314 			     (uint32_t)(temp_out_ptr - out_byte_string);
315 	TRY(_memcpy_s(temp_out_ptr, dest_size, option_byte_string.ptr,
316 		      option_byte_string.len));
317 
318 	temp_out_ptr += option_byte_string.len;
319 
320 	/* Payload */
321 	if (in->payload.len != 0) {
322 		*temp_out_ptr = OPTION_PAYLOAD_MARKER;
323 
324 		dest_size = *out_byte_string_len -
325 			    (uint32_t)(temp_out_ptr + 1 - out_byte_string);
326 		TRY(_memcpy_s(++temp_out_ptr, dest_size, in->payload.ptr,
327 			      in->payload.len));
328 	}
329 	*out_byte_string_len =
330 		(uint32_t)4 + in->header.TKL + option_byte_string.len;
331 	if (in->payload.len) {
332 		*out_byte_string_len += 1 + in->payload.len;
333 	}
334 
335 	PRINT_ARRAY("Byte string of the converted packet", out_byte_string,
336 		    *out_byte_string_len);
337 	return ok;
338 }
339 
is_request(struct o_coap_packet * packet)340 bool is_request(struct o_coap_packet *packet)
341 {
342 	if ((CODE_CLASS_MASK & packet->header.code) == REQUEST_CLASS) {
343 		return true;
344 	} else {
345 		return false;
346 	}
347 }
348 
coap_get_message_type(struct o_coap_packet * coap_packet,enum o_coap_msg * msg_type)349 enum err coap_get_message_type(struct o_coap_packet *coap_packet,
350 			       enum o_coap_msg *msg_type)
351 {
352 	if ((NULL == coap_packet) || (NULL == msg_type)) {
353 		return wrong_parameter;
354 	}
355 
356 	enum o_coap_msg result;
357 	struct byte_array observe;
358 	bool observe_valid = get_observe_value(
359 		coap_packet->options, coap_packet->options_cnt, &observe);
360 	bool request = is_request(coap_packet);
361 	if (request) {
362 		// packet can be a request, a registration or a cancellation
363 		result = COAP_MSG_REQUEST;
364 		if (observe_valid) {
365 			if ((0 == observe.len) ||
366 			    ((1 == observe.len) &&
367 			     (OSCORE_OBSERVE_REGISTRATION_VALUE ==
368 			      observe.ptr[0]))) {
369 				/* Empty uint option is interpreted as a value 0.
370 				   For more info, see RFC 7252 section 3.2. */
371 				result = COAP_MSG_REGISTRATION;
372 			} else if ((1 == observe.len) &&
373 				   (OSCORE_OBSERVE_CANCELLATION_VALUE ==
374 				    observe.ptr[0])) {
375 				result = COAP_MSG_CANCELLATION;
376 			}
377 		}
378 	} else {
379 		// packet can be a regular response or a notification
380 		result = (observe_valid ? COAP_MSG_NOTIFICATION :
381 					  COAP_MSG_RESPONSE);
382 	}
383 
384 	*msg_type = result;
385 	return ok;
386 }
387