LCOV - code coverage report
Current view: top level - library/spdm_common_lib - libspdm_com_opaque_data.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 89.2 % 288 257
Test Date: 2026-08-16 08:12:25 Functions: 100.0 % 14 14

            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          189 : size_t libspdm_get_opaque_data_version_selection_data_size(const libspdm_context_t *spdm_context)
      11              : {
      12              :     size_t size;
      13              : 
      14          189 :     if (spdm_context->local_context.secured_message_version.secured_message_version_count == 0) {
      15            0 :         return 0;
      16              :     }
      17              : 
      18          189 :     if (libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_12) {
      19           28 :         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          161 :         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          189 :     return (size + 3) & ~3;
      29              : }
      30              : 
      31          410 : size_t libspdm_get_opaque_data_supported_version_data_size(libspdm_context_t *spdm_context)
      32              : {
      33              :     size_t size;
      34              : 
      35          410 :     if (spdm_context->local_context.secured_message_version.secured_message_version_count == 0) {
      36            0 :         return 0;
      37              :     }
      38              : 
      39          410 :     if (libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_12) {
      40           48 :         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           48 :                sizeof(spdm_version_number_t) *
      44           48 :                spdm_context->local_context.secured_message_version.secured_message_version_count;
      45              :     } else {
      46          362 :         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          362 :                sizeof(spdm_version_number_t) *
      50          362 :                spdm_context->local_context.secured_message_version.secured_message_version_count;
      51              :     }
      52              :     /* Add Padding*/
      53          410 :     return (size + 3) & ~3;
      54              : }
      55              : 
      56           26 : 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           26 :     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           18 :         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           18 :                sizeof(spdm_version_number_t) * version_count;
      71              :     }
      72              :     /* Add Padding*/
      73           26 :     return (size + 3) & ~3;
      74              : }
      75              : 
      76          189 : 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          189 :     if (element_id > SPDM_REGISTRY_ID_MAX) {
      97            0 :         return false;
      98              :     }
      99          189 :     if ((data_in_size == 0) || (data_in == NULL)) {
     100            0 :         return false;
     101              :     }
     102              : 
     103          189 :     if (libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_12) {
     104           72 :         spdm_general_opaque_data_table_header = data_in;
     105           72 :         if (data_in_size < sizeof(spdm_general_opaque_data_table_header_t)) {
     106            0 :             return false;
     107              :         }
     108           72 :         if (spdm_general_opaque_data_table_header->total_elements < 1) {
     109            0 :             return false;
     110              :         }
     111           72 :         opaque_element_table_header = (const void *)(spdm_general_opaque_data_table_header + 1);
     112              : 
     113           72 :         element_num = spdm_general_opaque_data_table_header->total_elements;
     114              : 
     115           72 :         data_element_size = data_in_size - sizeof(spdm_general_opaque_data_table_header_t);
     116              :     } else {
     117          117 :         general_opaque_data_table_header = data_in;
     118          117 :         if (data_in_size < sizeof(secured_message_general_opaque_data_table_header_t)) {
     119            0 :             return false;
     120              :         }
     121          117 :         if ((general_opaque_data_table_header->spec_id != SECURED_MESSAGE_OPAQUE_DATA_SPEC_ID) ||
     122          116 :             (general_opaque_data_table_header->opaque_version != SECURED_MESSAGE_OPAQUE_VERSION) ||
     123          116 :             (general_opaque_data_table_header->total_elements < 1)) {
     124            1 :             return false;
     125              :         }
     126          116 :         opaque_element_table_header = (const void *)(general_opaque_data_table_header + 1);
     127              : 
     128          116 :         element_num = general_opaque_data_table_header->total_elements;
     129              : 
     130          116 :         data_element_size = data_in_size -
     131              :                             sizeof(secured_message_general_opaque_data_table_header_t);
     132              :     }
     133              : 
     134          188 :     total_element_len = 0;
     135          188 :     result = false;
     136              : 
     137              :     /* find the Nth element with specific element_id, N = element_index. */
     138          188 :     matched_element_cnt = 0;
     139          517 :     for (index = 0; index < element_num; index++) {
     140              :         /*ensure the opaque_element_table_header is valid*/
     141          333 :         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          333 :         if ((opaque_element_table_header->id > SPDM_REGISTRY_ID_MAX)) {
     148            4 :             return false;
     149              :         }
     150              : 
     151          329 :         if ((total_element_len + sizeof(opaque_element_table_header_t) +
     152          329 :              opaque_element_table_header->vendor_len + 2) > data_element_size) {
     153            0 :             return false;
     154              :         }
     155              : 
     156          329 :         opaque_element_data_len = libspdm_read_uint16(
     157          329 :             (const uint8_t *)opaque_element_table_header + sizeof(opaque_element_table_header_t) +
     158          329 :             opaque_element_table_header->vendor_len);
     159              : 
     160          329 :         current_element_len = sizeof(opaque_element_table_header_t) +
     161          329 :                               opaque_element_table_header->vendor_len + 2 + opaque_element_data_len;
     162              :         /* Add Padding*/
     163          329 :         current_element_len = (current_element_len + 3) & ~3;
     164              : 
     165          329 :         total_element_len += current_element_len;
     166              : 
     167          329 :         if (data_element_size < total_element_len) {
     168            0 :             return false;
     169              :         }
     170              : 
     171          329 :         if (opaque_element_table_header->id == element_id) {
     172              :             /*get element by element id*/
     173          222 :             if (matched_element_cnt == element_index) {
     174          188 :                 *get_element_ptr = opaque_element_table_header;
     175          188 :                 *get_element_len = current_element_len;
     176          188 :                 result = true;
     177              :             }
     178          222 :             matched_element_cnt += 1;
     179              :         }
     180              : 
     181              :         /*move to next element*/
     182          329 :         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          184 :     if (data_element_size != total_element_len) {
     189            0 :         return false;
     190              :     }
     191              : 
     192          184 :     *total_matched_element_cnt = matched_element_cnt;
     193          184 :     return result;
     194              : }
     195              : 
     196           92 : 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           92 :     if ((data_in_size == 0) || (data_in == NULL)) {
     212            0 :         return false;
     213              :     }
     214              : 
     215              :     /*get the total matched element count*/
     216           92 :     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           92 :     if (!result) {
     221            5 :         return false;
     222              :     }
     223              : 
     224           87 :     element_num = total_matched_element_cnt;
     225          108 :     for (element_index = 0; element_index < element_num; element_index++) {
     226              :         /*get element by element id*/
     227           97 :         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           97 :         if (!result) {
     232            0 :             return false;
     233              :         }
     234              : 
     235           97 :         secured_message_element_table_header = (const void *)opaque_element_table_header;
     236           97 :         if (secured_message_element_table_header->vendor_len == 0) {
     237           97 :             secured_message_element_header =
     238              :                 (const void *)(secured_message_element_table_header + 1);
     239           97 :             if ((const uint8_t *)secured_message_element_header +
     240              :                 sizeof(secured_message_opaque_element_header_t) >
     241           97 :                 (const uint8_t *)data_in + data_in_size) {
     242            0 :                 return false;
     243              :             }
     244              : 
     245           97 :             if ((secured_message_element_header->sm_data_id == sm_data_id) &&
     246           76 :                 (secured_message_element_header->sm_data_version ==
     247              :                  SECURED_MESSAGE_OPAQUE_ELEMENT_SMDATA_DATA_VERSION)) {
     248           76 :                 *get_element_ptr = opaque_element_table_header;
     249           76 :                 *get_element_len = opaque_element_len;
     250           76 :                 return true;
     251              :             }
     252              :         }
     253              :     }
     254              : 
     255           11 :     return false;
     256              : }
     257              : 
     258           76 : 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           76 :     uint8_t zero_padding[4] = {0};
     273              : 
     274           76 :     total_element_len = 0;
     275              : 
     276           76 :     LIBSPDM_ASSERT(data_in_size <= SPDM_MAX_OPAQUE_DATA_SIZE);
     277              : 
     278           76 :     if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) {
     279           19 :         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           15 :             if ((data_in_size & 3) != 0) {
     283            0 :                 return false;
     284              :             }
     285              : 
     286           15 :             spdm_general_opaque_data_table_header = data_in;
     287           15 :             if (data_in_size < sizeof(spdm_general_opaque_data_table_header_t)) {
     288            0 :                 return false;
     289              :             }
     290           15 :             if (spdm_general_opaque_data_table_header->total_elements < 1) {
     291            0 :                 return false;
     292              :             }
     293           15 :             opaque_element_table_header = (const void *)(spdm_general_opaque_data_table_header + 1);
     294              : 
     295           15 :             element_num = spdm_general_opaque_data_table_header->total_elements;
     296              : 
     297           15 :             data_element_size = data_in_size - sizeof(spdm_general_opaque_data_table_header_t);
     298              : 
     299           33 :             for (element_index = 0; element_index < element_num; element_index++) {
     300              :                 /*ensure the opaque_element_table_header is valid*/
     301           19 :                 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           19 :                 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           19 :                 if (total_element_len + sizeof(opaque_element_table_header_t) +
     314           19 :                     opaque_element_table_header->vendor_len +
     315              :                     sizeof(opaque_element_data_len) >
     316              :                     data_element_size) {
     317            0 :                     return false;
     318              :                 }
     319              : 
     320           19 :                 opaque_element_data_len = libspdm_read_uint16(
     321           19 :                     (const uint8_t *)(opaque_element_table_header + 1) +
     322           19 :                     opaque_element_table_header->vendor_len);
     323              : 
     324           19 :                 current_element_len = sizeof(opaque_element_table_header_t) +
     325           19 :                                       opaque_element_table_header->vendor_len +
     326           19 :                                       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           19 :                 if (total_element_len + ((current_element_len + 3) & ~3) >
     331              :                     data_element_size) {
     332            0 :                     return false;
     333              :                 }
     334              : 
     335           19 :                 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           18 :                 current_element_len = (current_element_len + 3) & ~3;
     346              : 
     347           18 :                 total_element_len += current_element_len;
     348              : 
     349              :                 /*move to next element*/
     350           18 :                 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           75 :     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           44 : 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           44 :     result = false;
     382           44 :     get_element_ptr = NULL;
     383              : 
     384           44 :     if (spdm_context->local_context.secured_message_version.secured_message_version_count == 0) {
     385            0 :         return LIBSPDM_STATUS_SUCCESS;
     386              :     }
     387              : 
     388           44 :     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           44 :     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           41 :     opaque_element_table_header = (const secured_message_opaque_element_table_header_t*)
     398              :                                   get_element_ptr;
     399              : 
     400              :     /* Check for selection version data. */
     401           41 :     if ((opaque_element_table_header->vendor_len != 0) ||
     402           41 :         (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           41 :     opaque_element_version_section = (const void *)(opaque_element_table_header + 1);
     407              : 
     408           41 :     if ((const uint8_t *)opaque_element_version_section +
     409              :         sizeof(secured_message_opaque_element_version_selection_t) >
     410           41 :         (const uint8_t *)opaque_element_table_header + get_element_len) {
     411            0 :         return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     412              :     }
     413              : 
     414           41 :     for (secured_message_version_index = 0;
     415           46 :          secured_message_version_index <
     416           46 :          spdm_context->local_context.secured_message_version.secured_message_version_count;
     417            5 :          secured_message_version_index++) {
     418           92 :         if (libspdm_get_version_from_version_number(opaque_element_version_section->
     419              :                                                     selected_version)
     420              :             ==
     421           46 :             libspdm_get_version_from_version_number(
     422           46 :                 spdm_context->local_context.secured_message_version.secured_message_version[
     423              :                     secured_message_version_index])) {
     424           41 :             libspdm_copy_mem(secured_message_version,
     425              :                              sizeof(spdm_version_number_t),
     426           41 :                              &(opaque_element_version_section->selected_version),
     427              :                              sizeof(spdm_version_number_t));
     428           41 :             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          134 : 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          134 :     max_version = 0;
     446          134 :     for (index = 0;
     447          277 :          index < spdm_context->local_context.secured_message_version.secured_message_version_count;
     448          143 :          index++) {
     449          143 :         spdm_version_number_t version =
     450          143 :             spdm_context->local_context.secured_message_version.secured_message_version[index];
     451          286 :         if (libspdm_get_version_from_version_number(version) >
     452          143 :             libspdm_get_version_from_version_number(max_version)) {
     453          143 :             max_version = version;
     454              :         }
     455              :     }
     456          134 :     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           39 : 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           39 :     if (max_sequence_number >= LIBSPDM_MAX_SPDM_SESSION_SEQUENCE_NUMBER) {
     475           30 :         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          325 : 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          325 :     if (libspdm_get_version_from_version_number(secured_message_version) < SECURED_SPDM_VERSION_13) {
     495          285 :         return 0;
     496              :     }
     497              : 
     498           40 :     size = sizeof(secured_message_opaque_element_table_header_t) +
     499              :            sizeof(secured_message_opaque_element_aead_limit_t);
     500              :     /* Add Padding*/
     501           40 :     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          162 : 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          162 :     if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) {
     521           18 :         if (data_out_capacity < sizeof(spdm_general_opaque_data_table_header_t)) {
     522            0 :             return false;
     523              :         }
     524           18 :         spdm_general_opaque_data_table_header = data_out;
     525           18 :         element_num = spdm_general_opaque_data_table_header->total_elements;
     526           18 :         opaque_element_table_header = (const void *)(spdm_general_opaque_data_table_header + 1);
     527           18 :         total_size = sizeof(spdm_general_opaque_data_table_header_t);
     528              :     } else {
     529          144 :         if (data_out_capacity < sizeof(secured_message_general_opaque_data_table_header_t)) {
     530            0 :             return false;
     531              :         }
     532          144 :         general_opaque_data_table_header = data_out;
     533          144 :         element_num = general_opaque_data_table_header->total_elements;
     534          144 :         opaque_element_table_header = (const void *)(general_opaque_data_table_header + 1);
     535          144 :         total_size = sizeof(secured_message_general_opaque_data_table_header_t);
     536              :     }
     537              : 
     538          324 :     for (index = 0; index < element_num; index++) {
     539          162 :         if (total_size + sizeof(opaque_element_table_header_t) +
     540          162 :             opaque_element_table_header->vendor_len + sizeof(uint16_t) > data_out_capacity) {
     541            0 :             return false;
     542              :         }
     543          162 :         opaque_element_data_len = libspdm_read_uint16(
     544          162 :             (const uint8_t *)opaque_element_table_header + sizeof(opaque_element_table_header_t) +
     545          162 :             opaque_element_table_header->vendor_len);
     546          162 :         current_element_len = sizeof(opaque_element_table_header_t) +
     547          162 :                               opaque_element_table_header->vendor_len + sizeof(uint16_t) +
     548              :                               opaque_element_data_len;
     549              :         /* Add Padding*/
     550          162 :         current_element_len = (current_element_len + 3) & ~3;
     551          162 :         if (total_size + current_element_len > data_out_capacity) {
     552            0 :             return false;
     553              :         }
     554          162 :         total_size += current_element_len;
     555          162 :         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          162 :     *current_size = total_size;
     561          162 :     return true;
     562              : }
     563              : 
     564          162 : 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          162 :     data_out_capacity = *data_out_size;
     580          162 :     result = libspdm_get_opaque_data_current_size(spdm_context, data_out, data_out_capacity,
     581              :                                                   &existing_size);
     582          162 :     LIBSPDM_ASSERT(result);
     583          162 :     if (!result) {
     584          141 :         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          162 :     element_size = libspdm_get_opaque_data_aead_limit_element_size(spdm_context,
     590              :                                                                    secured_message_version);
     591          162 :     if (element_size == 0) {
     592          141 :         *data_out_size = existing_size;
     593          141 :         return;
     594              :     }
     595              : 
     596           21 :     LIBSPDM_ASSERT(existing_size + element_size <= data_out_capacity);
     597              : 
     598           21 :     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           10 :         spdm_general_opaque_data_table_header = data_out;
     601           10 :         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           11 :         general_opaque_data_table_header = data_out;
     605           11 :         general_opaque_data_table_header->total_elements++;
     606              :     }
     607              : 
     608           21 :     element_ptr = (uint8_t *)data_out + existing_size;
     609           21 :     opaque_element_table_header = (void *)element_ptr;
     610           21 :     opaque_element_table_header->id = SPDM_REGISTRY_ID_DMTF;
     611           21 :     opaque_element_table_header->vendor_len = 0;
     612           21 :     opaque_element_table_header->opaque_element_data_len =
     613              :         sizeof(secured_message_opaque_element_aead_limit_t);
     614              : 
     615           21 :     opaque_element_aead_limit = (void *)(opaque_element_table_header + 1);
     616           21 :     opaque_element_aead_limit->sm_data_version =
     617              :         SECURED_MESSAGE_OPAQUE_ELEMENT_SMDATA_DATA_VERSION;
     618           21 :     opaque_element_aead_limit->sm_data_id =
     619              :         SECURED_MESSAGE_OPAQUE_ELEMENT_SMDATA_ID_AEAD_LIMIT;
     620           21 :     opaque_element_aead_limit->aead_limit_exponent =
     621           21 :         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           21 :     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           21 :     *data_out_size = existing_size + element_size;
     631              : }
     632              : 
     633           71 : 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           71 :     *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           71 :     if (libspdm_get_version_from_version_number(secured_message_version) <
     652              :         SECURED_SPDM_VERSION_13) {
     653           51 :         return LIBSPDM_STATUS_SUCCESS;
     654              :     }
     655              : 
     656           20 :     get_element_ptr = NULL;
     657           20 :     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           20 :     if ((!result) || (get_element_ptr == NULL)) {
     662              :         /* Absent is allowed: keep the default exponent. */
     663           11 :         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           18 : 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           18 :     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           18 :     local_aead_limit_exponent = libspdm_aead_limit_exponent_from_max_sequence_number(
     717              :         spdm_context->max_spdm_session_sequence_number);
     718           18 :     if (local_aead_limit_exponent >= 64) {
     719           14 :         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           18 :     if (peer_aead_limit_exponent >= 64) {
     725           12 :         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           18 :     effective_max = local_max_sequence_number;
     731           18 :     if (peer_max_sequence_number < effective_max) {
     732            4 :         effective_max = peer_max_sequence_number;
     733              :     }
     734              : 
     735           18 :     libspdm_secured_message_set_max_spdm_session_sequence_number(
     736              :         session_info->secured_message_context, effective_max);
     737           18 : }
        

Generated by: LCOV version 2.0-1