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/aad.h"
19 #include "oscore/oscore_coap.h"
20 #include "oscore/nonce.h"
21 #include "oscore/option.h"
22 #include "oscore/oscore_cose.h"
23 #include "oscore/security_context.h"
24 #include "oscore/nvm.h"
25 
26 #include "common/byte_array.h"
27 #include "common/oscore_edhoc_error.h"
28 #include "common/memcpy_s.h"
29 #include "common/print_util.h"
30 #include "common/unit_test.h"
31 
32 /**
33  * @brief Extract input CoAP options into E(encrypted) and U(unprotected)
34  * @param in_o_coap: input CoAP packet
35  * @param e_options: output pointer to E-options
36  * @param e_options_cnt: count number of output E-options
37  * @param e_options_len: Byte string length of all E-options, which will be used when forming E-options into plaintext
38  * @param U_options: output pointer to U-options
39  * @param U_options_cnt: count number of output U-options
40  * @return err
41  *
42  */
inner_outer_option_split(struct o_coap_packet * in_o_coap,struct o_coap_option * e_options,uint8_t * e_options_cnt,uint16_t * e_options_len,struct o_coap_option * U_options,uint8_t * U_options_cnt)43 STATIC enum err inner_outer_option_split(struct o_coap_packet *in_o_coap,
44 					 struct o_coap_option *e_options,
45 					 uint8_t *e_options_cnt,
46 					 uint16_t *e_options_len,
47 					 struct o_coap_option *U_options,
48 					 uint8_t *U_options_cnt)
49 {
50 	enum err r = ok;
51 
52 	/* Initialize to 0 */
53 	*e_options_len = 0;
54 
55 	uint8_t temp_option_nr = 0;
56 	uint16_t temp_len = 0;
57 	uint8_t temp_E_option_delta_sum = 0;
58 	uint8_t temp_U_option_delta_sum = 0;
59 
60 	if (MAX_OPTION_COUNT < in_o_coap->options_cnt) {
61 		return too_many_options;
62 	}
63 
64 	for (uint8_t i = 0; i < in_o_coap->options_cnt; i++) {
65 		uint8_t extra_bytes =
66 			opt_extra_bytes(in_o_coap->options[i].delta) +
67 			opt_extra_bytes(in_o_coap->options[i].len);
68 
69 		temp_option_nr =
70 			(uint8_t)(temp_option_nr + in_o_coap->options[i].delta);
71 		temp_len = in_o_coap->options[i].len;
72 
73 		/* process special options, see 4.1.3 in RFC8613*/
74 		/* if the option does not need special processing just put it in the
75 		E or U array*/
76 
77 		switch (temp_option_nr) {
78 		case OBSERVE:
79 			/*An observe option in an a CoAP packet is transformed to an inner
80 			and outer option in a OSCORE packet.*/
81 
82 			/*
83 			* Inner option has value NULL if notification or the original value
84 			* in the coap packet if registration/cancellation.
85 			*/
86 			e_options[*e_options_cnt].delta = (uint16_t)(
87 				temp_option_nr - temp_E_option_delta_sum);
88 			if (is_request(in_o_coap)) {
89 				/*registrations/cancellations are requests */
90 				e_options[*e_options_cnt].len = temp_len;
91 				e_options[*e_options_cnt].value =
92 					in_o_coap->options[i].value;
93 
94 				/* Add option header length and value length */
95 				(*e_options_len) =
96 					(uint16_t)((*e_options_len) + 1 +
97 						   extra_bytes + temp_len);
98 			} else {
99 				/*notifications are responses*/
100 				e_options[*e_options_cnt].len = 0;
101 				e_options[*e_options_cnt].value = NULL;
102 
103 				/* since the option value has length 0, we add 1 for the option header which is always there */
104 				(*e_options_len)++;
105 			}
106 
107 			e_options[*e_options_cnt].option_number =
108 				temp_option_nr;
109 
110 			/* Update delta sum of E-options */
111 			temp_E_option_delta_sum =
112 				(uint8_t)(temp_E_option_delta_sum +
113 					  e_options[*e_options_cnt].delta);
114 
115 			/* Increment E-options count */
116 			(*e_options_cnt)++;
117 
118 			/*
119 			*outer option (value as in the original coap packet
120 			*/
121 			U_options[*U_options_cnt].delta = (uint16_t)(
122 				temp_option_nr - temp_U_option_delta_sum);
123 			U_options[*U_options_cnt].len = temp_len;
124 			U_options[*U_options_cnt].value =
125 				in_o_coap->options[i].value;
126 			U_options[*U_options_cnt].option_number =
127 				temp_option_nr;
128 
129 			/* Update delta sum of E-options */
130 			temp_U_option_delta_sum =
131 				(uint8_t)(temp_U_option_delta_sum +
132 					  U_options[*U_options_cnt].delta);
133 
134 			/* Increment E-options count */
135 			(*U_options_cnt)++;
136 
137 			break;
138 
139 		default:
140 			/* check delta, whether current option U or E */
141 			if (is_class_e(temp_option_nr) == 1) {
142 				/* E-options, which will be copied in plaintext to be encrypted*/
143 				e_options[*e_options_cnt].delta =
144 					(uint16_t)(temp_option_nr -
145 						   temp_E_option_delta_sum);
146 				e_options[*e_options_cnt].len = temp_len;
147 				e_options[*e_options_cnt].value =
148 					in_o_coap->options[i].value;
149 				e_options[*e_options_cnt].option_number =
150 					temp_option_nr;
151 
152 				/* Update delta sum of E-options */
153 				temp_E_option_delta_sum = (uint8_t)(
154 					temp_E_option_delta_sum +
155 					e_options[*e_options_cnt].delta);
156 
157 				/* Increment E-options count */
158 				(*e_options_cnt)++;
159 				/* Add option header length and value length */
160 				(*e_options_len) =
161 					(uint16_t)((*e_options_len) + 1 +
162 						   extra_bytes + temp_len);
163 			} else {
164 				/* U-options */
165 				U_options[*U_options_cnt].delta =
166 					(uint16_t)(temp_option_nr -
167 						   temp_U_option_delta_sum);
168 				U_options[*U_options_cnt].len = temp_len;
169 				U_options[*U_options_cnt].value =
170 					in_o_coap->options[i].value;
171 				U_options[*U_options_cnt].option_number =
172 					temp_option_nr;
173 
174 				/* Update delta sum of E-options */
175 				temp_U_option_delta_sum = (uint8_t)(
176 					temp_U_option_delta_sum +
177 					U_options[*U_options_cnt].delta);
178 
179 				/* Increment E-options count */
180 				(*U_options_cnt)++;
181 			}
182 			break;
183 		}
184 	}
185 	return r;
186 }
187 
188 /**
189  * @brief Build up plaintext which should be encrypted and protected
190  * @param in_o_coap: input CoAP packet that will be analyzed
191  * @param E_options: E-options, which should be protected
192  * @param E_options_cnt: count number of E-options
193  * @param plaintext: output plaintext, which will be encrypted
194  * @return err
195  *
196  */
plaintext_setup(struct o_coap_packet * in_o_coap,struct o_coap_option * E_options,uint8_t E_options_cnt,struct byte_array * plaintext)197 static inline enum err plaintext_setup(struct o_coap_packet *in_o_coap,
198 				       struct o_coap_option *E_options,
199 				       uint8_t E_options_cnt,
200 				       struct byte_array *plaintext)
201 {
202 	uint8_t *temp_plaintext_ptr = plaintext->ptr;
203 
204 	/* Add code to plaintext */
205 	*temp_plaintext_ptr = in_o_coap->header.code;
206 
207 	/* Calculate the maximal length of all options, i.e. all options
208 	have two bytes extra delta and length */
209 	uint16_t e_opt_serial_len = 0;
210 	for (uint8_t i = 0; i < E_options_cnt; i++) {
211 		e_opt_serial_len = (uint16_t)(e_opt_serial_len + 1 + 2 + 2 +
212 					      E_options[i].len);
213 	}
214 	/* Setup buffer */
215 	BYTE_ARRAY_NEW(e_opt_serial, E_OPTIONS_BUFF_MAX_LEN, e_opt_serial_len);
216 
217 	/* Convert all E-options structure to byte string, and copy it to
218 	output*/
219 	TRY(options_serialize(E_options, E_options_cnt, &e_opt_serial));
220 
221 	uint32_t dest_size = (plaintext->len - (uint32_t)(temp_plaintext_ptr +
222 							  1 - plaintext->ptr));
223 	TRY(_memcpy_s(++temp_plaintext_ptr, dest_size, e_opt_serial.ptr,
224 		      e_opt_serial.len));
225 	temp_plaintext_ptr += e_opt_serial.len;
226 
227 	/* Add payload to plaintext*/
228 	if (in_o_coap->payload.len != 0) {
229 		/* An extra byte 0xFF before payload*/
230 		*temp_plaintext_ptr = 0xff;
231 
232 		dest_size = (plaintext->len - (uint32_t)(temp_plaintext_ptr +
233 							 1 - plaintext->ptr));
234 		TRY(_memcpy_s(++temp_plaintext_ptr, dest_size,
235 			      in_o_coap->payload.ptr, in_o_coap->payload.len));
236 	}
237 	PRINT_ARRAY("Plain text", plaintext->ptr, plaintext->len);
238 	return ok;
239 }
240 
241 /**
242  * @brief   OSCORE option value length
243  * @param   piv_len length of the PIV array
244  * @param   kid_len length of the KID array
245  * @param   kid_context_len length of the KID context array
246  * @return  length of the OSCORE option value
247  */
get_oscore_opt_val_len(uint32_t piv_len,uint32_t kid_len,uint32_t kid_context_len)248 static inline uint32_t get_oscore_opt_val_len(uint32_t piv_len,
249 					      uint32_t kid_len,
250 					      uint32_t kid_context_len)
251 {
252 	uint32_t length = piv_len + kid_len + kid_context_len;
253 	if (length) {
254 		/*if any of piv, kid_context or kid is present 1 byte for the flags is reserved */
255 		length++;
256 	}
257 	if (kid_context_len) {
258 		/*if kid_context is present one byte is reserved for the s field*/
259 		length++;
260 	}
261 	return length;
262 }
263 
264 /**
265  * @brief   Generate an OSCORE option.
266  * @param   piv set to the trimmed sender sequence number in requests or NULL
267  *          in responses
268  * @param   kid set to Sender ID in requests or NULL in responses
269  * @param   kid_context set to ID context in request when present. If not
270  *          present or a response set to NULL
271  * @param   oscore_option: output pointer OSCORE option structure
272  * @return  err
273  */
oscore_option_generate(struct byte_array * piv,struct byte_array * kid,struct byte_array * kid_context,struct oscore_option * oscore_option)274 STATIC enum err oscore_option_generate(struct byte_array *piv,
275 				       struct byte_array *kid,
276 				       struct byte_array *kid_context,
277 				       struct oscore_option *oscore_option)
278 {
279 	uint32_t piv_len = (NULL == piv) ? 0 : piv->len;
280 	uint32_t kid_len = (NULL == kid) ? 0 : kid->len;
281 	uint32_t kid_context_len = (NULL == kid_context) ? 0 : kid_context->len;
282 
283 	oscore_option->option_number = OSCORE;
284 	oscore_option->len = (uint8_t)get_oscore_opt_val_len(piv_len, kid_len,
285 							     kid_context_len);
286 	TRY(check_buffer_size(OSCORE_OPT_VALUE_LEN, oscore_option->len));
287 	oscore_option->value = oscore_option->buf;
288 
289 	uint32_t dest_size;
290 
291 	if (oscore_option->len == 0) {
292 		oscore_option->value = NULL;
293 	} else {
294 		memset(oscore_option->value, 0, oscore_option->len);
295 
296 		uint8_t *temp_ptr = oscore_option->value;
297 
298 		if (piv_len != 0) {
299 			/* Set header bits of PIV */
300 			oscore_option->value[0] =
301 				(uint8_t)(oscore_option->value[0] | piv->len);
302 			/* copy PIV (sender sequence) */
303 
304 			dest_size = (uint32_t)(
305 				oscore_option->len -
306 				(temp_ptr + 1 - oscore_option->value));
307 			TRY(_memcpy_s(++temp_ptr, dest_size, piv->ptr,
308 				      piv->len));
309 
310 			temp_ptr += piv->len;
311 		} else {
312 			temp_ptr++;
313 		}
314 
315 		if (kid_context_len != 0) {
316 			/* Set header flag bit of KID context */
317 			oscore_option->value[0] |= COMP_OSCORE_OPT_KIDC_H_MASK;
318 			/* Copy length and context value */
319 			*temp_ptr = (uint8_t)(kid_context->len);
320 
321 			dest_size = (uint32_t)(
322 				oscore_option->len -
323 				(temp_ptr + 1 - oscore_option->value));
324 			TRY(_memcpy_s(++temp_ptr, dest_size, kid_context->ptr,
325 				      kid_context->len));
326 
327 			temp_ptr += kid_context->len;
328 		}
329 
330 		/* Set header flag bit of KID */
331 		/* The KID header flag is set always in requests */
332 		/* This function is not called in responses */
333 		oscore_option->value[0] |= COMP_OSCORE_OPT_KID_K_MASK;
334 		if (kid_len != 0) {
335 			/* Copy KID */
336 			dest_size =
337 				(uint32_t)(oscore_option->len -
338 					   (temp_ptr - oscore_option->value));
339 			TRY(_memcpy_s(temp_ptr, dest_size, kid->ptr, kid->len));
340 		}
341 	}
342 
343 	PRINT_ARRAY("OSCORE option value", oscore_option->value,
344 		    oscore_option->len);
345 	return ok;
346 }
347 
348 /**
349  * @brief Generate an OSCORE packet with all needed data
350  * @param in_o_coap: input CoAP packet
351  * @param out_oscore: output pointer to OSCORE packet
352  * @param U_options: pointer to array of all unprotected options, including OSCORE_option
353  * @param U_options_cnt: count number of U-options
354  * @param in_ciphertext: input ciphertext, will be set into payload in OSCORE packet
355  * @param oscore_option: The OSCORE option
356  * @return err
357  *
358  */
oscore_pkg_generate(struct o_coap_packet * in_o_coap,struct o_coap_packet * out_oscore,struct o_coap_option * u_options,uint8_t u_options_cnt,struct byte_array * in_ciphertext,struct oscore_option * oscore_option)359 STATIC enum err oscore_pkg_generate(struct o_coap_packet *in_o_coap,
360 				    struct o_coap_packet *out_oscore,
361 				    struct o_coap_option *u_options,
362 				    uint8_t u_options_cnt,
363 				    struct byte_array *in_ciphertext,
364 				    struct oscore_option *oscore_option)
365 {
366 	/* Set OSCORE header and Token*/
367 	out_oscore->header.ver = in_o_coap->header.ver;
368 	out_oscore->header.type = in_o_coap->header.type;
369 	out_oscore->header.TKL = in_o_coap->header.TKL;
370 	out_oscore->header.MID = in_o_coap->header.MID;
371 	if (out_oscore->header.TKL == 0) {
372 		out_oscore->token = NULL;
373 	} else {
374 		out_oscore->token = in_o_coap->token;
375 	}
376 
377 	bool observe = is_observe(u_options, u_options_cnt);
378 	if (is_request(in_o_coap)) {
379 		if (observe) {
380 			out_oscore->header.code = CODE_REQ_FETCH;
381 		} else {
382 			out_oscore->header.code = CODE_REQ_POST;
383 		}
384 	} else {
385 		if (observe) {
386 			out_oscore->header.code = CODE_RESP_CONTENT;
387 		} else {
388 			out_oscore->header.code = CODE_RESP_CHANGED;
389 		}
390 	}
391 
392 	/* U-options + OSCORE option (compare oscore option number with others)
393 	 Find out the appropriate position of OSCORE option */
394 	uint8_t oscore_opt_pos = u_options_cnt;
395 	for (uint8_t i = 0; i < u_options_cnt; i++) {
396 		/* Once found, finish the for-loop */
397 		if (u_options[i].option_number > OSCORE) {
398 			oscore_opt_pos = i;
399 			break;
400 		}
401 	}
402 
403 	/* Update options count number to output*/
404 	out_oscore->options_cnt = (uint8_t)(1 + u_options_cnt);
405 
406 	uint8_t temp_opt_number_sum = 0;
407 	/* Show the position of U-options */
408 	uint8_t u_opt_pos = 0;
409 	for (uint8_t i = 0; i < u_options_cnt + 1; i++) {
410 		if (i == oscore_opt_pos) {
411 			/* OSCORE_option */
412 			out_oscore->options[i].delta =
413 				(uint16_t)(oscore_option->option_number -
414 					   temp_opt_number_sum);
415 			out_oscore->options[i].len = oscore_option->len;
416 			out_oscore->options[i].option_number =
417 				oscore_option->option_number;
418 			out_oscore->options[i].value = oscore_option->value;
419 		} else {
420 			/* U-options */
421 			out_oscore->options[i].delta =
422 				(uint16_t)(u_options[u_opt_pos].option_number -
423 					   temp_opt_number_sum);
424 			out_oscore->options[i].len = u_options[u_opt_pos].len;
425 			out_oscore->options[i].option_number =
426 				u_options[u_opt_pos].option_number;
427 			out_oscore->options[i].value =
428 				u_options[u_opt_pos].value;
429 
430 			u_opt_pos++;
431 		}
432 		temp_opt_number_sum = (uint8_t)(temp_opt_number_sum +
433 						out_oscore->options[i].delta);
434 	}
435 
436 	/* Protected Payload */
437 	out_oscore->payload.len = in_ciphertext->len;
438 	out_oscore->payload.ptr = in_ciphertext->ptr;
439 	return ok;
440 }
441 
442 /**
443  * @brief Increment Sender Sequence Number and call the function to periodically write it to NVM.
444  *
445  * @param c Security context.
446  * @return enum err
447  */
generate_new_ssn(struct context * c)448 static enum err generate_new_ssn(struct context *c)
449 {
450 	if (NULL == c) {
451 		return wrong_parameter;
452 	}
453 
454 	c->sc.ssn++;
455 
456 #ifdef OSCORE_NVM_SUPPORT
457 	struct nvm_key_t nvm_key = { .sender_id = c->sc.sender_id,
458 				     .recipient_id = c->rc.recipient_id,
459 				     .id_context = c->cc.id_context };
460 	bool echo_sync_in_progress =
461 		(ECHO_SYNCHRONIZED != c->rrc.echo_state_machine);
462 	return ssn_store_in_nvm(&nvm_key, c->sc.ssn, echo_sync_in_progress);
463 #else
464 	return ok;
465 #endif
466 }
467 
468 /**
469  * @brief Checks if given message needs a fresh PIV/nonce, based on its type and current state of ECHO challenge.
470  * @param msg_type Message type.
471  * @param echo_state ECHO challenge state.
472  * @return If true, new PIV/nonce must be generated.
473  */
needs_new_piv(enum o_coap_msg msg_type,enum echo_state echo_state)474 static bool needs_new_piv(enum o_coap_msg msg_type, enum echo_state echo_state)
475 {
476 	/* Encrypt data using new PIV/nonce in the following cases:
477 		- Client prepares any kind of request.
478 		- Server prepares a response with ECHO challenge after the reboot (see RFC 8613 Appendix B.1.2).
479 		- Server prepares a notification (response) to an observe registration.
480 	   Encrypt data using corresponding request nonce:
481 		- Server prepares a response to a request after the ECHO challenge.
482 	   For more details, see RFC 8613 p. 8.3 and the following hyperlinks.*/
483 	return ((COAP_MSG_RESPONSE != msg_type) || (ECHO_VERIFY == echo_state));
484 }
485 
486 /**
487  * @brief Wrapper function with common operations for encrypting the payload.
488  *        These operations are shared in all possible scenarios.
489  *        For more info, see RFC8616 8.1 and 8.3.
490  *
491  * @param plaintext Input plaintext to be encrypted.
492  * @param ciphertext Output encrypted payload for the OSCORE packet.
493  * @param c Security context.
494  * @param input_coap Input coap packet.
495  * @param oscore_option Output OSCORE option.
496  * @return enum err
497  */
encrypt_wrapper(struct byte_array * plaintext,struct byte_array * ciphertext,struct context * c,struct o_coap_packet * input_coap,struct oscore_option * oscore_option)498 static enum err encrypt_wrapper(struct byte_array *plaintext,
499 				struct byte_array *ciphertext,
500 				struct context *c,
501 				struct o_coap_packet *input_coap,
502 				struct oscore_option *oscore_option)
503 {
504 	BYTE_ARRAY_NEW(new_piv, MAX_PIV_LEN, MAX_PIV_LEN);
505 	BYTE_ARRAY_NEW(new_nonce, NONCE_LEN, NONCE_LEN);
506 	struct byte_array piv = BYTE_ARRAY_INIT(NULL, 0);
507 	struct byte_array kid = BYTE_ARRAY_INIT(NULL, 0);
508 	struct byte_array kid_context = BYTE_ARRAY_INIT(NULL, 0);
509 	struct byte_array nonce;
510 
511 	/* Read necessary fields from the input packet. */
512 	enum o_coap_msg msg_type;
513 	TRY(coap_get_message_type(input_coap, &msg_type));
514 	struct byte_array token =
515 		BYTE_ARRAY_INIT(input_coap->token, input_coap->header.TKL);
516 
517 	/* Generate new PIV/nonce if needed. */
518 	bool use_new_piv = needs_new_piv(msg_type, c->rrc.echo_state_machine);
519 	if (use_new_piv) {
520 		TRY(ssn2piv(c->sc.ssn, &new_piv));
521 		TRY(generate_new_ssn(c));
522 		TRY(create_nonce(&c->sc.sender_id, &new_piv, &c->cc.common_iv,
523 				 &new_nonce));
524 
525 		nonce = new_nonce;
526 		piv = new_piv;
527 		kid = c->sc.sender_id;
528 		kid_context = c->cc.id_context;
529 	} else {
530 		nonce = c->rrc.nonce;
531 	}
532 
533 	/* Generate OSCORE option based on selected values. */
534 	TRY(oscore_option_generate(&piv, &kid, &kid_context, oscore_option));
535 
536 	/* AAD shares the same format for both requests and responses,
537 	   yet request_kid and request_piv fields are only used by responses.
538 	   For more details, see 5.4. */
539 	BYTE_ARRAY_NEW(aad, MAX_AAD_LEN, MAX_AAD_LEN);
540 	struct byte_array request_piv = piv;
541 	struct byte_array request_kid = kid;
542 	TRY(oscore_interactions_read_wrapper(msg_type, &token,
543 					     c->rrc.interactions, &request_piv,
544 					     &request_kid));
545 	TRY(create_aad(NULL, 0, c->cc.aead_alg, &request_kid, &request_piv,
546 		       &aad));
547 
548 	/* Encrypt the plaintext */
549 	TRY(oscore_cose_encrypt(plaintext, ciphertext, &nonce, &aad,
550 				&c->sc.sender_key));
551 
552 	/* Update nonce only after successful encryption (for handling future responses). */
553 	if (use_new_piv) {
554 		TRY(byte_array_cpy(&c->rrc.nonce, &nonce, NONCE_LEN));
555 	}
556 
557 	/* Handle OSCORE interactions after successful encryption. */
558 	BYTE_ARRAY_NEW(uri_paths, OSCORE_MAX_URI_PATH_LEN,
559 		       OSCORE_MAX_URI_PATH_LEN);
560 	TRY(uri_path_create(input_coap->options, input_coap->options_cnt,
561 			    uri_paths.ptr, &(uri_paths.len)));
562 	TRY(oscore_interactions_update_wrapper(msg_type, &token, &uri_paths,
563 					       c->rrc.interactions,
564 					       &request_piv, &request_kid));
565 
566 	return ok;
567 }
568 
569 /**
570  *@brief 	Converts a CoAP packet to OSCORE packet
571  *@note		For messaging layer packets (simple ACK with no payload, code 0.00),
572  *			encryption is dismissed and raw input buffer is copied,
573  *			as specified at section 4.2 in RFC8613.
574  *@param	buf_o_coap a buffer containing a CoAP packet
575  *@param	buf_o_coap_len length of the CoAP buffer
576  *@param	buf_oscore a buffer where the OSCORE packet will be written
577  *@param	buf_oscore_len length of the OSCORE packet
578  *@param	c a struct containing the OSCORE context
579  *
580  *@return	err
581  */
coap2oscore(uint8_t * buf_o_coap,uint32_t buf_o_coap_len,uint8_t * buf_oscore,uint32_t * buf_oscore_len,struct context * c)582 enum err coap2oscore(uint8_t *buf_o_coap, uint32_t buf_o_coap_len,
583 		     uint8_t *buf_oscore, uint32_t *buf_oscore_len,
584 		     struct context *c)
585 {
586 	struct o_coap_packet o_coap_pkt;
587 	struct byte_array buf;
588 	uint32_t plaintext_len = 0;
589 
590 	PRINT_MSG("\n\n\ncoap2oscore***************************************\n");
591 	PRINT_ARRAY("Input CoAP packet", buf_o_coap, buf_o_coap_len);
592 
593 	buf.len = buf_o_coap_len;
594 	buf.ptr = buf_o_coap;
595 
596 	/* Make sure that given context is fresh enough to process the message. */
597 	TRY(check_context_freshness(c));
598 
599 	/* Parse the coap buf into a CoAP struct */
600 	memset(&o_coap_pkt, 0, sizeof(o_coap_pkt));
601 	TRY(coap_deserialize(&buf, &o_coap_pkt));
602 
603 	/* Dismiss OSCORE encryption if messaging layer detected (simple ACK, code=0.00) */
604 	if ((TYPE_ACK == o_coap_pkt.header.type) &&
605 	    (CODE_EMPTY == o_coap_pkt.header.code)) {
606 		PRINT_MSG(
607 			"Messaging Layer CoAP packet detected, encryption dismissed\n");
608 		*buf_oscore_len = buf_o_coap_len;
609 		return _memcpy_s(buf_oscore, buf_o_coap_len, buf_o_coap,
610 				 buf_o_coap_len);
611 	}
612 
613 	/* 1. Divide CoAP options into E-option and U-option */
614 	struct o_coap_option e_options[MAX_OPTION_COUNT];
615 	uint8_t e_options_cnt = 0;
616 	uint16_t e_options_len = 0;
617 	struct o_coap_option u_options[MAX_OPTION_COUNT];
618 	uint8_t u_options_cnt = 0;
619 
620 	/* Analyze CoAP options, extract E-options and U-options */
621 	TRY(inner_outer_option_split(&o_coap_pkt, e_options, &e_options_cnt,
622 				     &e_options_len, u_options,
623 				     &u_options_cnt));
624 
625 	/* 2. Create plaintext (code + E-options + o_coap_payload) */
626 	/* Calculate complete plaintext length: 1 byte code + E-options + 1 byte 0xFF + payload */
627 	plaintext_len = (uint32_t)(1 + e_options_len);
628 
629 	if (o_coap_pkt.payload.len) {
630 		plaintext_len = plaintext_len + 1 + o_coap_pkt.payload.len;
631 	}
632 
633 	/* Setup buffer for plaintext */
634 	BYTE_ARRAY_NEW(plaintext, MAX_PLAINTEXT_LEN, plaintext_len);
635 
636 	/* Combine code, E-options and payload of CoAP to plaintext */
637 	TRY(plaintext_setup(&o_coap_pkt, e_options, e_options_cnt, &plaintext));
638 
639 	/* Generate ciphertext array */
640 	BYTE_ARRAY_NEW(ciphertext, MAX_CIPHERTEXT_LEN,
641 		       plaintext.len + AUTH_TAG_LEN);
642 
643 	if (ECHO_VERIFY == c->rrc.echo_state_machine) {
644 		/* A server prepares a response with ECHO challenge after the reboot. */
645 		TRY(cache_echo_val(&c->rrc.echo_opt_val, e_options,
646 				   e_options_cnt));
647 	}
648 
649 	/* Encrypt data using either a freshly generated nonce (if needed), or the one cached from the corresponding request. */
650 	struct oscore_option oscore_option;
651 	TRY(encrypt_wrapper(&plaintext, &ciphertext, c, &o_coap_pkt,
652 			    &oscore_option));
653 
654 	/*create an OSCORE packet*/
655 	struct o_coap_packet oscore_pkt;
656 	TRY(oscore_pkg_generate(&o_coap_pkt, &oscore_pkt, u_options,
657 				u_options_cnt, &ciphertext, &oscore_option));
658 
659 	/*convert the oscore pkg to byte string*/
660 	return coap_serialize(&oscore_pkt, buf_oscore, buf_oscore_len);
661 }
662