LCOV - code coverage report
Current view: top level - src/oscore - oscore_coap.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 213 217 98.2 %
Date: 2024-09-16 20:15:30 Functions: 7 7 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 72 90 80.0 %

           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/oscore_coap.h"
      19                 :            : #include "oscore/option.h"
      20                 :            : 
      21                 :            : #include "common/oscore_edhoc_error.h"
      22                 :            : #include "common/memcpy_s.h"
      23                 :            : #include "common/print_util.h"
      24                 :            : #include "common/unit_test.h"
      25                 :            : 
      26                 :            : #define OSCORE_OBSERVE_REGISTRATION_VALUE 0
      27                 :            : #define OSCORE_OBSERVE_CANCELLATION_VALUE 1
      28                 :            : 
      29                 :        218 : uint8_t opt_extra_bytes(uint16_t delta_or_len)
      30                 :            : {
      31         [ +  + ]:        218 :         if (delta_or_len < 13) {
      32                 :        181 :                 return 0;
      33                 :            :         }
      34                 :            : 
      35         [ +  + ]:         37 :         if (delta_or_len < 269) {
      36                 :         31 :                 return 1;
      37                 :            :         }
      38                 :            : 
      39                 :          6 :         return 2;
      40                 :            : }
      41                 :            : 
      42                 :         65 : enum err options_serialize(struct o_coap_option *options, uint8_t options_cnt,
      43                 :            :                            struct byte_array *out)
      44                 :            : {
      45                 :         65 :         uint8_t delta_extra_byte = 0;
      46                 :         65 :         uint8_t len_extra_byte = 0;
      47                 :         65 :         uint8_t *temp_ptr = out->ptr;
      48                 :            :         uint8_t *header_byte;
      49                 :            : 
      50                 :            :         /* Reset length */
      51                 :         65 :         uint32_t out_capacity = out->len;
      52                 :         65 :         out->len = 0;
      53                 :            : 
      54         [ +  + ]:        142 :         for (uint8_t i = 0; i < options_cnt; i++) {
      55                 :         77 :                 delta_extra_byte = opt_extra_bytes(options[i].delta);
      56                 :         77 :                 len_extra_byte = opt_extra_bytes(options[i].len);
      57                 :            : 
      58                 :         77 :                 header_byte = temp_ptr;
      59                 :         77 :                 *header_byte = 0;
      60                 :            : 
      61   [ +  +  +  - ]:         77 :                 switch (delta_extra_byte) {
      62                 :         54 :                 case 0:
      63                 :         54 :                         *(header_byte) = (uint8_t)(options[i].delta << 4);
      64                 :         54 :                         break;
      65                 :         20 :                 case 1:
      66                 :         20 :                         *(header_byte) = (uint8_t)(13 << 4);
      67                 :         20 :                         *(temp_ptr + 1) = (uint8_t)(options[i].delta - 13);
      68                 :         20 :                         break;
      69                 :          3 :                 case 2:
      70                 :          3 :                         *(header_byte) = (uint8_t)(14 << 4);
      71                 :          3 :                         uint16_t temp_delta =
      72                 :          3 :                                 (uint16_t)(options[i].delta - 269);
      73                 :          3 :                         *(temp_ptr + 1) = (uint8_t)((temp_delta & 0xFF00) >> 8);
      74                 :          3 :                         *(temp_ptr + 2) = (uint8_t)((temp_delta & 0x00FF) >> 0);
      75                 :          3 :                         break;
      76                 :            :                 }
      77                 :            : 
      78   [ +  +  +  - ]:         77 :                 switch (len_extra_byte) {
      79                 :         71 :                 case 0:
      80                 :         71 :                         *(header_byte) |= (uint8_t)(options[i].len);
      81                 :         71 :                         break;
      82                 :          3 :                 case 1:
      83                 :          3 :                         *(header_byte) |= 13;
      84                 :          3 :                         *(temp_ptr + delta_extra_byte + 1) =
      85                 :          3 :                                 (uint8_t)(options[i].len - 13);
      86                 :          3 :                         break;
      87                 :          3 :                 case 2:
      88                 :          3 :                         *(header_byte) |= 14;
      89                 :          3 :                         uint16_t temp_len = (uint16_t)(options[i].len - 269);
      90                 :          3 :                         *(temp_ptr + delta_extra_byte + 1) =
      91                 :          3 :                                 (uint8_t)((temp_len & 0xFF00) >> 8);
      92                 :          3 :                         *(temp_ptr + delta_extra_byte + 2) =
      93                 :          3 :                                 (uint8_t)((temp_len & 0x00FF) >> 0);
      94                 :          3 :                         break;
      95                 :            :                 }
      96                 :            : 
      97                 :            :                 /* Move to the position, where option value begins */
      98                 :         77 :                 temp_ptr += 1 + delta_extra_byte + len_extra_byte;
      99                 :            :                 /* Add length of current option*/
     100                 :         77 :                 out->len = (uint32_t)(out->len + 1 + delta_extra_byte +
     101                 :         77 :                                       len_extra_byte + options[i].len);
     102                 :            :                 /* Copy the byte string of current option into output*/
     103         [ +  + ]:         77 :                 if (0 != options[i].len) {
     104                 :         70 :                         uint32_t dest_size =
     105                 :         70 :                                 out_capacity - (uint32_t)(temp_ptr - out->ptr);
     106         [ -  + ]:         70 :                         TRY(_memcpy_s(temp_ptr, dest_size, options[i].value,
     107                 :            :                                       options[i].len));
     108                 :            : 
     109                 :         70 :                         temp_ptr += options[i].len;
     110                 :            :                 }
     111                 :            :         }
     112                 :         65 :         return ok;
     113                 :            : }
     114                 :            : 
     115                 :         69 : enum err options_deserialize(struct byte_array *in_data,
     116                 :            :                              struct o_coap_option *opt, uint8_t *opt_cnt,
     117                 :            :                              struct byte_array *payload)
     118                 :            : {
     119                 :         69 :         uint8_t *temp_options_ptr = in_data->ptr;
     120                 :         69 :         uint8_t temp_options_count = 0;
     121                 :         69 :         uint8_t temp_option_header_len = 0;
     122                 :         69 :         uint16_t temp_option_delta = 0;
     123                 :         69 :         uint16_t temp_option_len = 0;
     124                 :         69 :         uint16_t temp_option_number = 0;
     125                 :            : 
     126         [ +  + ]:         69 :         if (0 == in_data->len) {
     127                 :          7 :                 payload->len = 0;
     128                 :          7 :                 payload->ptr = NULL;
     129                 :          7 :                 *opt_cnt = 0;
     130                 :          7 :                 return ok;
     131                 :            :         }
     132                 :            : 
     133                 :            :         /* Go through the in_data to find out how many options are there */
     134                 :         62 :         uint16_t i = 0;
     135         [ +  + ]:        157 :         while (i < in_data->len) {
     136         [ +  + ]:        119 :                 if (OPTION_PAYLOAD_MARKER == in_data->ptr[i]) {
     137         [ +  + ]:         21 :                         if ((in_data->len - i) < 2) {
     138                 :          1 :                                 return not_valid_input_packet;
     139                 :            :                         }
     140                 :         20 :                         i++;
     141                 :         20 :                         payload->len = (uint32_t)in_data->len - i;
     142                 :         20 :                         payload->ptr = &in_data->ptr[i];
     143                 :         20 :                         return ok;
     144                 :            :                 }
     145                 :            : 
     146                 :         98 :                 temp_option_header_len = 1;
     147                 :            :                 /* Parser first byte,lower 4 bits for option value length and higher 4 bits for option delta*/
     148                 :         98 :                 temp_option_delta = ((*temp_options_ptr) & 0xF0) >> 4;
     149                 :         98 :                 temp_option_len = (*temp_options_ptr) & 0x0F;
     150                 :            : 
     151                 :         98 :                 temp_options_ptr++;
     152                 :            : 
     153                 :            :                 /* Special cases for extended option delta: 13 - 1 extra delta byte, 14 - 2 extra delta bytes, 15 - reserved */
     154   [ +  +  +  + ]:         98 :                 switch (temp_option_delta) {
     155                 :         19 :                 case 13:
     156                 :         19 :                         temp_option_header_len =
     157                 :            :                                 (uint8_t)(temp_option_header_len + 1);
     158                 :         19 :                         temp_option_delta = (uint8_t)(*temp_options_ptr + 13);
     159                 :         19 :                         temp_options_ptr += 1;
     160                 :         19 :                         break;
     161                 :          3 :                 case 14:
     162                 :          3 :                         temp_option_header_len =
     163                 :            :                                 (uint8_t)(temp_option_header_len + 2);
     164                 :          3 :                         temp_option_delta =
     165                 :          3 :                                 (uint16_t)(((*temp_options_ptr) << 8) |
     166                 :          3 :                                            *(temp_options_ptr + 1)) +
     167                 :            :                                 269;
     168                 :          3 :                         temp_options_ptr += 2;
     169                 :          3 :                         break;
     170                 :          1 :                 case 15:
     171                 :            :                         // ERROR
     172                 :          1 :                         return oscore_inpkt_invalid_option_delta;
     173                 :            :                         break;
     174                 :         75 :                 default:
     175                 :         75 :                         break;
     176                 :            :                 }
     177                 :            : 
     178                 :            :                 /* Special cases for extended option value length: 13 - 1 extra length byte, 14 - 2 extra length bytes, 15 - reserved */
     179   [ +  +  +  + ]:         97 :                 switch (temp_option_len) {
     180                 :          3 :                 case 13:
     181                 :          3 :                         temp_option_header_len =
     182                 :            :                                 (uint8_t)(temp_option_header_len + 1);
     183                 :          3 :                         temp_option_len = (uint8_t)(*temp_options_ptr + 13);
     184                 :          3 :                         temp_options_ptr += 1;
     185                 :          3 :                         break;
     186                 :          3 :                 case 14:
     187                 :          3 :                         temp_option_header_len =
     188                 :            :                                 (uint8_t)(temp_option_header_len + 2);
     189                 :          3 :                         temp_option_len =
     190                 :          3 :                                 (uint16_t)(((*temp_options_ptr) << 8) |
     191                 :          3 :                                            (*(temp_options_ptr + 1) + 269));
     192                 :          3 :                         temp_options_ptr += 2;
     193                 :          3 :                         break;
     194                 :          1 :                 case 15:
     195                 :            :                         /* ERROR */
     196                 :          1 :                         return oscore_inpkt_invalid_optionlen;
     197                 :            :                         break;
     198                 :         90 :                 default:
     199                 :         90 :                         break;
     200                 :            :                 }
     201                 :            : 
     202                 :         96 :                 temp_option_number = temp_option_number + temp_option_delta;
     203                 :            :                 /* Update in output options */
     204                 :         96 :                 opt[temp_options_count].delta = temp_option_delta;
     205                 :         96 :                 opt[temp_options_count].len = temp_option_len;
     206                 :         96 :                 opt[temp_options_count].option_number = temp_option_number;
     207         [ +  + ]:         96 :                 if (temp_option_len == 0)
     208                 :         26 :                         opt[temp_options_count].value = NULL;
     209                 :            :                 else
     210                 :         70 :                         opt[temp_options_count].value = temp_options_ptr;
     211                 :            : 
     212                 :            :                 /* Update parameters*/
     213                 :         96 :                 i = (uint16_t)(i + temp_option_header_len + temp_option_len);
     214                 :         96 :                 temp_options_ptr += temp_option_len;
     215         [ +  + ]:         96 :                 if ((MAX_OPTION_COUNT - 1) > temp_options_count) {
     216                 :         95 :                         temp_options_count++;
     217                 :            :                 } else {
     218                 :          1 :                         return too_many_options;
     219                 :            :                 }
     220                 :         95 :                 *opt_cnt = temp_options_count;
     221                 :            :         }
     222                 :         38 :         return ok;
     223                 :            : }
     224                 :            : 
     225                 :         37 : enum err coap_deserialize(struct byte_array *in, struct o_coap_packet *out)
     226                 :            : {
     227                 :         37 :         uint8_t *tmp_p = in->ptr;
     228                 :         37 :         uint32_t payload_len = in->len;
     229                 :            : 
     230                 :            :         /* Read CoAP/OSCORE header (4 bytes)*/
     231         [ +  + ]:         37 :         if (payload_len < HEADER_LEN) {
     232                 :          1 :                 return not_valid_input_packet;
     233                 :            :         }
     234                 :         36 :         out->options_cnt = 0;
     235                 :         36 :         out->header.ver =
     236                 :         36 :                 ((*tmp_p) & HEADER_VERSION_MASK) >> HEADER_VERSION_OFFSET;
     237                 :         36 :         out->header.type = ((*tmp_p) & HEADER_TYPE_MASK) >> HEADER_TYPE_OFFSET;
     238                 :         36 :         out->header.TKL = ((*tmp_p) & HEADER_TKL_MASK) >> HEADER_TKL_OFFSET;
     239                 :         36 :         out->header.code = *(tmp_p + 1);
     240                 :         36 :         uint16_t mid_l = *(tmp_p + 3);
     241                 :         36 :         uint16_t mid_h = *(tmp_p + 2);
     242                 :         36 :         out->header.MID = (uint16_t)(mid_h << 8 | mid_l);
     243                 :            : 
     244                 :            :         /* Update pointer and length*/
     245                 :         36 :         tmp_p += 4;
     246                 :         36 :         payload_len -= 4;
     247                 :            : 
     248                 :            :         /*Read the token, if it exists*/
     249         [ +  + ]:         36 :         if (out->header.TKL == 0) {
     250                 :          2 :                 out->token = NULL;
     251         [ +  + ]:         34 :         } else if (out->header.TKL <= 8) {
     252         [ +  + ]:         33 :                 if (out->header.TKL <= payload_len) {
     253                 :         32 :                         out->token = tmp_p;
     254                 :            :                 } else {
     255                 :          1 :                         return oscore_inpkt_invalid_tkl;
     256                 :            :                 }
     257                 :            :         } else {
     258                 :            :                 /* ERROR: CoAP token length maximal 8 bytes */
     259                 :          1 :                 return oscore_inpkt_invalid_tkl;
     260                 :            :         }
     261                 :            :         /* Update pointer and length */
     262                 :         34 :         tmp_p += out->header.TKL;
     263                 :         34 :         payload_len -= out->header.TKL;
     264                 :            : 
     265                 :         34 :         struct byte_array remaining_bytes = BYTE_ARRAY_INIT(tmp_p, payload_len);
     266         [ -  + ]:         34 :         TRY(options_deserialize(&remaining_bytes,
     267                 :            :                                 (struct o_coap_option *)&out->options,
     268                 :            :                                 &out->options_cnt, &out->payload));
     269                 :            : 
     270                 :         34 :         return ok;
     271                 :            : }
     272                 :            : 
     273                 :         36 : enum err coap_serialize(struct o_coap_packet *in, uint8_t *out_byte_string,
     274                 :            :                         uint32_t *out_byte_string_len)
     275                 :            : {
     276                 :         36 :         uint8_t *temp_out_ptr = out_byte_string;
     277                 :            : 
     278                 :            :         /* First byte in header (version + type + token length) */
     279                 :         36 :         *temp_out_ptr = (uint8_t)((in->header.ver << HEADER_VERSION_OFFSET) |
     280                 :         36 :                                   (in->header.type << HEADER_TYPE_OFFSET) |
     281                 :         36 :                                   (in->header.TKL));
     282                 :            :         /* Following 3 bytes in header (1 byte code + 2 bytes message ID)*/
     283                 :         36 :         *(temp_out_ptr + 1) = in->header.code;
     284                 :         36 :         uint16_t temp_MID = in->header.MID;
     285                 :         36 :         *(temp_out_ptr + 2) = (uint8_t)((temp_MID & 0xFF00) >> 8);
     286                 :         36 :         *(temp_out_ptr + 3) = (uint8_t)(temp_MID & 0x00FF);
     287                 :            : 
     288                 :         36 :         temp_out_ptr += 4;
     289                 :            :         /* Copy token */
     290         [ +  + ]:         36 :         if (in->header.TKL > 0) {
     291                 :         35 :                 uint32_t dest_size = *out_byte_string_len -
     292                 :         35 :                                      (uint32_t)(temp_out_ptr - out_byte_string);
     293         [ -  + ]:         35 :                 TRY(_memcpy_s(temp_out_ptr, dest_size, in->token,
     294                 :            :                               in->header.TKL));
     295                 :            : 
     296                 :         35 :                 temp_out_ptr += in->header.TKL;
     297                 :            :         }
     298                 :            : 
     299                 :            :         /* Calculate the maximal length of all options, i.e. all options have two bytes extra delta and length*/
     300                 :         36 :         uint32_t opt_bytes_len = 0;
     301         [ +  + ]:         79 :         for (uint8_t i = 0; i < in->options_cnt; i++) {
     302                 :         43 :                 opt_bytes_len += OPT_SERIAL_OVERHEAD + in->options[i].len;
     303                 :            :         }
     304                 :            : 
     305   [ -  +  +  + ]:         36 :         BYTE_ARRAY_NEW(option_byte_string, MAX_COAP_OPTIONS_LEN, opt_bytes_len);
     306                 :            : 
     307                 :            :         /* Convert all OSCORE U-options structure into byte string*/
     308         [ -  + ]:         36 :         TRY(options_serialize(in->options, in->options_cnt,
     309                 :            :                               &option_byte_string));
     310                 :            : 
     311                 :            :         /* Copy options byte string into output*/
     312                 :            : 
     313                 :         36 :         uint32_t dest_size = *out_byte_string_len -
     314                 :         36 :                              (uint32_t)(temp_out_ptr - out_byte_string);
     315         [ -  + ]:         36 :         TRY(_memcpy_s(temp_out_ptr, dest_size, option_byte_string.ptr,
     316                 :            :                       option_byte_string.len));
     317                 :            : 
     318                 :         36 :         temp_out_ptr += option_byte_string.len;
     319                 :            : 
     320                 :            :         /* Payload */
     321         [ +  + ]:         36 :         if (in->payload.len != 0) {
     322                 :         18 :                 *temp_out_ptr = OPTION_PAYLOAD_MARKER;
     323                 :            : 
     324                 :         18 :                 dest_size = *out_byte_string_len -
     325                 :         18 :                             (uint32_t)(temp_out_ptr + 1 - out_byte_string);
     326         [ -  + ]:         18 :                 TRY(_memcpy_s(++temp_out_ptr, dest_size, in->payload.ptr,
     327                 :            :                               in->payload.len));
     328                 :            :         }
     329                 :         36 :         *out_byte_string_len =
     330                 :         36 :                 (uint32_t)4 + in->header.TKL + option_byte_string.len;
     331         [ +  + ]:         36 :         if (in->payload.len) {
     332                 :         18 :                 *out_byte_string_len += 1 + in->payload.len;
     333                 :            :         }
     334                 :            : 
     335                 :         36 :         PRINT_ARRAY("Byte string of the converted packet", out_byte_string,
     336                 :            :                     *out_byte_string_len);
     337                 :         36 :         return ok;
     338                 :            : }
     339                 :            : 
     340                 :         78 : bool is_request(struct o_coap_packet *packet)
     341                 :            : {
     342         [ +  + ]:         78 :         if ((CODE_CLASS_MASK & packet->header.code) == REQUEST_CLASS) {
     343                 :         44 :                 return true;
     344                 :            :         } else {
     345                 :         34 :                 return false;
     346                 :            :         }
     347                 :            : }
     348                 :            : 
     349                 :         41 : enum err coap_get_message_type(struct o_coap_packet *coap_packet,
     350                 :            :                                enum o_coap_msg *msg_type)
     351                 :            : {
     352   [ +  -  -  + ]:         41 :         if ((NULL == coap_packet) || (NULL == msg_type)) {
     353                 :          0 :                 return wrong_parameter;
     354                 :            :         }
     355                 :            : 
     356                 :            :         enum o_coap_msg result;
     357                 :            :         struct byte_array observe;
     358                 :         41 :         bool observe_valid = get_observe_value(
     359                 :         41 :                 coap_packet->options, coap_packet->options_cnt, &observe);
     360                 :         41 :         bool request = is_request(coap_packet);
     361         [ +  + ]:         41 :         if (request) {
     362                 :            :                 // packet can be a request, a registration or a cancellation
     363                 :         23 :                 result = COAP_MSG_REQUEST;
     364         [ +  + ]:         23 :                 if (observe_valid) {
     365         [ +  - ]:          3 :                         if ((0 == observe.len) ||
     366         [ +  - ]:          3 :                             ((1 == observe.len) &&
     367                 :            :                              (OSCORE_OBSERVE_REGISTRATION_VALUE ==
     368         [ +  - ]:          3 :                               observe.ptr[0]))) {
     369                 :            :                                 /* Empty uint option is interpreted as a value 0.
     370                 :            :                                    For more info, see RFC 7252 section 3.2. */
     371                 :          3 :                                 result = COAP_MSG_REGISTRATION;
     372         [ #  # ]:          0 :                         } else if ((1 == observe.len) &&
     373                 :            :                                    (OSCORE_OBSERVE_CANCELLATION_VALUE ==
     374         [ #  # ]:          0 :                                     observe.ptr[0])) {
     375                 :          0 :                                 result = COAP_MSG_CANCELLATION;
     376                 :            :                         }
     377                 :            :                 }
     378                 :            :         } else {
     379                 :            :                 // packet can be a regular response or a notification
     380         [ +  + ]:         18 :                 result = (observe_valid ? COAP_MSG_NOTIFICATION :
     381                 :            :                                           COAP_MSG_RESPONSE);
     382                 :            :         }
     383                 :            : 
     384                 :         41 :         *msg_type = result;
     385                 :         41 :         return ok;
     386                 :            : }

Generated by: LCOV version 1.14