Code coverage report for DMTF/libspdm
Current view: top level - library/spdm_common_lib - libspdm_com_opaque_data.c (source / functions) Coverage Total Hit
Test: 36148b912f76d231c18d216d6dee5c0858575bb1 Lines: 89.9 % 287 258
Test Date: 2026-10-25 08:40:22 Functions: 100.0 % 14 14
Branches: 73.0 % 152 111

             Branch data     Line data    Source code
       1                 :             : /**
       2                 :             :  *  Copyright Notice:
       3                 :             :  *  Copyright 2021-2026 DMTF. All rights reserved.
       4                 :             :  *  License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md
       5                 :             :  **/
       6                 :             : 
       7                 :             : #include "internal/libspdm_common_lib.h"
       8                 :             : #include "internal/libspdm_secured_message_lib.h"
       9                 :             : 
      10                 :         576 : size_t libspdm_get_opaque_data_version_selection_data_size(const libspdm_context_t *spdm_context)
      11                 :             : {
      12                 :             :     size_t size;
      13                 :             : 
      14         [ -  + ]:         576 :     if (spdm_context->local_context.secured_message_version.secured_message_version_count == 0) {
      15                 :           0 :         return 0;
      16                 :             :     }
      17                 :             : 
      18         [ +  + ]:         576 :     if (libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_12) {
      19                 :          80 :         size = sizeof(spdm_general_opaque_data_table_header_t) +
      20                 :             :                sizeof(secured_message_opaque_element_table_header_t) +
      21                 :             :                sizeof(secured_message_opaque_element_version_selection_t);
      22                 :             :     } else {
      23                 :         496 :         size = sizeof(secured_message_general_opaque_data_table_header_t) +
      24                 :             :                sizeof(secured_message_opaque_element_table_header_t) +
      25                 :             :                sizeof(secured_message_opaque_element_version_selection_t);
      26                 :             :     }
      27                 :             :     /* Add Padding*/
      28                 :         576 :     return (size + 3) & ~3;
      29                 :             : }
      30                 :             : 
      31                 :        1082 : size_t libspdm_get_opaque_data_supported_version_data_size(libspdm_context_t *spdm_context)
      32                 :             : {
      33                 :             :     size_t size;
      34                 :             : 
      35         [ -  + ]:        1082 :     if (spdm_context->local_context.secured_message_version.secured_message_version_count == 0) {
      36                 :           0 :         return 0;
      37                 :             :     }
      38                 :             : 
      39         [ +  + ]:        1082 :     if (libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_12) {
      40                 :         136 :         size = sizeof(spdm_general_opaque_data_table_header_t) +
      41                 :             :                sizeof(secured_message_opaque_element_table_header_t) +
      42                 :             :                sizeof(secured_message_opaque_element_supported_version_t) +
      43                 :         136 :                sizeof(spdm_version_number_t) *
      44                 :         136 :                spdm_context->local_context.secured_message_version.secured_message_version_count;
      45                 :             :     } else {
      46                 :         946 :         size = sizeof(secured_message_general_opaque_data_table_header_t) +
      47                 :             :                sizeof(secured_message_opaque_element_table_header_t) +
      48                 :             :                sizeof(secured_message_opaque_element_supported_version_t) +
      49                 :         946 :                sizeof(spdm_version_number_t) *
      50                 :         946 :                spdm_context->local_context.secured_message_version.secured_message_version_count;
      51                 :             :     }
      52                 :             :     /* Add Padding*/
      53                 :        1082 :     return (size + 3) & ~3;
      54                 :             : }
      55                 :             : 
      56                 :         116 : size_t libspdm_get_untrusted_opaque_data_supported_version_data_size(
      57                 :             :     libspdm_context_t *spdm_context, uint8_t version_count)
      58                 :             : {
      59                 :             :     size_t size;
      60                 :             : 
      61         [ +  + ]:         116 :     if (libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_12) {
      62                 :          20 :         size = sizeof(spdm_general_opaque_data_table_header_t) +
      63                 :             :                sizeof(secured_message_opaque_element_table_header_t) +
      64                 :             :                sizeof(secured_message_opaque_element_supported_version_t) +
      65                 :          20 :                sizeof(spdm_version_number_t) * version_count;
      66                 :             :     } else {
      67                 :          96 :         size = sizeof(secured_message_general_opaque_data_table_header_t) +
      68                 :             :                sizeof(secured_message_opaque_element_table_header_t) +
      69                 :             :                sizeof(secured_message_opaque_element_supported_version_t) +
      70                 :          96 :                sizeof(spdm_version_number_t) * version_count;
      71                 :             :     }
      72                 :             :     /* Add Padding*/
      73                 :         116 :     return (size + 3) & ~3;
      74                 :             : }
      75                 :             : 
      76                 :         570 : bool libspdm_get_element_from_opaque_data_with_element_id (libspdm_context_t *spdm_context,
      77                 :             :                                                            size_t data_in_size, const void *data_in,
      78                 :             :                                                            uint8_t element_id, uint8_t element_index,
      79                 :             :                                                            uint8_t *total_matched_element_cnt,
      80                 :             :                                                            const void **get_element_ptr, size_t *get_element_len)
      81                 :             : {
      82                 :             :     const secured_message_general_opaque_data_table_header_t *general_opaque_data_table_header;
      83                 :             :     const spdm_general_opaque_data_table_header_t *spdm_general_opaque_data_table_header;
      84                 :             :     const opaque_element_table_header_t *opaque_element_table_header;
      85                 :             :     uint16_t opaque_element_data_len;
      86                 :             : 
      87                 :             :     bool result;
      88                 :             :     uint8_t element_num;
      89                 :             :     uint8_t index;
      90                 :             :     uint8_t matched_element_cnt;
      91                 :             :     size_t data_element_size;
      92                 :             :     size_t current_element_len;
      93                 :             :     size_t total_element_len;
      94                 :             : 
      95                 :             :     /*check parameter in*/
      96         [ -  + ]:         570 :     if (element_id > SPDM_REGISTRY_ID_MAX) {
      97                 :           0 :         return false;
      98                 :             :     }
      99   [ +  -  -  + ]:         570 :     if ((data_in_size == 0) || (data_in == NULL)) {
     100                 :           0 :         return false;
     101                 :             :     }
     102                 :             : 
     103         [ +  + ]:         570 :     if (libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_12) {
     104                 :         180 :         spdm_general_opaque_data_table_header = data_in;
     105         [ -  + ]:         180 :         if (data_in_size < sizeof(spdm_general_opaque_data_table_header_t)) {
     106                 :           0 :             return false;
     107                 :             :         }
     108         [ -  + ]:         180 :         if (spdm_general_opaque_data_table_header->total_elements < 1) {
     109                 :           0 :             return false;
     110                 :             :         }
     111                 :         180 :         opaque_element_table_header = (const void *)(spdm_general_opaque_data_table_header + 1);
     112                 :             : 
     113                 :         180 :         element_num = spdm_general_opaque_data_table_header->total_elements;
     114                 :             : 
     115                 :         180 :         data_element_size = data_in_size - sizeof(spdm_general_opaque_data_table_header_t);
     116                 :             :     } else {
     117                 :         390 :         general_opaque_data_table_header = data_in;
     118         [ -  + ]:         390 :         if (data_in_size < sizeof(secured_message_general_opaque_data_table_header_t)) {
     119                 :           0 :             return false;
     120                 :             :         }
     121         [ +  + ]:         390 :         if ((general_opaque_data_table_header->spec_id != SECURED_MESSAGE_OPAQUE_DATA_SPEC_ID) ||
     122         [ +  - ]:         388 :             (general_opaque_data_table_header->opaque_version != SECURED_MESSAGE_OPAQUE_VERSION) ||
     123         [ -  + ]:         388 :             (general_opaque_data_table_header->total_elements < 1)) {
     124                 :           2 :             return false;
     125                 :             :         }
     126                 :         388 :         opaque_element_table_header = (const void *)(general_opaque_data_table_header + 1);
     127                 :             : 
     128                 :         388 :         element_num = general_opaque_data_table_header->total_elements;
     129                 :             : 
     130                 :         388 :         data_element_size = data_in_size -
     131                 :             :                             sizeof(secured_message_general_opaque_data_table_header_t);
     132                 :             :     }
     133                 :             : 
     134                 :         568 :     total_element_len = 0;
     135                 :         568 :     result = false;
     136                 :             : 
     137                 :             :     /* find the Nth element with specific element_id, N = element_index. */
     138                 :         568 :     matched_element_cnt = 0;
     139         [ +  + ]:        1446 :     for (index = 0; index < element_num; index++) {
     140                 :             :         /*ensure the opaque_element_table_header is valid*/
     141         [ -  + ]:         888 :         if (total_element_len + sizeof(opaque_element_table_header_t) >
     142                 :             :             data_element_size) {
     143                 :           0 :             return false;
     144                 :             :         }
     145                 :             : 
     146                 :             :         /*check element header id*/
     147         [ +  + ]:         888 :         if ((opaque_element_table_header->id > SPDM_REGISTRY_ID_MAX)) {
     148                 :           8 :             return false;
     149                 :             :         }
     150                 :             : 
     151                 :         880 :         if ((total_element_len + sizeof(opaque_element_table_header_t) +
     152         [ -  + ]:         880 :              opaque_element_table_header->vendor_len + 2) > data_element_size) {
     153                 :           0 :             return false;
     154                 :             :         }
     155                 :             : 
     156                 :         880 :         opaque_element_data_len = libspdm_read_uint16(
     157                 :         880 :             (const uint8_t *)opaque_element_table_header + sizeof(opaque_element_table_header_t) +
     158                 :         880 :             opaque_element_table_header->vendor_len);
     159                 :             : 
     160                 :         880 :         current_element_len = sizeof(opaque_element_table_header_t) +
     161                 :         880 :                               opaque_element_table_header->vendor_len + 2 + opaque_element_data_len;
     162                 :             :         /* Add Padding*/
     163                 :         880 :         current_element_len = (current_element_len + 3) & ~3;
     164                 :             : 
     165                 :         880 :         total_element_len += current_element_len;
     166                 :             : 
     167         [ +  + ]:         880 :         if (data_element_size < total_element_len) {
     168                 :           2 :             return false;
     169                 :             :         }
     170                 :             : 
     171         [ +  + ]:         878 :         if (opaque_element_table_header->id == element_id) {
     172                 :             :             /*get element by element id*/
     173         [ +  + ]:         644 :             if (matched_element_cnt == element_index) {
     174                 :         566 :                 *get_element_ptr = opaque_element_table_header;
     175                 :         566 :                 *get_element_len = current_element_len;
     176                 :         566 :                 result = true;
     177                 :             :             }
     178                 :         644 :             matched_element_cnt += 1;
     179                 :             :         }
     180                 :             : 
     181                 :             :         /*move to next element*/
     182                 :         878 :         opaque_element_table_header = (const opaque_element_table_header_t *)
     183                 :             :                                       ((const uint8_t *)opaque_element_table_header +
     184                 :             :                                        current_element_len);
     185                 :             :     }
     186                 :             : 
     187                 :             :     /*ensure data size is right*/
     188         [ -  + ]:         558 :     if (data_element_size != total_element_len) {
     189                 :           0 :         return false;
     190                 :             :     }
     191                 :             : 
     192                 :         558 :     *total_matched_element_cnt = matched_element_cnt;
     193                 :         558 :     return result;
     194                 :             : }
     195                 :             : 
     196                 :         280 : bool libspdm_get_sm_data_element_from_opaque_data (libspdm_context_t *spdm_context,
     197                 :             :                                                    size_t data_in_size, const void *data_in,
     198                 :             :                                                    uint8_t sm_data_id,
     199                 :             :                                                    const void **get_element_ptr, size_t *get_element_len)
     200                 :             : {
     201                 :             :     const opaque_element_table_header_t *opaque_element_table_header;
     202                 :             :     size_t opaque_element_len;
     203                 :             :     const secured_message_opaque_element_table_header_t *secured_message_element_table_header;
     204                 :             :     const secured_message_opaque_element_header_t *secured_message_element_header;
     205                 :             :     bool result;
     206                 :             :     uint8_t element_index;
     207                 :             :     uint8_t element_num;
     208                 :             :     uint8_t total_matched_element_cnt;
     209                 :             : 
     210                 :             :     /*check parameter in*/
     211   [ +  -  -  + ]:         280 :     if ((data_in_size == 0) || (data_in == NULL)) {
     212                 :           0 :         return false;
     213                 :             :     }
     214                 :             : 
     215                 :             :     /*get the total matched element count*/
     216                 :         280 :     result = libspdm_get_element_from_opaque_data_with_element_id(
     217                 :             :         spdm_context, data_in_size, data_in,
     218                 :             :         SPDM_REGISTRY_ID_DMTF, 0, &total_matched_element_cnt,
     219                 :             :         (const void **) &opaque_element_table_header, &opaque_element_len);
     220         [ +  + ]:         280 :     if (!result) {
     221                 :          12 :         return false;
     222                 :             :     }
     223                 :             : 
     224                 :         268 :     element_num = total_matched_element_cnt;
     225         [ +  + ]:         320 :     for (element_index = 0; element_index < element_num; element_index++) {
     226                 :             :         /*get element by element id*/
     227                 :         290 :         result = libspdm_get_element_from_opaque_data_with_element_id(
     228                 :             :             spdm_context, data_in_size, data_in,
     229                 :             :             SPDM_REGISTRY_ID_DMTF, element_index, &total_matched_element_cnt,
     230                 :             :             (const void **) &opaque_element_table_header, &opaque_element_len);
     231         [ -  + ]:         290 :         if (!result) {
     232                 :           0 :             return false;
     233                 :             :         }
     234                 :             : 
     235                 :         290 :         secured_message_element_table_header = (const void *)opaque_element_table_header;
     236         [ +  - ]:         290 :         if (secured_message_element_table_header->vendor_len == 0) {
     237                 :         290 :             secured_message_element_header =
     238                 :             :                 (const void *)(secured_message_element_table_header + 1);
     239                 :         290 :             if ((const uint8_t *)secured_message_element_header +
     240                 :             :                 sizeof(secured_message_opaque_element_header_t) >
     241         [ -  + ]:         290 :                 (const uint8_t *)data_in + data_in_size) {
     242                 :           0 :                 return false;
     243                 :             :             }
     244                 :             : 
     245         [ +  + ]:         290 :             if ((secured_message_element_header->sm_data_id == sm_data_id) &&
     246         [ +  - ]:         238 :                 (secured_message_element_header->sm_data_version ==
     247                 :             :                  SECURED_MESSAGE_OPAQUE_ELEMENT_SMDATA_DATA_VERSION)) {
     248                 :         238 :                 *get_element_ptr = opaque_element_table_header;
     249                 :         238 :                 *get_element_len = opaque_element_len;
     250                 :         238 :                 return true;
     251                 :             :             }
     252                 :             :         }
     253                 :             :     }
     254                 :             : 
     255                 :          30 :     return false;
     256                 :             : }
     257                 :             : 
     258                 :         236 : bool libspdm_process_general_opaque_data_check(libspdm_context_t *spdm_context,
     259                 :             :                                                size_t data_in_size,
     260                 :             :                                                const void *data_in)
     261                 :             : {
     262                 :             :     const spdm_general_opaque_data_table_header_t
     263                 :             :     *spdm_general_opaque_data_table_header;
     264                 :             :     const opaque_element_table_header_t
     265                 :             :     *opaque_element_table_header;
     266                 :             :     uint8_t element_num;
     267                 :             :     uint8_t element_index;
     268                 :             :     uint16_t opaque_element_data_len;
     269                 :             :     size_t data_element_size;
     270                 :             :     size_t current_element_len;
     271                 :             :     size_t total_element_len;
     272                 :         236 :     uint8_t zero_padding[4] = {0};
     273                 :             : 
     274                 :         236 :     total_element_len = 0;
     275                 :             : 
     276         [ +  + ]:         236 :     if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) {
     277         [ +  + ]:          54 :         if ((spdm_context->connection_info.algorithm.other_params_support &
     278                 :             :              SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_MASK) == SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_1) {
     279                 :             :             /* Check byte alignment */
     280         [ -  + ]:          46 :             if ((data_in_size & 3) != 0) {
     281                 :           0 :                 return false;
     282                 :             :             }
     283                 :             : 
     284                 :          46 :             spdm_general_opaque_data_table_header = data_in;
     285         [ -  + ]:          46 :             if (data_in_size < sizeof(spdm_general_opaque_data_table_header_t)) {
     286                 :           0 :                 return false;
     287                 :             :             }
     288         [ +  + ]:          46 :             if (spdm_general_opaque_data_table_header->total_elements < 1) {
     289                 :           2 :                 return false;
     290                 :             :             }
     291                 :          44 :             opaque_element_table_header = (const void *)(spdm_general_opaque_data_table_header + 1);
     292                 :             : 
     293                 :          44 :             element_num = spdm_general_opaque_data_table_header->total_elements;
     294                 :             : 
     295                 :          44 :             data_element_size = data_in_size - sizeof(spdm_general_opaque_data_table_header_t);
     296                 :             : 
     297         [ +  + ]:         100 :             for (element_index = 0; element_index < element_num; element_index++) {
     298                 :             :                 /*ensure the opaque_element_table_header is valid*/
     299         [ -  + ]:          58 :                 if (total_element_len + sizeof(opaque_element_table_header_t) +
     300                 :             :                     sizeof(opaque_element_data_len) >
     301                 :             :                     data_element_size) {
     302                 :           0 :                     return false;
     303                 :             :                 }
     304                 :             : 
     305                 :             :                 /*check element header id*/
     306         [ -  + ]:          58 :                 if (opaque_element_table_header->id > SPDM_REGISTRY_ID_MAX) {
     307                 :           0 :                     return false;
     308                 :             :                 }
     309                 :             : 
     310                 :             :                 /*ensure the vendor_id and opaque_element_data_len field are within the buffer*/
     311                 :          58 :                 if (total_element_len + sizeof(opaque_element_table_header_t) +
     312         [ -  + ]:          58 :                     opaque_element_table_header->vendor_len +
     313                 :             :                     sizeof(opaque_element_data_len) >
     314                 :             :                     data_element_size) {
     315                 :           0 :                     return false;
     316                 :             :                 }
     317                 :             : 
     318                 :          58 :                 opaque_element_data_len = libspdm_read_uint16(
     319                 :          58 :                     (const uint8_t *)(opaque_element_table_header + 1) +
     320                 :          58 :                     opaque_element_table_header->vendor_len);
     321                 :             : 
     322                 :          58 :                 current_element_len = sizeof(opaque_element_table_header_t) +
     323                 :          58 :                                       opaque_element_table_header->vendor_len +
     324                 :          58 :                                       sizeof(opaque_element_data_len) +
     325                 :             :                                       opaque_element_data_len;
     326                 :             : 
     327                 :             :                 /*ensure the element with padding is within the buffer before reading it*/
     328         [ -  + ]:          58 :                 if (total_element_len + ((current_element_len + 3) & ~3) >
     329                 :             :                     data_element_size) {
     330                 :           0 :                     return false;
     331                 :             :                 }
     332                 :             : 
     333         [ +  + ]:          58 :                 if ((current_element_len & 3) != 0) {
     334         [ +  + ]:          30 :                     if (!libspdm_consttime_is_mem_equal(zero_padding,
     335                 :             :                                                         (uint8_t *)(size_t)
     336                 :             :                                                         (opaque_element_table_header) +
     337                 :             :                                                         current_element_len,
     338                 :          30 :                                                         4 - (current_element_len & 3))) {
     339                 :           2 :                         return false;
     340                 :             :                     }
     341                 :             :                 }
     342                 :             :                 /* Add Padding*/
     343                 :          56 :                 current_element_len = (current_element_len + 3) & ~3;
     344                 :             : 
     345                 :          56 :                 total_element_len += current_element_len;
     346                 :             : 
     347                 :             :                 /*move to next element*/
     348                 :          56 :                 opaque_element_table_header =
     349                 :             :                     (const opaque_element_table_header_t *)
     350                 :             :                     ((const uint8_t *)opaque_element_table_header +
     351                 :             :                      current_element_len);
     352                 :             :             }
     353                 :             :         }
     354                 :             :     }
     355                 :             : 
     356                 :         232 :     return true;
     357                 :             : }
     358                 :             : 
     359                 :             : /**
     360                 :             :  * Process opaque data version selection.
     361                 :             :  *
     362                 :             :  * This function should be called in KEY_EXCHANGE/PSK_EXCHANGE response parsing in requester.
     363                 :             :  *
     364                 :             :  * @param  data_in_size                   size in bytes of the data_in.
     365                 :             :  * @param  data_in                       A pointer to the buffer to store the opaque data version selection.
     366                 :             :  **/
     367                 :         110 : libspdm_return_t libspdm_process_opaque_data_version_selection_data(
     368                 :             :     libspdm_context_t *spdm_context, size_t data_in_size, void *data_in,
     369                 :             :     spdm_version_number_t *secured_message_version)
     370                 :             : {
     371                 :             :     const secured_message_opaque_element_table_header_t *opaque_element_table_header;
     372                 :             :     const secured_message_opaque_element_version_selection_t *opaque_element_version_section;
     373                 :             : 
     374                 :             :     bool result;
     375                 :             :     uint8_t secured_message_version_index;
     376                 :             :     const void *get_element_ptr;
     377                 :             :     size_t get_element_len;
     378                 :             : 
     379                 :         110 :     result = false;
     380                 :         110 :     get_element_ptr = NULL;
     381                 :             : 
     382         [ -  + ]:         110 :     if (spdm_context->local_context.secured_message_version.secured_message_version_count == 0) {
     383                 :           0 :         return LIBSPDM_STATUS_SUCCESS;
     384                 :             :     }
     385                 :             : 
     386                 :         110 :     result = libspdm_get_sm_data_element_from_opaque_data(
     387                 :             :         spdm_context, data_in_size, data_in,
     388                 :             :         SECURED_MESSAGE_OPAQUE_ELEMENT_SMDATA_ID_VERSION_SELECTION,
     389                 :             :         &get_element_ptr, &get_element_len);
     390   [ +  +  -  + ]:         110 :     if ((!result) || (get_element_ptr == NULL)) {
     391                 :           6 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"get element error!\n"));
     392                 :           6 :         return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     393                 :             :     }
     394                 :             : 
     395                 :         104 :     opaque_element_table_header = (const secured_message_opaque_element_table_header_t*)
     396                 :             :                                   get_element_ptr;
     397                 :             : 
     398                 :             :     /* Check for selection version data. */
     399         [ +  - ]:         104 :     if ((opaque_element_table_header->vendor_len != 0) ||
     400         [ -  + ]:         104 :         (opaque_element_table_header->opaque_element_data_len !=
     401                 :             :          sizeof(secured_message_opaque_element_version_selection_t))) {
     402                 :           0 :         return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     403                 :             :     }
     404                 :         104 :     opaque_element_version_section = (const void *)(opaque_element_table_header + 1);
     405                 :             : 
     406                 :         104 :     if ((const uint8_t *)opaque_element_version_section +
     407                 :             :         sizeof(secured_message_opaque_element_version_selection_t) >
     408         [ -  + ]:         104 :         (const uint8_t *)opaque_element_table_header + get_element_len) {
     409                 :           0 :         return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     410                 :             :     }
     411                 :             : 
     412                 :         104 :     for (secured_message_version_index = 0;
     413                 :         128 :          secured_message_version_index <
     414         [ +  - ]:         128 :          spdm_context->local_context.secured_message_version.secured_message_version_count;
     415                 :          24 :          secured_message_version_index++) {
     416         [ +  + ]:         256 :         if (libspdm_get_version_from_version_number(opaque_element_version_section->
     417                 :             :                                                     selected_version)
     418                 :             :             ==
     419                 :         128 :             libspdm_get_version_from_version_number(
     420                 :         128 :                 spdm_context->local_context.secured_message_version.secured_message_version[
     421                 :             :                     secured_message_version_index])) {
     422                 :         104 :             libspdm_copy_mem(secured_message_version,
     423                 :             :                              sizeof(spdm_version_number_t),
     424                 :         104 :                              &(opaque_element_version_section->selected_version),
     425                 :             :                              sizeof(spdm_version_number_t));
     426                 :         104 :             return LIBSPDM_STATUS_SUCCESS;
     427                 :             :         }
     428                 :             :     }
     429                 :             : 
     430                 :           0 :     return LIBSPDM_STATUS_UNSUPPORTED_CAP;
     431                 :             : }
     432                 :             : 
     433                 :             : /* Return the highest secured message version this endpoint offers in its local supported list, in
     434                 :             :  * version-number form (e.g. SECURED_SPDM_VERSION_13 << SPDM_VERSION_NUMBER_SHIFT_BIT), or 0 if the
     435                 :             :  * list is empty. The Requester uses this as the "version" to gate the AEADlimitOE element in its
     436                 :             :  * request, since no version has been negotiated yet at that point. */
     437                 :         312 : spdm_version_number_t libspdm_local_max_secured_message_version(
     438                 :             :     const libspdm_context_t *spdm_context)
     439                 :             : {
     440                 :             :     uint8_t index;
     441                 :             :     spdm_version_number_t max_version;
     442                 :             : 
     443                 :         312 :     max_version = 0;
     444                 :         312 :     for (index = 0;
     445         [ +  + ]:         672 :          index < spdm_context->local_context.secured_message_version.secured_message_version_count;
     446                 :         360 :          index++) {
     447                 :         360 :         spdm_version_number_t version =
     448                 :         360 :             spdm_context->local_context.secured_message_version.secured_message_version[index];
     449         [ +  - ]:         720 :         if (libspdm_get_version_from_version_number(version) >
     450                 :         360 :             libspdm_get_version_from_version_number(max_version)) {
     451                 :         360 :             max_version = version;
     452                 :             :         }
     453                 :             :     }
     454                 :         312 :     return max_version;
     455                 :             : }
     456                 :             : 
     457                 :             : /* DSP0277 1.3: derive the AeadLimitExponent that this endpoint advertises from its single source of
     458                 :             :  * truth, max_spdm_session_sequence_number. That value is the maximum sequence number that IS allowed
     459                 :             :  * (seq > max triggers overflow), i.e. AeadLimit - 1, so the AEAD limit is
     460                 :             :  * AeadLimit = max + 1 = 2 ^ exponent (see libspdm_apply_aead_limit_to_session). The advertised
     461                 :             :  * exponent is therefore floor(log2(max + 1)): the largest e such that 2 ^ e <= max + 1. The all-ones
     462                 :             :  * cap maps to 64 (the spec default, since 2^64 is not representable). A cap that is not of the form
     463                 :             :  * 2 ^ e - 1 rounds the exponent down to the nearest representable AEAD limit, which is <= the
     464                 :             :  * configured cap (the safe direction). */
     465                 :         104 : static uint8_t libspdm_aead_limit_exponent_from_max_sequence_number(uint64_t max_sequence_number)
     466                 :             : {
     467                 :             :     uint8_t exponent;
     468                 :             :     uint64_t aead_limit;
     469                 :             : 
     470                 :             :     /* All-ones is the maximum allowed value for the default AeadLimit of 2^64, which is not
     471                 :             :      * representable in a uint64_t; adding 1 would overflow, so handle it directly. */
     472         [ +  + ]:         104 :     if (max_sequence_number >= LIBSPDM_MAX_SPDM_SESSION_SEQUENCE_NUMBER) {
     473                 :          86 :         return SECURED_MESSAGE_AEAD_LIMIT_EXPONENT_MAX;
     474                 :             :     }
     475                 :             : 
     476                 :          18 :     aead_limit = max_sequence_number + 1;
     477                 :          18 :     exponent = 0;
     478         [ +  + ]:         460 :     while (aead_limit > 1) {
     479                 :         442 :         aead_limit >>= 1;
     480                 :         442 :         exponent++;
     481                 :             :     }
     482                 :          18 :     return exponent;
     483                 :             : }
     484                 :             : 
     485                 :         822 : size_t libspdm_get_opaque_data_aead_limit_element_size(const libspdm_context_t *spdm_context,
     486                 :             :                                                        spdm_version_number_t secured_message_version)
     487                 :             : {
     488                 :             :     size_t size;
     489                 :             : 
     490                 :             :     /* The AEADlimitOE element is only defined for secured message version 1.3 and later. It must
     491                 :             :      * not be appended to opaque data for an older version. */
     492         [ +  + ]:         822 :     if (libspdm_get_version_from_version_number(secured_message_version) < SECURED_SPDM_VERSION_13) {
     493                 :         706 :         return 0;
     494                 :             :     }
     495                 :             : 
     496                 :         116 :     size = sizeof(secured_message_opaque_element_table_header_t) +
     497                 :             :            sizeof(secured_message_opaque_element_aead_limit_t);
     498                 :             :     /* Add Padding*/
     499                 :         116 :     return (size + 3) & ~3;
     500                 :             : }
     501                 :             : 
     502                 :             : /* Walk a well-formed opaque data blob (general opaque data table header followed by total_elements
     503                 :             :  * elements) and return its current length in bytes. data_out_capacity bounds the walk. Returns
     504                 :             :  * false if the blob does not fit within data_out_capacity. */
     505                 :         396 : static bool libspdm_get_opaque_data_current_size(libspdm_context_t *spdm_context,
     506                 :             :                                                  const void *data_out, size_t data_out_capacity,
     507                 :             :                                                  size_t *current_size)
     508                 :             : {
     509                 :             :     const secured_message_general_opaque_data_table_header_t *general_opaque_data_table_header;
     510                 :             :     const spdm_general_opaque_data_table_header_t *spdm_general_opaque_data_table_header;
     511                 :             :     const opaque_element_table_header_t *opaque_element_table_header;
     512                 :             :     uint8_t element_num;
     513                 :             :     uint8_t index;
     514                 :             :     uint16_t opaque_element_data_len;
     515                 :             :     size_t total_size;
     516                 :             :     size_t current_element_len;
     517                 :             : 
     518         [ +  + ]:         396 :     if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) {
     519         [ -  + ]:          50 :         if (data_out_capacity < sizeof(spdm_general_opaque_data_table_header_t)) {
     520                 :           0 :             return false;
     521                 :             :         }
     522                 :          50 :         spdm_general_opaque_data_table_header = data_out;
     523                 :          50 :         element_num = spdm_general_opaque_data_table_header->total_elements;
     524                 :          50 :         opaque_element_table_header = (const void *)(spdm_general_opaque_data_table_header + 1);
     525                 :          50 :         total_size = sizeof(spdm_general_opaque_data_table_header_t);
     526                 :             :     } else {
     527         [ -  + ]:         346 :         if (data_out_capacity < sizeof(secured_message_general_opaque_data_table_header_t)) {
     528                 :           0 :             return false;
     529                 :             :         }
     530                 :         346 :         general_opaque_data_table_header = data_out;
     531                 :         346 :         element_num = general_opaque_data_table_header->total_elements;
     532                 :         346 :         opaque_element_table_header = (const void *)(general_opaque_data_table_header + 1);
     533                 :         346 :         total_size = sizeof(secured_message_general_opaque_data_table_header_t);
     534                 :             :     }
     535                 :             : 
     536         [ +  + ]:         792 :     for (index = 0; index < element_num; index++) {
     537                 :         396 :         if (total_size + sizeof(opaque_element_table_header_t) +
     538         [ -  + ]:         396 :             opaque_element_table_header->vendor_len + sizeof(uint16_t) > data_out_capacity) {
     539                 :           0 :             return false;
     540                 :             :         }
     541                 :         396 :         opaque_element_data_len = libspdm_read_uint16(
     542                 :         396 :             (const uint8_t *)opaque_element_table_header + sizeof(opaque_element_table_header_t) +
     543                 :         396 :             opaque_element_table_header->vendor_len);
     544                 :         396 :         current_element_len = sizeof(opaque_element_table_header_t) +
     545                 :         396 :                               opaque_element_table_header->vendor_len + sizeof(uint16_t) +
     546                 :             :                               opaque_element_data_len;
     547                 :             :         /* Add Padding*/
     548                 :         396 :         current_element_len = (current_element_len + 3) & ~3;
     549         [ -  + ]:         396 :         if (total_size + current_element_len > data_out_capacity) {
     550                 :           0 :             return false;
     551                 :             :         }
     552                 :         396 :         total_size += current_element_len;
     553                 :         396 :         opaque_element_table_header = (const opaque_element_table_header_t *)
     554                 :             :                                       ((const uint8_t *)opaque_element_table_header +
     555                 :             :                                        current_element_len);
     556                 :             :     }
     557                 :             : 
     558                 :         396 :     *current_size = total_size;
     559                 :         396 :     return true;
     560                 :             : }
     561                 :             : 
     562                 :         396 : void libspdm_build_opaque_data_aead_limit_element(libspdm_context_t *spdm_context,
     563                 :             :                                                   spdm_version_number_t secured_message_version,
     564                 :             :                                                   size_t *data_out_size, void *data_out)
     565                 :             : {
     566                 :             :     size_t data_out_capacity;
     567                 :             :     size_t existing_size;
     568                 :             :     size_t element_size;
     569                 :             :     secured_message_opaque_element_table_header_t *opaque_element_table_header;
     570                 :             :     secured_message_opaque_element_aead_limit_t *opaque_element_aead_limit;
     571                 :             :     uint8_t *element_ptr;
     572                 :             :     bool result;
     573                 :             : 
     574                 :             :     /* data_out already holds a blob built by the supported-version / version-selection builder.
     575                 :             :      * *data_out_size is the capacity of data_out on input. Parse the blob to find where it ends;
     576                 :             :      * that is the append offset. */
     577                 :         396 :     data_out_capacity = *data_out_size;
     578                 :         396 :     result = libspdm_get_opaque_data_current_size(spdm_context, data_out, data_out_capacity,
     579                 :             :                                                   &existing_size);
     580                 :         396 :     LIBSPDM_ASSERT(result);
     581         [ -  + ]:         396 :     if (!result) {
     582                 :         336 :         return;
     583                 :             :     }
     584                 :             : 
     585                 :             :     /* The size helper enforces the secured message version 1.3 gate; for an older version it
     586                 :             :      * returns 0 and nothing is appended. */
     587                 :         396 :     element_size = libspdm_get_opaque_data_aead_limit_element_size(spdm_context,
     588                 :             :                                                                    secured_message_version);
     589         [ +  + ]:         396 :     if (element_size == 0) {
     590                 :         336 :         *data_out_size = existing_size;
     591                 :         336 :         return;
     592                 :             :     }
     593                 :             : 
     594                 :          60 :     LIBSPDM_ASSERT(existing_size + element_size <= data_out_capacity);
     595                 :             : 
     596         [ +  + ]:          60 :     if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) {
     597                 :             :         spdm_general_opaque_data_table_header_t *spdm_general_opaque_data_table_header;
     598                 :          30 :         spdm_general_opaque_data_table_header = data_out;
     599                 :          30 :         spdm_general_opaque_data_table_header->total_elements++;
     600                 :             :     } else {
     601                 :             :         secured_message_general_opaque_data_table_header_t *general_opaque_data_table_header;
     602                 :          30 :         general_opaque_data_table_header = data_out;
     603                 :          30 :         general_opaque_data_table_header->total_elements++;
     604                 :             :     }
     605                 :             : 
     606                 :          60 :     element_ptr = (uint8_t *)data_out + existing_size;
     607                 :          60 :     opaque_element_table_header = (void *)element_ptr;
     608                 :          60 :     opaque_element_table_header->id = SPDM_REGISTRY_ID_DMTF;
     609                 :          60 :     opaque_element_table_header->vendor_len = 0;
     610                 :          60 :     opaque_element_table_header->opaque_element_data_len =
     611                 :             :         sizeof(secured_message_opaque_element_aead_limit_t);
     612                 :             : 
     613                 :          60 :     opaque_element_aead_limit = (void *)(opaque_element_table_header + 1);
     614                 :          60 :     opaque_element_aead_limit->sm_data_version =
     615                 :             :         SECURED_MESSAGE_OPAQUE_ELEMENT_SMDATA_DATA_VERSION;
     616                 :          60 :     opaque_element_aead_limit->sm_data_id =
     617                 :             :         SECURED_MESSAGE_OPAQUE_ELEMENT_SMDATA_ID_AEAD_LIMIT;
     618                 :          60 :     opaque_element_aead_limit->aead_limit_exponent =
     619                 :          60 :         libspdm_aead_limit_exponent_from_max_sequence_number(
     620                 :             :             spdm_context->max_spdm_session_sequence_number);
     621                 :             : 
     622                 :             :     /* Zero the padding bytes between the element and the new end. */
     623                 :          60 :     libspdm_zero_mem(element_ptr + sizeof(secured_message_opaque_element_table_header_t) +
     624                 :             :                      sizeof(secured_message_opaque_element_aead_limit_t),
     625                 :             :                      element_size - (sizeof(secured_message_opaque_element_table_header_t) +
     626                 :             :                                      sizeof(secured_message_opaque_element_aead_limit_t)));
     627                 :             : 
     628                 :          60 :     *data_out_size = existing_size + element_size;
     629                 :             : }
     630                 :             : 
     631                 :         222 : libspdm_return_t libspdm_process_opaque_data_aead_limit(libspdm_context_t *spdm_context,
     632                 :             :                                                         spdm_version_number_t
     633                 :             :                                                         secured_message_version,
     634                 :             :                                                         size_t data_in_size, const void *data_in,
     635                 :             :                                                         uint8_t *aead_limit_exponent)
     636                 :             : {
     637                 :             :     bool result;
     638                 :             :     const void *get_element_ptr;
     639                 :             :     size_t get_element_len;
     640                 :             :     const secured_message_opaque_element_table_header_t *opaque_element_table_header;
     641                 :             :     const secured_message_opaque_element_aead_limit_t *opaque_element_aead_limit;
     642                 :             : 
     643                 :             :     /* Default per DSP0277 1.3: when the AEAD limit element is absent, the exponent is 64. */
     644                 :         222 :     *aead_limit_exponent = SECURED_MESSAGE_AEAD_LIMIT_EXPONENT_DEFAULT;
     645                 :             : 
     646                 :             :     /* The AEADlimitOE element is only defined for secured message version 1.3 and later. For an
     647                 :             :      * older negotiated version, ignore the element entirely (keep the default exponent) even if a
     648                 :             :      * peer erroneously included it. */
     649         [ +  + ]:         222 :     if (libspdm_get_version_from_version_number(secured_message_version) <
     650                 :             :         SECURED_SPDM_VERSION_13) {
     651                 :         172 :         return LIBSPDM_STATUS_SUCCESS;
     652                 :             :     }
     653                 :             : 
     654                 :          50 :     get_element_ptr = NULL;
     655                 :          50 :     result = libspdm_get_sm_data_element_from_opaque_data(
     656                 :             :         spdm_context, data_in_size, data_in,
     657                 :             :         SECURED_MESSAGE_OPAQUE_ELEMENT_SMDATA_ID_AEAD_LIMIT,
     658                 :             :         &get_element_ptr, &get_element_len);
     659   [ +  +  -  + ]:          50 :     if ((!result) || (get_element_ptr == NULL)) {
     660                 :             :         /* Absent is allowed: keep the default exponent. */
     661                 :          30 :         return LIBSPDM_STATUS_SUCCESS;
     662                 :             :     }
     663                 :             : 
     664                 :          20 :     opaque_element_table_header = (const secured_message_opaque_element_table_header_t *)
     665                 :             :                                   get_element_ptr;
     666         [ +  - ]:          20 :     if ((opaque_element_table_header->vendor_len != 0) ||
     667         [ -  + ]:          20 :         (opaque_element_table_header->opaque_element_data_len !=
     668                 :             :          sizeof(secured_message_opaque_element_aead_limit_t))) {
     669                 :           0 :         return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     670                 :             :     }
     671                 :             : 
     672                 :          20 :     opaque_element_aead_limit = (const void *)(opaque_element_table_header + 1);
     673                 :          20 :     if ((const uint8_t *)opaque_element_aead_limit +
     674                 :             :         sizeof(secured_message_opaque_element_aead_limit_t) >
     675         [ -  + ]:          20 :         (const uint8_t *)opaque_element_table_header + get_element_len) {
     676                 :           0 :         return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     677                 :             :     }
     678                 :             : 
     679                 :             :     /* AeadLimitExponent shall be <= 64. */
     680         [ +  + ]:          20 :     if (opaque_element_aead_limit->aead_limit_exponent >
     681                 :             :         SECURED_MESSAGE_AEAD_LIMIT_EXPONENT_MAX) {
     682                 :           2 :         return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     683                 :             :     }
     684                 :             : 
     685                 :          18 :     *aead_limit_exponent = opaque_element_aead_limit->aead_limit_exponent;
     686                 :          18 :     return LIBSPDM_STATUS_SUCCESS;
     687                 :             : }
     688                 :             : 
     689                 :          44 : void libspdm_apply_aead_limit_to_session(libspdm_context_t *spdm_context,
     690                 :             :                                          void *session_info_p,
     691                 :             :                                          uint8_t peer_aead_limit_exponent)
     692                 :             : {
     693                 :             :     libspdm_session_info_t *session_info;
     694                 :             :     uint8_t local_aead_limit_exponent;
     695                 :             :     uint64_t local_max_sequence_number;
     696                 :             :     uint64_t peer_max_sequence_number;
     697                 :             :     uint64_t effective_max;
     698                 :             : 
     699                 :          44 :     session_info = session_info_p;
     700                 :             : 
     701                 :             :     /* The caller invokes this only when the session negotiated secured message version >= 1.3.
     702                 :             :      *
     703                 :             :      * The DSP0277 AeadLimit is the first sequence number that is NOT allowed, so the maximum
     704                 :             :      * allowed sequence number is AeadLimit - 1 = 2 ^ AeadLimitExponent - 1. Fold together this
     705                 :             :      * endpoint's advertised limit and the peer's advertised limit; the effective cap is the
     706                 :             :      * smaller of the two, so neither side's limit is ever raised by the other.
     707                 :             :      *
     708                 :             :      * This endpoint's contribution must be the SAME rounded-down limit it advertised on the wire,
     709                 :             :      * not the raw configured max_spdm_session_sequence_number. When the configured cap is not of
     710                 :             :      * the form 2 ^ e - 1 the advertised exponent is floor(log2(cap + 1)); enforcing the raw cap
     711                 :             :      * here would let this side send past the limit the peer derives from that exponent. At
     712                 :             :      * exponent 64 the maximum allowed value is 2^64 - 1, i.e. LIBSPDM_MAX_SPDM_SESSION_SEQUENCE_NUMBER
     713                 :             :      * (all-ones), which is also the default. */
     714                 :          44 :     local_aead_limit_exponent = libspdm_aead_limit_exponent_from_max_sequence_number(
     715                 :             :         spdm_context->max_spdm_session_sequence_number);
     716         [ +  + ]:          44 :     if (local_aead_limit_exponent >= 64) {
     717                 :          36 :         local_max_sequence_number = LIBSPDM_MAX_SPDM_SESSION_SEQUENCE_NUMBER;
     718                 :             :     } else {
     719                 :           8 :         local_max_sequence_number = ((uint64_t)1 << local_aead_limit_exponent) - 1;
     720                 :             :     }
     721                 :             : 
     722         [ +  + ]:          44 :     if (peer_aead_limit_exponent >= 64) {
     723                 :          32 :         peer_max_sequence_number = LIBSPDM_MAX_SPDM_SESSION_SEQUENCE_NUMBER;
     724                 :             :     } else {
     725                 :          12 :         peer_max_sequence_number = ((uint64_t)1 << peer_aead_limit_exponent) - 1;
     726                 :             :     }
     727                 :             : 
     728                 :          44 :     effective_max = local_max_sequence_number;
     729         [ +  + ]:          44 :     if (peer_max_sequence_number < effective_max) {
     730                 :           8 :         effective_max = peer_max_sequence_number;
     731                 :             :     }
     732                 :             : 
     733                 :          44 :     libspdm_secured_message_set_max_spdm_session_sequence_number(
     734                 :             :         session_info->secured_message_context, effective_max);
     735                 :          44 : }
        

Generated by: LCOV version 2.0-1