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 <string.h>
13 
14 #include "oscore/option.h"
15 #include "oscore/oscore_coap.h"
16 
17 #include "common/memcpy_s.h"
18 
19 /**
20  * @brief Securely append a substring to given buffer.
21  *
22  * @param buffer Buffer to have the substring appended.
23  * @param current_size Current size of the buffer content. Updated after successfull append.
24  * @param max_size Memory size allocated for the buffer.
25  * @param substring Substring buffer to be appended.
26  * @param substring_size Substring size.
27  * @return ok or error
28  */
buffer_append(uint8_t * buffer,uint32_t * current_size,uint32_t max_size,const uint8_t * substring,uint32_t substring_size)29 static enum err buffer_append(uint8_t *buffer, uint32_t *current_size,
30 			      uint32_t max_size, const uint8_t *substring,
31 			      uint32_t substring_size)
32 {
33 	uint8_t *destination =
34 		&buffer[*current_size]; //pointer to current end of the content
35 	uint32_t remaining_size =
36 		max_size -
37 		(*current_size); //how many bytes in the buffer are still available
38 	TRY(_memcpy_s(destination, remaining_size, substring, substring_size));
39 	*current_size += substring_size;
40 	return ok;
41 }
42 
is_class_e(uint16_t code)43 bool is_class_e(uint16_t code)
44 {
45 	// blacklist, because OSCORE dictates that unknown options SHALL be processed as class E
46 	return code != URI_HOST && code != URI_PORT && code != OSCORE &&
47 	       code != PROXY_URI && code != PROXY_SCHEME;
48 }
49 
is_observe(struct o_coap_option * options,uint8_t options_cnt)50 bool is_observe(struct o_coap_option *options, uint8_t options_cnt)
51 {
52 	for (uint8_t i = 0; i < options_cnt; i++) {
53 		if (options[i].option_number == OBSERVE) {
54 			return true;
55 		}
56 	}
57 	return false;
58 }
59 
get_observe_value(struct o_coap_option * options,uint8_t options_cnt,struct byte_array * output)60 bool get_observe_value(struct o_coap_option *options, uint8_t options_cnt,
61 		       struct byte_array *output)
62 {
63 	if ((NULL == options) || (NULL == output)) {
64 		return false;
65 	}
66 
67 	for (uint8_t i = 0; i < options_cnt; i++) {
68 		if (OBSERVE != options[i].option_number) {
69 			continue;
70 		}
71 
72 		output->ptr = options[i].value;
73 		output->len = options[i].len;
74 		return true;
75 	}
76 	output = NULL;
77 	return false;
78 }
79 
cache_echo_val(struct byte_array * dest,struct o_coap_option * options,uint8_t options_cnt)80 enum err cache_echo_val(struct byte_array *dest, struct o_coap_option *options,
81 			uint8_t options_cnt)
82 {
83 	for (uint8_t i = 0; i < options_cnt; i++) {
84 		if (options[i].option_number == ECHO) {
85 			PRINT_MSG("Caching the ECHO value!\n");
86 			TRY(_memcpy_s(dest->ptr, dest->len, options[i].value,
87 				      options[i].len));
88 			dest->len = options[i].len;
89 			return ok;
90 		}
91 	}
92 	return no_echo_option;
93 }
94 
oscore_decrypted_payload_parser(struct byte_array * in_payload,uint8_t * out_code,struct o_coap_option * out_E_options,uint8_t * E_options_cnt,struct byte_array * out_o_coap_payload)95 enum err oscore_decrypted_payload_parser(struct byte_array *in_payload,
96 					 uint8_t *out_code,
97 					 struct o_coap_option *out_E_options,
98 					 uint8_t *E_options_cnt,
99 					 struct byte_array *out_o_coap_payload)
100 {
101 	uint8_t *temp_payload_ptr = in_payload->ptr;
102 	uint32_t temp_payload_len = in_payload->len;
103 
104 	/* Code */
105 	*out_code = *(temp_payload_ptr++);
106 	temp_payload_len--;
107 
108 	struct byte_array remaining_bytes =
109 		BYTE_ARRAY_INIT(temp_payload_ptr, temp_payload_len);
110 	TRY(options_deserialize(&remaining_bytes, out_E_options, E_options_cnt,
111 				out_o_coap_payload));
112 
113 	return ok;
114 }
115 
echo_val_is_fresh(struct byte_array * cache_val,struct byte_array * decrypted_payload)116 enum err echo_val_is_fresh(struct byte_array *cache_val,
117 			   struct byte_array *decrypted_payload)
118 {
119 	uint8_t code = 0;
120 	struct byte_array unprotected_o_coap_payload;
121 
122 	struct o_coap_option E_options[10];
123 	uint8_t E_options_cnt = 0;
124 
125 	/* Parse decrypted payload: code + options + unprotected CoAP payload*/
126 	TRY(oscore_decrypted_payload_parser(decrypted_payload, &code, E_options,
127 					    &E_options_cnt,
128 					    &unprotected_o_coap_payload));
129 
130 	for (uint8_t i = 0; i < E_options_cnt; i++) {
131 		if (E_options[i].option_number == ECHO) {
132 			if (0 == memcmp(E_options[i].value, cache_val->ptr,
133 					cache_val->len) &&
134 			    cache_val->len == E_options[i].len) {
135 				PRINT_MSG("ECHO option check -- OK\n");
136 				return ok;
137 			} else {
138 				return echo_val_mismatch;
139 			}
140 		}
141 	}
142 
143 	return no_echo_option;
144 }
145 
uri_path_create(struct o_coap_option * options,uint32_t options_size,uint8_t * uri_path,uint32_t * uri_path_size)146 enum err uri_path_create(struct o_coap_option *options, uint32_t options_size,
147 			 uint8_t *uri_path, uint32_t *uri_path_size)
148 {
149 	if ((NULL == options) || (NULL == uri_path) ||
150 	    (NULL == uri_path_size)) {
151 		return wrong_parameter;
152 	}
153 
154 	uint32_t current_size = 0;
155 	uint32_t max_size = *uri_path_size;
156 	memset(uri_path, 0, max_size);
157 
158 	const uint8_t delimiter = '/';
159 	const uint32_t delimiter_size = 1;
160 
161 	for (uint32_t index = 0; index < options_size; index++) {
162 		struct o_coap_option *option = &options[index];
163 		if (URI_PATH != option->option_number) {
164 			continue;
165 		}
166 		if ((0 != option->len) && (NULL == option->value)) {
167 			return oscore_wrong_uri_path;
168 		}
169 
170 		TRY(buffer_append(uri_path, &current_size, max_size,
171 				  option->value, option->len));
172 		TRY(buffer_append(uri_path, &current_size, max_size, &delimiter,
173 				  delimiter_size));
174 	}
175 
176 	/* Remove last '/' character, or add a single one if the path is empty */
177 	if (current_size > 0) {
178 		uri_path[current_size] = 0;
179 		current_size--;
180 	} else {
181 		uri_path[0] = delimiter;
182 		current_size = delimiter_size;
183 	}
184 
185 	*uri_path_size = current_size;
186 	return ok;
187 }
188