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, ¤t_size, max_size,
171 option->value, option->len));
172 TRY(buffer_append(uri_path, ¤t_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