LCOV - code coverage report
Current view: top level - src/oscore - coap2oscore.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 256 257 99.6 %
Date: 2024-09-16 20:15:30 Functions: 9 9 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 99 136 72.8 %

           Branch data     Line data    Source code
       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                 :            :  */
      43                 :         20 : 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                 :         20 :         enum err r = ok;
      51                 :            : 
      52                 :            :         /* Initialize to 0 */
      53                 :         20 :         *e_options_len = 0;
      54                 :            : 
      55                 :         20 :         uint8_t temp_option_nr = 0;
      56                 :         20 :         uint16_t temp_len = 0;
      57                 :         20 :         uint8_t temp_E_option_delta_sum = 0;
      58                 :         20 :         uint8_t temp_U_option_delta_sum = 0;
      59                 :            : 
      60         [ +  + ]:         20 :         if (MAX_OPTION_COUNT < in_o_coap->options_cnt) {
      61                 :          1 :                 return too_many_options;
      62                 :            :         }
      63                 :            : 
      64         [ +  + ]:         51 :         for (uint8_t i = 0; i < in_o_coap->options_cnt; i++) {
      65                 :         32 :                 uint8_t extra_bytes =
      66                 :         32 :                         opt_extra_bytes(in_o_coap->options[i].delta) +
      67                 :         32 :                         opt_extra_bytes(in_o_coap->options[i].len);
      68                 :            : 
      69                 :         32 :                 temp_option_nr =
      70                 :         32 :                         (uint8_t)(temp_option_nr + in_o_coap->options[i].delta);
      71                 :         32 :                 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         [ +  + ]:         32 :                 switch (temp_option_nr) {
      78                 :          4 :                 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                 :          4 :                         e_options[*e_options_cnt].delta =
      87                 :          4 :                                 (uint16_t)(temp_option_nr -
      88                 :            :                                            temp_E_option_delta_sum);
      89         [ +  + ]:          4 :                         if (is_request(in_o_coap)) {
      90                 :            :                                 /*registrations/cancellations are requests */
      91                 :          2 :                                 e_options[*e_options_cnt].len = temp_len;
      92                 :          2 :                                 e_options[*e_options_cnt].value =
      93                 :          2 :                                         in_o_coap->options[i].value;
      94                 :            : 
      95                 :            :                                 /* Add option header length and value length */
      96                 :          2 :                                 (*e_options_len) =
      97                 :          2 :                                         (uint16_t)((*e_options_len) + 1 +
      98                 :          2 :                                                    extra_bytes + temp_len);
      99                 :            :                         } else {
     100                 :            :                                 /*notifications are responses*/
     101                 :          2 :                                 e_options[*e_options_cnt].len = 0;
     102                 :          2 :                                 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                 :          2 :                                 (*e_options_len)++;
     106                 :            :                         }
     107                 :            : 
     108                 :          4 :                         e_options[*e_options_cnt].option_number =
     109                 :            :                                 temp_option_nr;
     110                 :            : 
     111                 :            :                         /* Update delta sum of E-options */
     112                 :          4 :                         temp_E_option_delta_sum =
     113                 :          4 :                                 (uint8_t)(temp_E_option_delta_sum +
     114                 :          4 :                                           e_options[*e_options_cnt].delta);
     115                 :            : 
     116                 :            :                         /* Increment E-options count */
     117                 :          4 :                         (*e_options_cnt)++;
     118                 :            : 
     119                 :            :                         /*
     120                 :            :                         *outer option (value as in the original coap packet
     121                 :            :                         */
     122                 :          4 :                         U_options[*U_options_cnt].delta =
     123                 :          4 :                                 (uint16_t)(temp_option_nr -
     124                 :            :                                            temp_U_option_delta_sum);
     125                 :          4 :                         U_options[*U_options_cnt].len = temp_len;
     126                 :          4 :                         U_options[*U_options_cnt].value =
     127                 :          4 :                                 in_o_coap->options[i].value;
     128                 :          4 :                         U_options[*U_options_cnt].option_number =
     129                 :            :                                 temp_option_nr;
     130                 :            : 
     131                 :            :                         /* Update delta sum of E-options */
     132                 :          4 :                         temp_U_option_delta_sum =
     133                 :          4 :                                 (uint8_t)(temp_U_option_delta_sum +
     134                 :          4 :                                           U_options[*U_options_cnt].delta);
     135                 :            : 
     136                 :            :                         /* Increment E-options count */
     137                 :          4 :                         (*U_options_cnt)++;
     138                 :            : 
     139                 :          4 :                         break;
     140                 :            : 
     141                 :         28 :                 default:
     142                 :            :                         /* check delta, whether current option U or E */
     143         [ +  + ]:         28 :                         if (is_class_e(temp_option_nr) == 1) {
     144                 :            :                                 /* E-options, which will be copied in plaintext to be encrypted*/
     145                 :         22 :                                 e_options[*e_options_cnt].delta =
     146                 :         22 :                                         (uint16_t)(temp_option_nr -
     147                 :            :                                                    temp_E_option_delta_sum);
     148                 :         22 :                                 e_options[*e_options_cnt].len = temp_len;
     149                 :         22 :                                 e_options[*e_options_cnt].value =
     150                 :         22 :                                         in_o_coap->options[i].value;
     151                 :         22 :                                 e_options[*e_options_cnt].option_number =
     152                 :            :                                         temp_option_nr;
     153                 :            : 
     154                 :            :                                 /* Update delta sum of E-options */
     155                 :         22 :                                 temp_E_option_delta_sum =
     156                 :         22 :                                         (uint8_t)(temp_E_option_delta_sum +
     157                 :         22 :                                                   e_options[*e_options_cnt]
     158                 :         22 :                                                           .delta);
     159                 :            : 
     160                 :            :                                 /* Increment E-options count */
     161                 :         22 :                                 (*e_options_cnt)++;
     162                 :            :                                 /* Add option header length and value length */
     163                 :         22 :                                 (*e_options_len) =
     164                 :         22 :                                         (uint16_t)((*e_options_len) + 1 +
     165                 :         22 :                                                    extra_bytes + temp_len);
     166                 :            :                         } else {
     167                 :            :                                 /* U-options */
     168                 :          6 :                                 U_options[*U_options_cnt].delta =
     169                 :          6 :                                         (uint16_t)(temp_option_nr -
     170                 :            :                                                    temp_U_option_delta_sum);
     171                 :          6 :                                 U_options[*U_options_cnt].len = temp_len;
     172                 :          6 :                                 U_options[*U_options_cnt].value =
     173                 :          6 :                                         in_o_coap->options[i].value;
     174                 :          6 :                                 U_options[*U_options_cnt].option_number =
     175                 :            :                                         temp_option_nr;
     176                 :            : 
     177                 :            :                                 /* Update delta sum of E-options */
     178                 :          6 :                                 temp_U_option_delta_sum =
     179                 :          6 :                                         (uint8_t)(temp_U_option_delta_sum +
     180                 :          6 :                                                   U_options[*U_options_cnt]
     181                 :          6 :                                                           .delta);
     182                 :            : 
     183                 :            :                                 /* Increment E-options count */
     184                 :          6 :                                 (*U_options_cnt)++;
     185                 :            :                         }
     186                 :         28 :                         break;
     187                 :            :                 }
     188                 :            :         }
     189                 :         19 :         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                 :            :  */
     201                 :         16 : 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                 :         16 :         uint8_t *temp_plaintext_ptr = plaintext->ptr;
     207                 :            : 
     208                 :            :         /* Add code to plaintext */
     209                 :         16 :         *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                 :         16 :         uint16_t e_opt_serial_len = 0;
     214         [ +  + ]:         31 :         for (uint8_t i = 0; i < E_options_cnt; i++) {
     215                 :         15 :                 e_opt_serial_len = (uint16_t)(e_opt_serial_len + 1 + 2 + 2 +
     216                 :         15 :                                               E_options[i].len);
     217                 :            :         }
     218                 :            :         /* Setup buffer */
     219         [ -  + ]:         16 :         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         [ -  + ]:         16 :         TRY(options_serialize(E_options, E_options_cnt, &e_opt_serial));
     225                 :            : 
     226                 :         16 :         uint32_t dest_size = (plaintext->len - (uint32_t)(temp_plaintext_ptr +
     227                 :         16 :                                                           1 - plaintext->ptr));
     228         [ -  + ]:         16 :         TRY(_memcpy_s(++temp_plaintext_ptr, dest_size, e_opt_serial.ptr,
     229                 :            :                       e_opt_serial.len));
     230                 :         16 :         temp_plaintext_ptr += e_opt_serial.len;
     231                 :            : 
     232                 :            :         /* Add payload to plaintext*/
     233         [ +  + ]:         16 :         if (in_o_coap->payload.len != 0) {
     234                 :            :                 /* An extra byte 0xFF before payload*/
     235                 :          2 :                 *temp_plaintext_ptr = 0xff;
     236                 :            : 
     237                 :          2 :                 dest_size = (plaintext->len - (uint32_t)(temp_plaintext_ptr +
     238                 :          2 :                                                          1 - plaintext->ptr));
     239         [ -  + ]:          2 :                 TRY(_memcpy_s(++temp_plaintext_ptr, dest_size,
     240                 :            :                               in_o_coap->payload.ptr, in_o_coap->payload.len));
     241                 :            :         }
     242                 :         16 :         PRINT_ARRAY("Plain text", plaintext->ptr, plaintext->len);
     243                 :         16 :         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                 :            :  */
     253                 :         16 : 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                 :         16 :         uint32_t length = piv_len + kid_len + kid_context_len;
     258         [ +  + ]:         16 :         if (length) {
     259                 :            :                 /*if any of piv, kid_context or kid is present 1 byte for the flags is reserved */
     260                 :         14 :                 length++;
     261                 :            :         }
     262         [ +  + ]:         16 :         if (kid_context_len) {
     263                 :            :                 /*if kid_context is present one byte is reserved for the s field*/
     264                 :          2 :                 length++;
     265                 :            :         }
     266                 :         16 :         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                 :            :  */
     279                 :         16 : 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         [ +  - ]:         16 :         uint32_t piv_len = (NULL == piv) ? 0 : piv->len;
     285         [ +  - ]:         16 :         uint32_t kid_len = (NULL == kid) ? 0 : kid->len;
     286         [ +  - ]:         16 :         uint32_t kid_context_len = (NULL == kid_context) ? 0 : kid_context->len;
     287                 :            : 
     288                 :         16 :         oscore_option->option_number = OSCORE;
     289                 :         16 :         oscore_option->len = (uint8_t)get_oscore_opt_val_len(piv_len, kid_len,
     290                 :            :                                                              kid_context_len);
     291         [ -  + ]:         16 :         TRY(check_buffer_size(OSCORE_OPT_VALUE_LEN, oscore_option->len));
     292                 :         16 :         oscore_option->value = oscore_option->buf;
     293                 :            : 
     294                 :            :         uint32_t dest_size;
     295                 :            : 
     296         [ +  + ]:         16 :         if (oscore_option->len == 0) {
     297                 :          2 :                 oscore_option->value = NULL;
     298                 :            :         } else {
     299                 :         14 :                 memset(oscore_option->value, 0, oscore_option->len);
     300                 :            : 
     301                 :         14 :                 uint8_t *temp_ptr = oscore_option->value;
     302                 :            : 
     303         [ +  + ]:         14 :                 if (piv_len != 0) {
     304                 :            :                         /* Set header bits of PIV */
     305                 :         13 :                         oscore_option->value[0] =
     306                 :         13 :                                 (uint8_t)(oscore_option->value[0] | piv->len);
     307                 :            :                         /* copy PIV (sender sequence) */
     308                 :            : 
     309                 :         13 :                         dest_size = (uint32_t)(oscore_option->len -
     310                 :         13 :                                                (temp_ptr + 1 -
     311                 :         13 :                                                 oscore_option->value));
     312         [ -  + ]:         13 :                         TRY(_memcpy_s(++temp_ptr, dest_size, piv->ptr,
     313                 :            :                                       piv->len));
     314                 :            : 
     315                 :         13 :                         temp_ptr += piv->len;
     316                 :            :                 } else {
     317                 :          1 :                         temp_ptr++;
     318                 :            :                 }
     319                 :            : 
     320         [ +  + ]:         14 :                 if (kid_context_len != 0) {
     321                 :            :                         /* Set header flag bit of KID context */
     322                 :          2 :                         oscore_option->value[0] |= COMP_OSCORE_OPT_KIDC_H_MASK;
     323                 :            :                         /* Copy length and context value */
     324                 :          2 :                         *temp_ptr = (uint8_t)(kid_context->len);
     325                 :            : 
     326                 :          2 :                         dest_size = (uint32_t)(oscore_option->len -
     327                 :          2 :                                                (temp_ptr + 1 -
     328                 :          2 :                                                 oscore_option->value));
     329         [ -  + ]:          2 :                         TRY(_memcpy_s(++temp_ptr, dest_size, kid_context->ptr,
     330                 :            :                                       kid_context->len));
     331                 :            : 
     332                 :          2 :                         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                 :         14 :                 oscore_option->value[0] |= COMP_OSCORE_OPT_KID_K_MASK;
     339         [ +  + ]:         14 :                 if (kid_len != 0) {
     340                 :            :                         /* Copy KID */
     341                 :          6 :                         dest_size =
     342                 :          6 :                                 (uint32_t)(oscore_option->len -
     343                 :          6 :                                            (temp_ptr - oscore_option->value));
     344         [ -  + ]:          6 :                         TRY(_memcpy_s(temp_ptr, dest_size, kid->ptr, kid->len));
     345                 :            :                 }
     346                 :            :         }
     347                 :            : 
     348                 :         16 :         PRINT_ARRAY("OSCORE option value", oscore_option->value,
     349                 :            :                     oscore_option->len);
     350                 :         16 :         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                 :            :  */
     364                 :         17 : 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                 :         17 :         out_oscore->header.ver = in_o_coap->header.ver;
     373                 :         17 :         out_oscore->header.type = in_o_coap->header.type;
     374                 :         17 :         out_oscore->header.TKL = in_o_coap->header.TKL;
     375                 :         17 :         out_oscore->header.MID = in_o_coap->header.MID;
     376         [ +  + ]:         17 :         if (out_oscore->header.TKL == 0) {
     377                 :          2 :                 out_oscore->token = NULL;
     378                 :            :         } else {
     379                 :         15 :                 out_oscore->token = in_o_coap->token;
     380                 :            :         }
     381                 :            : 
     382                 :         17 :         bool observe = is_observe(u_options, u_options_cnt);
     383         [ +  + ]:         17 :         if (is_request(in_o_coap)) {
     384         [ +  + ]:         10 :                 if (observe) {
     385                 :          2 :                         out_oscore->header.code = CODE_REQ_FETCH;
     386                 :            :                 } else {
     387                 :          8 :                         out_oscore->header.code = CODE_REQ_POST;
     388                 :            :                 }
     389                 :            :         } else {
     390         [ +  + ]:          7 :                 if (observe) {
     391                 :          2 :                         out_oscore->header.code = CODE_RESP_CONTENT;
     392                 :            :                 } else {
     393                 :          5 :                         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                 :         17 :         uint8_t oscore_opt_pos = u_options_cnt;
     400         [ +  + ]:         24 :         for (uint8_t i = 0; i < u_options_cnt; i++) {
     401                 :            :                 /* Once found, finish the for-loop */
     402         [ +  + ]:          8 :                 if (u_options[i].option_number > OSCORE) {
     403                 :          1 :                         oscore_opt_pos = i;
     404                 :          1 :                         break;
     405                 :            :                 }
     406                 :            :         }
     407                 :            : 
     408                 :            :         /* Update options count number to output*/
     409                 :         17 :         out_oscore->options_cnt = (uint8_t)(1 + u_options_cnt);
     410                 :            : 
     411                 :         17 :         uint8_t temp_opt_number_sum = 0;
     412                 :            :         /* Show the position of U-options */
     413                 :         17 :         uint8_t u_opt_pos = 0;
     414         [ +  + ]:         42 :         for (uint8_t i = 0; i < u_options_cnt + 1; i++) {
     415         [ +  + ]:         25 :                 if (i == oscore_opt_pos) {
     416                 :            :                         /* OSCORE_option */
     417                 :         17 :                         out_oscore->options[i].delta =
     418                 :         17 :                                 (uint16_t)(oscore_option->option_number -
     419                 :            :                                            temp_opt_number_sum);
     420                 :         17 :                         out_oscore->options[i].len = oscore_option->len;
     421                 :         17 :                         out_oscore->options[i].option_number =
     422                 :         17 :                                 oscore_option->option_number;
     423                 :         17 :                         out_oscore->options[i].value = oscore_option->value;
     424                 :            :                 } else {
     425                 :            :                         /* U-options */
     426                 :          8 :                         out_oscore->options[i].delta =
     427                 :          8 :                                 (uint16_t)(u_options[u_opt_pos].option_number -
     428                 :            :                                            temp_opt_number_sum);
     429                 :          8 :                         out_oscore->options[i].len = u_options[u_opt_pos].len;
     430                 :          8 :                         out_oscore->options[i].option_number =
     431                 :          8 :                                 u_options[u_opt_pos].option_number;
     432                 :          8 :                         out_oscore->options[i].value =
     433                 :          8 :                                 u_options[u_opt_pos].value;
     434                 :            : 
     435                 :          8 :                         u_opt_pos++;
     436                 :            :                 }
     437                 :         25 :                 temp_opt_number_sum = (uint8_t)(temp_opt_number_sum +
     438                 :         25 :                                                 out_oscore->options[i].delta);
     439                 :            :         }
     440                 :            : 
     441                 :            :         /* Protected Payload */
     442                 :         17 :         out_oscore->payload.len = in_ciphertext->len;
     443                 :         17 :         out_oscore->payload.ptr = in_ciphertext->ptr;
     444                 :         17 :         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                 :            :  */
     453                 :         13 : static enum err generate_new_ssn(struct context *c)
     454                 :            : {
     455         [ -  + ]:         13 :         if (NULL == c) {
     456                 :          0 :                 return wrong_parameter;
     457                 :            :         }
     458                 :            : 
     459                 :         13 :         c->sc.ssn++;
     460         [ +  + ]:         13 :         if (!c->cc.fresh_master_secret_salt) {
     461                 :            : #ifdef OSCORE_NVM_SUPPORT
     462                 :          9 :                 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                 :          9 :                 bool echo_sync_in_progress =
     466                 :          9 :                         (ECHO_SYNCHRONIZED != c->rrc.echo_state_machine);
     467                 :          9 :                 return ssn_store_in_nvm(&nvm_key, c->sc.ssn,
     468                 :            :                                         echo_sync_in_progress);
     469                 :            : #else
     470                 :            :                 return ok;
     471                 :            : #endif
     472                 :            :         }
     473                 :          4 :         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                 :            :  */
     482                 :         15 : 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   [ +  +  +  + ]:         15 :         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                 :            :  */
     506                 :         15 : 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         [ -  + ]:         15 :         BYTE_ARRAY_NEW(new_piv, MAX_PIV_LEN, MAX_PIV_LEN);
     513         [ -  + ]:         15 :         BYTE_ARRAY_NEW(new_nonce, NONCE_LEN, NONCE_LEN);
     514                 :         15 :         struct byte_array piv = BYTE_ARRAY_INIT(NULL, 0);
     515                 :         15 :         struct byte_array kid = BYTE_ARRAY_INIT(NULL, 0);
     516                 :         15 :         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         [ -  + ]:         15 :         TRY(coap_get_message_type(input_coap, &msg_type));
     522                 :         15 :         struct byte_array token =
     523                 :         15 :                 BYTE_ARRAY_INIT(input_coap->token, input_coap->header.TKL);
     524                 :            : 
     525                 :            :         /* Generate new PIV/nonce if needed. */
     526                 :         15 :         bool use_new_piv = needs_new_piv(msg_type, c->rrc.echo_state_machine);
     527         [ +  + ]:         15 :         if (use_new_piv) {
     528         [ -  + ]:         13 :                 TRY(ssn2piv(c->sc.ssn, &new_piv));
     529         [ -  + ]:         13 :                 TRY(generate_new_ssn(c));
     530         [ -  + ]:         13 :                 TRY(create_nonce(&c->sc.sender_id, &new_piv, &c->cc.common_iv,
     531                 :            :                                  &new_nonce));
     532                 :            : 
     533                 :         13 :                 nonce = new_nonce;
     534                 :         13 :                 piv = new_piv;
     535                 :         13 :                 kid = c->sc.sender_id;
     536                 :         13 :                 kid_context = c->cc.id_context;
     537                 :            :         } else {
     538                 :          2 :                 nonce = c->rrc.nonce;
     539                 :            :         }
     540                 :            : 
     541                 :            :         /* Generate OSCORE option based on selected values. */
     542         [ -  + ]:         15 :         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         [ -  + ]:         15 :         BYTE_ARRAY_NEW(aad, MAX_AAD_LEN, MAX_AAD_LEN);
     548                 :         15 :         struct byte_array request_piv = piv;
     549                 :         15 :         struct byte_array request_kid = kid;
     550         [ -  + ]:         15 :         TRY(oscore_interactions_read_wrapper(msg_type, &token,
     551                 :            :                                              c->rrc.interactions, &request_piv,
     552                 :            :                                              &request_kid));
     553         [ -  + ]:         15 :         TRY(create_aad(NULL, 0, c->cc.aead_alg, &request_kid, &request_piv,
     554                 :            :                        &aad));
     555                 :            : 
     556                 :            :         /* Encrypt the plaintext */
     557         [ -  + ]:         15 :         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         [ +  + ]:         15 :         if (use_new_piv) {
     562         [ -  + ]:         13 :                 TRY(byte_array_cpy(&c->rrc.nonce, &nonce, NONCE_LEN));
     563                 :            :         }
     564                 :            : 
     565                 :            :         /* Handle OSCORE interactions after successful encryption. */
     566         [ -  + ]:         15 :         BYTE_ARRAY_NEW(uri_paths, OSCORE_MAX_URI_PATH_LEN,
     567                 :            :                        OSCORE_MAX_URI_PATH_LEN);
     568         [ -  + ]:         15 :         TRY(uri_path_create(input_coap->options, input_coap->options_cnt,
     569                 :            :                             uri_paths.ptr, &(uri_paths.len)));
     570         [ -  + ]:         15 :         TRY(oscore_interactions_update_wrapper(msg_type, &token, &uri_paths,
     571                 :            :                                                c->rrc.interactions,
     572                 :            :                                                &request_piv, &request_kid));
     573                 :            : 
     574                 :         15 :         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                 :            :  */
     590                 :         17 : 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                 :         17 :         uint32_t plaintext_len = 0;
     597                 :            : 
     598                 :         17 :         PRINT_MSG("\n\n\ncoap2oscore***************************************\n");
     599                 :         17 :         PRINT_ARRAY("Input CoAP packet", buf_o_coap, buf_o_coap_len);
     600                 :            : 
     601                 :         17 :         buf.len = buf_o_coap_len;
     602                 :         17 :         buf.ptr = buf_o_coap;
     603                 :            : 
     604                 :            :         /* Make sure that given context is fresh enough to process the message. */
     605         [ -  + ]:         17 :         TRY(check_context_freshness(c));
     606                 :            : 
     607                 :            :         /* Parse the coap buf into a CoAP struct */
     608                 :         17 :         memset(&o_coap_pkt, 0, sizeof(o_coap_pkt));
     609         [ -  + ]:         17 :         TRY(coap_deserialize(&buf, &o_coap_pkt));
     610                 :            : 
     611                 :            :         /* Dismiss OSCORE encryption if messaging layer detected (simple ACK, code=0.00) */
     612         [ +  + ]:         17 :         if ((TYPE_ACK == o_coap_pkt.header.type) &&
     613         [ +  + ]:          8 :             (CODE_EMPTY == o_coap_pkt.header.code)) {
     614                 :          1 :                 PRINT_MSG(
     615                 :            :                         "Messaging Layer CoAP packet detected, encryption dismissed\n");
     616                 :          1 :                 *buf_oscore_len = buf_o_coap_len;
     617                 :          1 :                 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                 :         16 :         uint8_t e_options_cnt = 0;
     624                 :         16 :         uint16_t e_options_len = 0;
     625                 :            :         struct o_coap_option u_options[MAX_OPTION_COUNT];
     626                 :         16 :         uint8_t u_options_cnt = 0;
     627                 :            : 
     628                 :            :         /* Analyze CoAP options, extract E-options and U-options */
     629         [ -  + ]:         16 :         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                 :         16 :         plaintext_len = (uint32_t)(1 + e_options_len);
     636                 :            : 
     637         [ +  + ]:         16 :         if (o_coap_pkt.payload.len) {
     638                 :          2 :                 plaintext_len = plaintext_len + 1 + o_coap_pkt.payload.len;
     639                 :            :         }
     640                 :            : 
     641                 :            :         /* Setup buffer for plaintext */
     642   [ -  +  -  + ]:         16 :         BYTE_ARRAY_NEW(plaintext, MAX_PLAINTEXT_LEN, plaintext_len);
     643                 :            : 
     644                 :            :         /* Combine code, E-options and payload of CoAP to plaintext */
     645         [ -  + ]:         16 :         TRY(plaintext_setup(&o_coap_pkt, e_options, e_options_cnt, &plaintext));
     646                 :            : 
     647                 :            :         /* Generate ciphertext array */
     648   [ -  +  -  + ]:         16 :         BYTE_ARRAY_NEW(ciphertext, MAX_CIPHERTEXT_LEN,
     649                 :            :                        plaintext.len + AUTH_TAG_LEN);
     650                 :            : 
     651         [ +  + ]:         16 :         if (ECHO_VERIFY == c->rrc.echo_state_machine) {
     652                 :            :                 /* A server prepares a response with ECHO challenge after the reboot. */
     653         [ +  + ]:          4 :                 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         [ -  + ]:         15 :         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         [ -  + ]:         15 :         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                 :         15 :         return coap_serialize(&oscore_pkt, buf_oscore, buf_oscore_len);
     669                 :            : }

Generated by: LCOV version 1.14