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