LCOV - code coverage report
Current view: top level - spdm_requester_lib - libspdm_req_vendor_defined_request.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 82.9 % 164 136
Test Date: 2026-10-01 20:56:25 Functions: 100.0 % 2 2
Branches: 59.8 % 92 55

             Branch data     Line data    Source code
       1                 :             : /**
       2                 :             :  *  Copyright Notice:
       3                 :             :  *  Copyright 2023-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_requester_lib.h"
       8                 :             : 
       9                 :             : #if LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES
      10                 :             : 
      11                 :             : #define SPDM_MAX_VENDOR_PAYLOAD_LEN (SPDM_MAX_VENDOR_ID_LENGTH + 2 + 4 + \
      12                 :             :                                      SPDM_MAX_VENDOR_DEFINED_DATA_LEN_14)
      13                 :             : 
      14                 :             : #pragma pack(1)
      15                 :             : typedef struct {
      16                 :             :     spdm_message_header_t header;
      17                 :             :     uint16_t standard_id;
      18                 :             :     uint8_t vendor_id_len;
      19                 :             :     uint8_t vendor_plus_request[SPDM_MAX_VENDOR_PAYLOAD_LEN];
      20                 :             : } libspdm_vendor_defined_response_msg_max_t;
      21                 :             : #pragma pack()
      22                 :             : 
      23                 :          11 : static libspdm_return_t libspdm_try_vendor_send_request_receive_response(
      24                 :             :     libspdm_context_t *spdm_context,
      25                 :             :     const uint32_t *session_id,
      26                 :             :     uint16_t req_standard_id,
      27                 :             :     uint8_t req_vendor_id_len,
      28                 :             :     const void *req_vendor_id,
      29                 :             :     uint32_t req_size,
      30                 :             :     const void *req_data,
      31                 :             :     uint16_t *resp_standard_id,
      32                 :             :     uint8_t *resp_vendor_id_len,
      33                 :             :     void *resp_vendor_id,
      34                 :             :     uint32_t *resp_size,
      35                 :             :     void *resp_data)
      36                 :             : {
      37                 :             :     libspdm_return_t status;
      38                 :             :     spdm_vendor_defined_request_msg_t *spdm_request;
      39                 :             :     size_t spdm_request_size;
      40                 :             :     libspdm_vendor_defined_response_msg_max_t *spdm_response;
      41                 :             :     size_t spdm_response_size;
      42                 :             :     uint8_t *message;
      43                 :          11 :     size_t message_size = 0;
      44                 :             :     size_t transport_header_size;
      45                 :          11 :     size_t max_payload = 0;
      46                 :          11 :     uint8_t* vendor_request = NULL;
      47                 :          11 :     uint8_t *response_ptr = NULL;
      48                 :          11 :     uint32_t response_size = 0;
      49                 :             :     bool use_large_payload;
      50                 :             : 
      51                 :             :     /* -=[Check Parameters Phase]=- */
      52         [ +  - ]:          11 :     if (spdm_context == NULL ||
      53   [ +  -  +  -  :          11 :         (req_size != 0 && req_data == NULL) ||
                   +  - ]
      54         [ +  - ]:          11 :         resp_standard_id == NULL ||
      55         [ +  - ]:          11 :         resp_vendor_id_len == NULL ||
      56         [ +  - ]:          11 :         resp_vendor_id == NULL ||
      57                 :          11 :         resp_size == NULL ||
      58   [ +  +  -  + ]:          11 :         (*resp_size != 0 && resp_data == NULL)
      59                 :             :         ) {
      60                 :           0 :         return LIBSPDM_STATUS_INVALID_PARAMETER;
      61                 :             :     }
      62                 :             : 
      63         [ -  + ]:          11 :     if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
      64                 :           0 :         return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
      65                 :             :     }
      66                 :             : 
      67                 :          11 :     transport_header_size = spdm_context->local_context.capability.transport_header_size;
      68                 :             : 
      69         [ -  + ]:          11 :     if (req_size > SPDM_MAX_VENDOR_DEFINED_DATA_LEN) {
      70         [ #  # ]:           0 :         if (libspdm_get_connection_version (spdm_context) < SPDM_MESSAGE_VERSION_14) {
      71                 :           0 :             return LIBSPDM_STATUS_UNSUPPORTED_CAP;
      72         [ #  # ]:           0 :         } else if (!libspdm_is_capabilities_flag_supported(
      73                 :             :                        spdm_context, true,
      74                 :             :                        SPDM_GET_CAPABILITIES_REQUEST_FLAGS_LARGE_RESP_CAP,
      75                 :             :                        SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_LARGE_RESP_CAP)) {
      76                 :           0 :             return LIBSPDM_STATUS_INVALID_PARAMETER;
      77                 :             :         }
      78                 :             :     }
      79                 :             : 
      80   [ +  +  +  - ]:          15 :     if ((libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_14) &&
      81                 :           4 :         libspdm_is_capabilities_flag_supported(
      82                 :             :             spdm_context, true,
      83                 :             :             SPDM_GET_CAPABILITIES_REQUEST_FLAGS_LARGE_RESP_CAP,
      84                 :             :             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_LARGE_RESP_CAP)) {
      85                 :           4 :         use_large_payload = true;
      86                 :             :     } else {
      87                 :           7 :         use_large_payload = false;
      88                 :             :     }
      89                 :             : 
      90                 :             :     /* -=[Construct Request Phase]=- */
      91                 :          11 :     status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
      92         [ -  + ]:          11 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
      93                 :           0 :         return status;
      94                 :             :     }
      95                 :             : 
      96                 :             :     /* calculate useful payload the sender buffer can hold after
      97                 :             :      * removing all protocol, spdm and vendor defined message headers
      98                 :             :      * -3 bytes is for the standard_id and vendor_id_len fields in the vendor header
      99                 :             :      * -2 bytes is for the payload length field */
     100                 :          11 :     max_payload = message_size - transport_header_size -
     101                 :          11 :                   spdm_context->local_context.capability.transport_tail_size
     102                 :          11 :                   - sizeof(spdm_request->header) - 3 - req_vendor_id_len - 2;
     103                 :             : 
     104         [ -  + ]:          11 :     LIBSPDM_ASSERT (message_size >= transport_header_size +
     105                 :             :                     spdm_context->local_context.capability.transport_tail_size);
     106                 :             : 
     107                 :             :     /* do not accept requests exceeding maximum allowed payload */
     108         [ -  + ]:          11 :     if ((size_t)req_size > max_payload) {
     109                 :           0 :         return LIBSPDM_STATUS_INVALID_PARAMETER;
     110                 :             :     }
     111                 :             : 
     112                 :          11 :     spdm_request = (void *)(message + transport_header_size);
     113                 :          11 :     spdm_request_size = message_size - transport_header_size -
     114                 :          11 :                         spdm_context->local_context.capability.transport_tail_size;
     115                 :             : 
     116         [ -  + ]:          11 :     LIBSPDM_ASSERT(spdm_request_size >= sizeof(spdm_vendor_defined_request_msg_t) +
     117                 :             :                    req_vendor_id_len + sizeof(uint16_t) + req_size);
     118                 :          11 :     spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
     119                 :          11 :     spdm_request->header.request_response_code = SPDM_VENDOR_DEFINED_REQUEST;
     120                 :          11 :     spdm_request->header.param1 = 0;
     121                 :          11 :     spdm_request->header.param2 = 0;
     122                 :             :     /* Message header here */
     123                 :          11 :     spdm_request->standard_id = req_standard_id;
     124                 :          11 :     spdm_request->len = req_vendor_id_len;
     125                 :             : 
     126                 :             :     /* Copy Vendor id */
     127                 :          11 :     vendor_request = ((uint8_t *)spdm_request) + sizeof(spdm_vendor_defined_request_msg_t);
     128         [ +  - ]:          11 :     if (req_vendor_id_len != 0) {
     129                 :          11 :         libspdm_copy_mem(vendor_request, req_vendor_id_len, req_vendor_id, req_vendor_id_len);
     130                 :          11 :         vendor_request += req_vendor_id_len;
     131                 :             :     }
     132                 :             : 
     133         [ +  + ]:          11 :     if (use_large_payload) {
     134                 :           4 :         spdm_request->header.param1 |= SPDM_VENDOR_DEFINED_REQUEST_LARGE_REQ;
     135                 :             :         /* skip request_len */
     136                 :           4 :         vendor_request += sizeof(uint16_t);
     137                 :             : 
     138                 :             :         /* Copy large_request_len */
     139                 :           4 :         libspdm_copy_mem(vendor_request, sizeof(uint32_t), &req_size, sizeof(uint32_t));
     140                 :           4 :         vendor_request += sizeof(uint32_t);
     141                 :             : 
     142                 :             :         /* Copy payload */
     143         [ +  - ]:           4 :         if (req_size != 0) {
     144                 :           4 :             libspdm_copy_mem(vendor_request, req_size, req_data, req_size);
     145                 :             :         }
     146                 :             : 
     147                 :           4 :         spdm_request_size = sizeof(spdm_vendor_defined_request_msg_t) +
     148                 :           4 :                             req_vendor_id_len + sizeof(uint16_t) + sizeof(uint32_t) + req_size;
     149                 :             : 
     150                 :             :     } else {
     151                 :             :         /* Copy request_len */
     152                 :           7 :         libspdm_copy_mem(vendor_request, sizeof(uint16_t), &req_size, sizeof(uint16_t));
     153                 :           7 :         vendor_request += sizeof(uint16_t);
     154                 :             : 
     155                 :             :         /* Copy payload */
     156         [ +  - ]:           7 :         if (req_size != 0) {
     157                 :           7 :             libspdm_copy_mem(vendor_request, req_size, req_data, req_size);
     158                 :             :         }
     159                 :             : 
     160                 :           7 :         spdm_request_size = sizeof(spdm_vendor_defined_request_msg_t) +
     161                 :           7 :                             req_vendor_id_len + sizeof(uint16_t) + req_size;
     162                 :             :     }
     163                 :             : 
     164                 :             :     /* -=[Send Request Phase]=- */
     165                 :          11 :     status = libspdm_send_spdm_request(spdm_context, session_id, spdm_request_size, spdm_request);
     166         [ +  + ]:          11 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     167                 :           1 :         libspdm_release_sender_buffer (spdm_context);
     168                 :           1 :         return LIBSPDM_STATUS_SEND_FAIL;
     169                 :             :     }
     170                 :          10 :     libspdm_zero_mem(message, message_size);
     171                 :          10 :     libspdm_release_sender_buffer (spdm_context);
     172                 :          10 :     spdm_request = (void *)spdm_context->last_spdm_request;
     173                 :             : 
     174                 :             :     /* -=[Receive Response Phase]=- */
     175                 :          10 :     status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
     176         [ -  + ]:          10 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     177                 :           0 :         return status;
     178                 :             :     }
     179         [ -  + ]:          10 :     LIBSPDM_ASSERT (message_size >= transport_header_size);
     180                 :          10 :     spdm_response = (void *)(message);
     181                 :          10 :     spdm_response_size = message_size;
     182                 :             : 
     183                 :          10 :     status = libspdm_receive_spdm_response(spdm_context, session_id,
     184                 :             :                                            &spdm_response_size,
     185                 :             :                                            (void **)&spdm_response);
     186                 :             : 
     187         [ +  + ]:          10 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     188                 :           2 :         status = LIBSPDM_STATUS_RECEIVE_FAIL;
     189                 :           2 :         goto done;
     190                 :             :     }
     191                 :             : 
     192                 :             :     /* -=[Validate Response Phase]=- */
     193         [ -  + ]:           8 :     if (spdm_response_size < sizeof(spdm_message_header_t)) {
     194                 :           0 :         status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     195                 :           0 :         goto done;
     196                 :             :     }
     197         [ +  + ]:           8 :     if (spdm_response->header.request_response_code == SPDM_ERROR) {
     198                 :           1 :         status = libspdm_handle_error_response_main(
     199                 :             :             spdm_context, session_id,
     200                 :             :             &spdm_response_size,
     201                 :             :             (void **)&spdm_response, SPDM_VENDOR_DEFINED_REQUEST,
     202                 :             :             SPDM_VENDOR_DEFINED_RESPONSE);
     203         [ +  - ]:           1 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     204                 :           1 :             goto done;
     205                 :             :         }
     206         [ -  + ]:           7 :     } else if (spdm_response->header.request_response_code != SPDM_VENDOR_DEFINED_RESPONSE) {
     207                 :           0 :         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     208                 :           0 :         goto done;
     209                 :             :     }
     210         [ -  + ]:           7 :     if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
     211                 :           0 :         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     212                 :           0 :         goto done;
     213                 :             :     }
     214                 :             : 
     215         [ -  + ]:           7 :     if (spdm_response_size < sizeof(spdm_vendor_defined_response_msg_t)) {
     216                 :           0 :         status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     217                 :           0 :         goto done;
     218                 :             :     }
     219                 :             : 
     220         [ -  + ]:           7 :     if (!libspdm_validate_svh_vendor_id_len(spdm_response->standard_id,
     221                 :           7 :                                             spdm_response->vendor_id_len)) {
     222                 :           0 :         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     223                 :           0 :         goto done;
     224                 :             :     }
     225                 :             : 
     226                 :           7 :     if ((spdm_response->header.param1 & SPDM_VENDOR_DEFINED_RESPONSE_LARGE_RESP) !=
     227         [ +  + ]:           7 :         (spdm_request->header.param1 & SPDM_VENDOR_DEFINED_REQUEST_LARGE_REQ)) {
     228                 :           1 :         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     229                 :           1 :         goto done;
     230                 :             :     }
     231                 :             : 
     232         [ +  + ]:           6 :     if (use_large_payload) {
     233                 :             :         /* check response buffer size at least spdm response default header plus
     234                 :             :          * number of bytes required by vendor id and 2 bytes for reserved and 4 bytes
     235                 :             :          * for large response payload size */
     236                 :           3 :         if (spdm_response_size < sizeof(spdm_vendor_defined_response_msg_t) +
     237         [ +  + ]:           3 :             spdm_response->vendor_id_len + sizeof(uint16_t) + sizeof(uint32_t)) {
     238                 :           1 :             status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     239                 :           1 :             goto done;
     240                 :             :         }
     241                 :             :     } else {
     242                 :             :         /* check response buffer size at least spdm response default header plus
     243                 :             :          * number of bytes required by vendor id and 2 bytes for response payload size */
     244                 :           3 :         if (spdm_response_size < sizeof(spdm_vendor_defined_response_msg_t) +
     245         [ -  + ]:           3 :             spdm_response->vendor_id_len + sizeof(uint16_t)) {
     246                 :           0 :             status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     247                 :           0 :             goto done;
     248                 :             :         }
     249                 :             :     }
     250                 :             : 
     251                 :           5 :     *resp_standard_id = spdm_response->standard_id;
     252         [ -  + ]:           5 :     if (*resp_vendor_id_len < spdm_response->vendor_id_len) {
     253                 :           0 :         status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     254                 :           0 :         goto done;
     255                 :             :     }
     256                 :           5 :     *resp_vendor_id_len = spdm_response->vendor_id_len;
     257         [ +  - ]:           5 :     if ((*resp_vendor_id_len) != 0) {
     258                 :           5 :         libspdm_copy_mem(resp_vendor_id, *resp_vendor_id_len, spdm_response->vendor_plus_request,
     259                 :           5 :                          *resp_vendor_id_len);
     260                 :             :     }
     261                 :             : 
     262                 :             :     /* -=[Process Response Phase]=- */
     263                 :           5 :     response_ptr = spdm_response->vendor_plus_request + spdm_response->vendor_id_len;
     264         [ +  + ]:           5 :     if (use_large_payload) {
     265                 :           2 :         response_ptr += sizeof(uint16_t);
     266                 :           2 :         response_size = libspdm_read_uint32(response_ptr);
     267                 :           2 :         if (spdm_response_size < response_size +
     268                 :           2 :             sizeof(spdm_vendor_defined_response_msg_t) +
     269         [ +  + ]:           2 :             spdm_response->vendor_id_len + sizeof(uint16_t) + sizeof(uint32_t)) {
     270                 :           1 :             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     271                 :           1 :             goto done;
     272                 :             :         }
     273                 :           1 :         response_ptr += sizeof(uint32_t);
     274                 :             :     } else {
     275                 :           3 :         response_size = libspdm_read_uint16(response_ptr);
     276                 :             : 
     277                 :           3 :         if (spdm_response_size < response_size +
     278                 :           3 :             sizeof(spdm_vendor_defined_response_msg_t) +
     279         [ -  + ]:           3 :             spdm_response->vendor_id_len + sizeof(uint16_t)) {
     280                 :           0 :             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     281                 :           0 :             goto done;
     282                 :             :         }
     283                 :           3 :         response_ptr += sizeof(uint16_t);
     284                 :             :     }
     285                 :             : 
     286         [ +  + ]:           4 :     if (*resp_size < response_size) {
     287                 :           2 :         status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
     288                 :           2 :         goto done;
     289                 :             :     }
     290                 :           2 :     libspdm_copy_mem(resp_data, *resp_size, response_ptr, response_size);
     291                 :           2 :     *resp_size = response_size;
     292                 :             : 
     293                 :             :     /* -=[Log Message Phase]=- */
     294                 :             :     #if LIBSPDM_ENABLE_MSG_LOG
     295                 :           2 :     libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
     296                 :             :     #endif /* LIBSPDM_ENABLE_MSG_LOG */
     297                 :             : 
     298                 :           2 :     status = LIBSPDM_STATUS_SUCCESS;
     299                 :          10 : done:
     300                 :          10 :     libspdm_zero_mem(spdm_context->last_spdm_request,
     301                 :          10 :                      libspdm_get_scratch_buffer_last_spdm_request_capacity(spdm_context));
     302                 :          10 :     spdm_context->last_spdm_request_size = 0;
     303                 :             :     /*
     304                 :             :      * receiver buffer "message" contains encrypted message
     305                 :             :      * "spdm_response" contains the plain-text VDM message
     306                 :             :      */
     307                 :          10 :     libspdm_zero_mem(spdm_response, spdm_response_size);
     308                 :          10 :     libspdm_release_receiver_buffer (spdm_context); /* this will free up response-message, need to find workaround */
     309                 :          10 :     return status;
     310                 :             : }
     311                 :             : 
     312                 :          11 : libspdm_return_t libspdm_vendor_send_request_receive_response(
     313                 :             :     void *spdm_context,
     314                 :             :     const uint32_t *session_id,
     315                 :             :     uint16_t req_standard_id,
     316                 :             :     uint8_t req_vendor_id_len,
     317                 :             :     const void *req_vendor_id,
     318                 :             :     uint32_t req_size,
     319                 :             :     const void *req_data,
     320                 :             :     uint16_t *resp_standard_id,
     321                 :             :     uint8_t *resp_vendor_id_len,
     322                 :             :     void *resp_vendor_id,
     323                 :             :     uint32_t *resp_size,
     324                 :             :     void *resp_data)
     325                 :             : {
     326                 :             :     libspdm_context_t *context;
     327                 :             :     size_t retry;
     328                 :             :     uint64_t retry_delay_time;
     329                 :             :     libspdm_return_t status;
     330                 :             : 
     331                 :          11 :     context = spdm_context;
     332                 :          11 :     context->crypto_request = true;
     333                 :          11 :     retry = context->retry_times;
     334                 :          11 :     retry_delay_time = context->retry_delay_time;
     335                 :             :     do {
     336                 :          11 :         status = libspdm_try_vendor_send_request_receive_response(
     337                 :             :             context,
     338                 :             :             session_id,
     339                 :             :             req_standard_id,
     340                 :             :             req_vendor_id_len,
     341                 :             :             req_vendor_id,
     342                 :             :             req_size,
     343                 :             :             req_data,
     344                 :             :             resp_standard_id,
     345                 :             :             resp_vendor_id_len,
     346                 :             :             resp_vendor_id,
     347                 :             :             resp_size,
     348                 :             :             resp_data);
     349         [ +  - ]:          11 :         if (status != LIBSPDM_STATUS_BUSY_PEER) {
     350                 :          11 :             return status;
     351                 :             :         }
     352                 :             : 
     353                 :           0 :         libspdm_sleep(retry_delay_time);
     354         [ #  # ]:           0 :     } while (retry-- != 0);
     355                 :             : 
     356                 :           0 :     return status;
     357                 :             : }
     358                 :             : 
     359                 :             : #endif /* LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES */
        

Generated by: LCOV version 2.0-1