LCOV - code coverage report
Current view: top level - spdm_common_lib - libspdm_com_opaque_data.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 89.6 % 288 258
Test Date: 2026-10-01 20:56:25 Functions: 100.0 % 14 14
Branches: 71.5 % 158 113

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

Generated by: LCOV version 2.0-1