LCOV - code coverage report
Current view: top level - library/spdm_requester_lib - libspdm_req_send_receive.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 83.3 % 354 295
Test Date: 2025-10-12 08:10:56 Functions: 100.0 % 5 5

            Line data    Source code
       1              : /**
       2              :  *  Copyright Notice:
       3              :  *  Copyright 2021-2025 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              : #include "internal/libspdm_secured_message_lib.h"
       9              : 
      10        68204 : libspdm_return_t libspdm_send_request(void *spdm_context, const uint32_t *session_id,
      11              :                                       bool is_app_message,
      12              :                                       size_t request_size, void *request)
      13              : {
      14              :     libspdm_context_t *context;
      15              :     libspdm_return_t status;
      16              :     uint8_t *message;
      17              :     size_t message_size;
      18              :     uint64_t timeout;
      19              :     uint8_t *scratch_buffer;
      20              :     size_t scratch_buffer_size;
      21              :     size_t transport_header_size;
      22              :     uint8_t *sender_buffer;
      23              :     size_t sender_buffer_size;
      24              : 
      25        68204 :     context = spdm_context;
      26              : 
      27        68204 :     LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
      28              :                    "libspdm_send_spdm_request[%x] msg %s(0x%x), size (0x%zx): \n",
      29              :                    (session_id != NULL) ? *session_id : 0x0,
      30              :                    libspdm_get_code_str(((spdm_message_header_t *)request)->request_response_code),
      31              :                    ((spdm_message_header_t *)request)->request_response_code, request_size));
      32        68204 :     LIBSPDM_INTERNAL_DUMP_HEX(request, request_size);
      33              : 
      34        68204 :     transport_header_size = context->local_context.capability.transport_header_size;
      35        68204 :     libspdm_get_scratch_buffer(context, (void **)&scratch_buffer, &scratch_buffer_size);
      36        68204 :     libspdm_get_sender_buffer(context, (void **)&sender_buffer, &sender_buffer_size);
      37              : 
      38              :     /* This is a problem because original code assumes request is in the sender buffer,
      39              :      * when it can really be using the scratch space for chunking.
      40              :      * Did not want to modify all request handlers to pass this information,
      41              :      * so just making the determination here by examining scratch/sender buffers.
      42              :      * This may be something that should be refactored in the future. */
      43              :     #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
      44        68204 :     if ((uint8_t *)request >= sender_buffer &&
      45        68204 :         (uint8_t *)request < sender_buffer + sender_buffer_size) {
      46            0 :         message = sender_buffer;
      47            0 :         message_size = sender_buffer_size;
      48              :     } else {
      49        68204 :         if ((uint8_t *)request >=
      50        68204 :             scratch_buffer + libspdm_get_scratch_buffer_sender_receiver_offset(spdm_context)
      51        68204 :             && (uint8_t *)request <
      52       136408 :             scratch_buffer + libspdm_get_scratch_buffer_sender_receiver_offset(spdm_context)
      53        68204 :             + libspdm_get_scratch_buffer_sender_receiver_capacity(spdm_context)) {
      54       131260 :             message = scratch_buffer +
      55        65630 :                       libspdm_get_scratch_buffer_sender_receiver_offset(spdm_context);
      56        65630 :             message_size = libspdm_get_scratch_buffer_sender_receiver_capacity(spdm_context);
      57         2574 :         } else if ((uint8_t *)request >=
      58         5148 :                    scratch_buffer +
      59         2574 :                    libspdm_get_scratch_buffer_large_sender_receiver_offset(spdm_context)
      60         2574 :                    && (uint8_t *)request <
      61              :                    scratch_buffer +
      62         2574 :                    libspdm_get_scratch_buffer_large_sender_receiver_offset(spdm_context) +
      63         2574 :                    libspdm_get_scratch_buffer_large_sender_receiver_capacity(spdm_context)) {
      64         5148 :             message = scratch_buffer +
      65         2574 :                       libspdm_get_scratch_buffer_large_sender_receiver_offset(spdm_context);
      66         2574 :             message_size = libspdm_get_scratch_buffer_large_sender_receiver_capacity(spdm_context);
      67              :         }
      68              :     }
      69              :     #else /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
      70              :     message = sender_buffer;
      71              :     message_size = sender_buffer_size;
      72              :     #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
      73              : 
      74        68204 :     if (session_id != NULL) {
      75              :         /* For secure message, message is in sender buffer, we need copy it to scratch buffer.
      76              :          * transport_message is always in sender buffer. */
      77              : 
      78          244 :         libspdm_copy_mem (scratch_buffer + transport_header_size,
      79              :                           scratch_buffer_size - transport_header_size,
      80              :                           request, request_size);
      81          244 :         request = scratch_buffer + transport_header_size;
      82              :     }
      83              : 
      84              :     /* backup it to last_spdm_request, because the caller wants to compare it with response */
      85        68204 :     if (((const spdm_message_header_t *)request)->request_response_code != SPDM_RESPOND_IF_READY
      86        68175 :         && ((const spdm_message_header_t *)request)->request_response_code != SPDM_CHUNK_GET
      87         2561 :         && ((const spdm_message_header_t *)request)->request_response_code != SPDM_CHUNK_SEND) {
      88         2545 :         libspdm_copy_mem (context->last_spdm_request,
      89         2545 :                           libspdm_get_scratch_buffer_last_spdm_request_capacity(context),
      90              :                           request,
      91              :                           request_size);
      92         2545 :         context->last_spdm_request_size = request_size;
      93              :     }
      94              : 
      95        68204 :     status = context->transport_encode_message(
      96              :         context, session_id, is_app_message, true, request_size,
      97              :         request, &message_size, (void **)&message);
      98        68204 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
      99            0 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "transport_encode_message status - %xu\n", status));
     100            0 :         if ((session_id != NULL) &&
     101            0 :             ((status == LIBSPDM_STATUS_SEQUENCE_NUMBER_OVERFLOW) ||
     102              :              (status == LIBSPDM_STATUS_CRYPTO_ERROR))) {
     103            0 :             libspdm_free_session_id(context, *session_id);
     104              :         }
     105            0 :         return status;
     106              :     }
     107              : 
     108        68204 :     timeout = context->local_context.capability.rtt;
     109        68204 :     status = context->send_message(context, message_size, message, timeout);
     110              : 
     111        68204 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     112           25 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "libspdm_send_spdm_request[%x] status - %xu\n",
     113              :                        (session_id != NULL) ? *session_id : 0x0, status));
     114              :     }
     115              : 
     116        68204 :     return status;
     117              : }
     118              : 
     119        68172 : libspdm_return_t libspdm_receive_response(void *spdm_context, const uint32_t *session_id,
     120              :                                           bool is_app_message,
     121              :                                           size_t *response_size,
     122              :                                           void **response)
     123              : {
     124              :     libspdm_context_t *context;
     125              :     void *temp_session_context;
     126              :     libspdm_return_t status;
     127              :     uint8_t *message;
     128              :     size_t message_size;
     129              :     uint32_t *message_session_id;
     130              :     uint32_t message_id;
     131              :     bool is_message_app_message;
     132              :     uint64_t timeout;
     133              :     size_t transport_header_size;
     134              :     uint8_t *scratch_buffer;
     135              :     size_t scratch_buffer_size;
     136              :     void *backup_response;
     137              :     size_t backup_response_size;
     138              :     bool reset_key_update;
     139              :     bool result;
     140              : 
     141        68172 :     context = spdm_context;
     142              : 
     143        68172 :     if (context->crypto_request) {
     144        67980 :         timeout = context->local_context.capability.rtt +
     145        67980 :                   ((uint64_t)1 << context->connection_info.capability.ct_exponent);
     146              :     } else {
     147          192 :         timeout = context->local_context.capability.rtt + context->local_context.capability.st1;
     148              :     }
     149              : 
     150        68172 :     message = *response;
     151        68172 :     message_size = *response_size;
     152        68172 :     status = context->receive_message(context, &message_size, (void **)&message, timeout);
     153        68172 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     154            9 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
     155              :                        "libspdm_receive_spdm_response[%x] status - %xu\n",
     156              :                        (session_id != NULL) ? *session_id : 0x0, status));
     157            9 :         return status;
     158              :     }
     159              : 
     160              :     /*
     161              :      * The storage transport encoding, defined by DSP0286, does not indicate
     162              :      * if we are/are not in a secure session in the transport data. This is
     163              :      * different to most other transport encodings, which includes session
     164              :      * information in the encoding.
     165              :      *
     166              :      * As such if we are in a secure session, session_id != NULL, we set
     167              :      * message_session_id to be non-NULL to indicate to the lower layer
     168              :      * that we are in a secure session.
     169              :      */
     170        68163 :     if (session_id != NULL) {
     171          237 :         message_session_id = &message_id;
     172          237 :         message_id = *session_id;
     173              :     } else {
     174        67926 :         message_session_id = NULL;
     175              :     }
     176        68163 :     is_message_app_message = false;
     177              : 
     178              :     /* always use scratch buffer to response.
     179              :      * if it is secured message, this scratch buffer will be used.
     180              :      * if it is normal message, the response ptr will point to receiver buffer. */
     181        68163 :     transport_header_size = context->local_context.capability.transport_header_size;
     182        68163 :     libspdm_get_scratch_buffer (context, (void **)&scratch_buffer, &scratch_buffer_size);
     183              :     #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
     184        68163 :     *response = scratch_buffer + libspdm_get_scratch_buffer_secure_message_offset(context) +
     185              :                 transport_header_size;
     186        68163 :     *response_size = libspdm_get_scratch_buffer_secure_message_capacity(context) -
     187              :                      transport_header_size;
     188              :     #else
     189              :     *response = scratch_buffer + transport_header_size;
     190              :     *response_size = scratch_buffer_size - transport_header_size;
     191              :     #endif
     192              : 
     193        68163 :     backup_response = *response;
     194        68163 :     backup_response_size = *response_size;
     195              : 
     196        68163 :     status = context->transport_decode_message(
     197              :         context, &message_session_id, &is_message_app_message,
     198              :         false, message_size, message, response_size, response);
     199              : 
     200        68163 :     reset_key_update = false;
     201        68163 :     temp_session_context = NULL;
     202              : 
     203        68163 :     if (status == LIBSPDM_STATUS_SESSION_TRY_DISCARD_KEY_UPDATE) {
     204              :         /* Failed to decode, but have backup keys. Try rolling back before aborting.
     205              :          * message_session_id must be valid for us to have attempted decryption. */
     206           27 :         if (message_session_id == NULL) {
     207            0 :             return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
     208              :         }
     209           27 :         temp_session_context = libspdm_get_secured_message_context_via_session_id(
     210              :             context, *message_session_id);
     211           27 :         if (temp_session_context == NULL) {
     212            0 :             return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
     213              :         }
     214              : 
     215           27 :         result = libspdm_activate_update_session_data_key(
     216              :             temp_session_context, LIBSPDM_KEY_UPDATE_ACTION_RESPONDER, false);
     217           27 :         if (!result) {
     218            0 :             return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
     219              :         }
     220              : 
     221              :         /* Retry decoding message with backup Requester key.
     222              :          * Must reset some of the parameters in case they were modified */
     223           27 :         if (session_id != NULL) {
     224           27 :             *message_session_id = *session_id;
     225              :         } else {
     226            0 :             message_session_id = NULL;
     227              :         }
     228           27 :         is_message_app_message = false;
     229           27 :         *response = backup_response;
     230           27 :         *response_size = backup_response_size;
     231           27 :         status = context->transport_decode_message(
     232              :             context, &message_session_id, &is_message_app_message,
     233              :             false, message_size, message, response_size, response);
     234              : 
     235           27 :         reset_key_update = true;
     236              :     }
     237              : 
     238        68163 :     if (session_id != NULL) {
     239          237 :         if (message_session_id == NULL) {
     240            0 :             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
     241              :                            "libspdm_receive_spdm_response[%x] GetSessionId - NULL\n",
     242              :                            (session_id != NULL) ? *session_id : 0x0));
     243            0 :             goto error;
     244              :         }
     245          237 :         if (*message_session_id != *session_id) {
     246            0 :             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
     247              :                            "libspdm_receive_spdm_response[%x] GetSessionId - %x\n",
     248              :                            (session_id != NULL) ? *session_id : 0x0, *message_session_id));
     249            0 :             goto error;
     250              :         }
     251              :     } else {
     252        67926 :         if (message_session_id != NULL) {
     253            0 :             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
     254              :                            "libspdm_receive_spdm_response[%x] GetSessionId - %x\n",
     255              :                            (session_id != NULL) ? *session_id : 0x0, *message_session_id));
     256            0 :             goto error;
     257              :         }
     258              :     }
     259              : 
     260        68163 :     if ((is_app_message && !is_message_app_message) ||
     261        68163 :         (!is_app_message && is_message_app_message)) {
     262            0 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
     263              :                        "libspdm_receive_spdm_response[%x] app_message mismatch\n",
     264              :                        (session_id != NULL) ? *session_id : 0x0));
     265            0 :         goto error;
     266              :     }
     267              : 
     268        68163 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     269            0 :         if ((session_id != NULL) &&
     270            0 :             (context->last_spdm_error.error_code == SPDM_ERROR_CODE_DECRYPT_ERROR)) {
     271            0 :             libspdm_free_session_id(context, *session_id);
     272              :         }
     273            0 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
     274              :                        "libspdm_receive_spdm_response[%x] status - %xu\n",
     275              :                        (session_id != NULL) ? *session_id : 0x0, status));
     276              :     } else {
     277        68163 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
     278              :                        "libspdm_receive_spdm_response[%x] msg %s(0x%x), size (0x%zx): \n",
     279              :                        (session_id != NULL) ? *session_id : 0x0,
     280              :                        libspdm_get_code_str(((spdm_message_header_t *)*response)->
     281              :                                             request_response_code),
     282              :                        ((spdm_message_header_t *)*response)->request_response_code,
     283              :                        *response_size));
     284        68163 :         LIBSPDM_INTERNAL_DUMP_HEX(*response, *response_size);
     285              :     }
     286              : 
     287              :     /* Handle special case:
     288              :      * If the Responder returns RESPONSE_NOT_READY error to KEY_UPDATE, the Requester needs
     289              :      * to activate backup key to parse the error. Then later the Responder will return SUCCESS,
     290              :      * the Requester needs new key. So we need to restore the environment by
     291              :      * libspdm_create_update_session_data_key() again.*/
     292        68163 :     if (reset_key_update) {
     293              :         /* temp_session_context and message_session_id must necessarily
     294              :          * be valid for us to reach here. */
     295           27 :         if (temp_session_context == NULL || message_session_id == NULL) {
     296            0 :             return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
     297              :         }
     298           27 :         result = libspdm_create_update_session_data_key(
     299              :             temp_session_context, LIBSPDM_KEY_UPDATE_ACTION_RESPONDER);
     300           27 :         if (!result) {
     301            0 :             return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
     302              :         }
     303              :     }
     304              : 
     305        68163 :     return status;
     306              : 
     307            0 : error:
     308            0 :     if (context->last_spdm_error.error_code == SPDM_ERROR_CODE_DECRYPT_ERROR) {
     309            0 :         return LIBSPDM_STATUS_SESSION_MSG_ERROR;
     310              :     } else {
     311            0 :         return LIBSPDM_STATUS_RECEIVE_FAIL;
     312              :     }
     313              : }
     314              : 
     315              : #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
     316           14 : libspdm_return_t libspdm_handle_large_request(
     317              :     libspdm_context_t *spdm_context,
     318              :     const uint32_t *session_id,
     319              :     size_t request_size, void *request)
     320              : {
     321              :     libspdm_return_t status;
     322              : 
     323              :     spdm_chunk_send_request_t *spdm_request;
     324              :     spdm_chunk_send_request_14_t *spdm_request_14;
     325              :     size_t spdm_request_size;
     326              :     spdm_chunk_send_ack_response_t *spdm_response;
     327              :     spdm_chunk_send_ack_response_14_t *spdm_response_14;
     328              :     size_t response_header_size;
     329              :     uint8_t *message;
     330              :     size_t message_size;
     331              :     void *response;
     332              :     size_t response_size;
     333              :     size_t transport_header_size;
     334              : 
     335              :     uint8_t *scratch_buffer;
     336              :     size_t scratch_buffer_size;
     337              : 
     338              :     uint8_t *chunk_ptr;
     339              :     size_t copy_size;
     340              :     libspdm_chunk_info_t *send_info;
     341              :     uint32_t min_data_transfer_size;
     342              :     uint64_t max_chunk_data_transfer_size;
     343              :     spdm_error_response_t *spdm_error;
     344              : 
     345           14 :     if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_12) {
     346            0 :         return LIBSPDM_STATUS_UNSUPPORTED_CAP;
     347              :     }
     348              : 
     349              :     /* Fail if requester or responder does not support chunk cap */
     350           14 :     if (!libspdm_is_capabilities_flag_supported(
     351              :             spdm_context, true,
     352              :             SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP,
     353              :             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP)) {
     354            0 :         return LIBSPDM_STATUS_ERROR_PEER;
     355              :     }
     356              : 
     357              :     /* Fail if exceed max chunks */
     358           14 :     min_data_transfer_size = LIBSPDM_MIN(
     359              :         spdm_context->connection_info.capability.data_transfer_size,
     360              :         spdm_context->local_context.capability.sender_data_transfer_size);
     361              : 
     362           14 :     if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_14) {
     363              :         /* chunk seq no wrap not considered in spdm 1.4+ */
     364              : 
     365           13 :         max_chunk_data_transfer_size =
     366           13 :             ((size_t) min_data_transfer_size - sizeof(spdm_chunk_send_request_t)) * 65536 -
     367              :             sizeof(uint32_t);
     368              :         /* max_spdm_msg_size is already checked in caller */
     369              : 
     370           13 :         if (request_size > max_chunk_data_transfer_size) {
     371            1 :             return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
     372              :         }
     373              :     }
     374              :     /* now we can get sender buffer */
     375           13 :     transport_header_size = spdm_context->local_context.capability.transport_header_size;
     376              : 
     377           13 :     libspdm_get_scratch_buffer(spdm_context, (void **)&scratch_buffer, &scratch_buffer_size);
     378              : 
     379              :     /* Temporary send/receive buffers for chunking are in the scratch space */
     380           13 :     message = scratch_buffer + libspdm_get_scratch_buffer_sender_receiver_offset(spdm_context);
     381           13 :     message_size = libspdm_get_scratch_buffer_sender_receiver_capacity(spdm_context);
     382              : 
     383           13 :     send_info = &spdm_context->chunk_context.send;
     384           13 :     send_info->chunk_in_use = true;
     385              : 
     386              :     /* The first section of the scratch
     387              :      * buffer may be used for other purposes. Use only after that section. */
     388           26 :     send_info->large_message = scratch_buffer +
     389           13 :                                libspdm_get_scratch_buffer_large_message_offset(spdm_context);
     390           13 :     send_info->large_message_capacity =
     391           13 :         libspdm_get_scratch_buffer_large_message_capacity(spdm_context);
     392              : 
     393           13 :     libspdm_zero_mem(send_info->large_message, send_info->large_message_capacity);
     394           13 :     libspdm_copy_mem(send_info->large_message, send_info->large_message_capacity,
     395              :                      request, request_size);
     396              : 
     397           13 :     send_info->large_message_size = request_size;
     398           13 :     send_info->chunk_bytes_transferred = 0;
     399           13 :     send_info->chunk_seq_no = 0;
     400           13 :     request = NULL; /* Invalidate to prevent accidental use. */
     401           13 :     request_size = 0;
     402              : 
     403              :     do {
     404           16 :         LIBSPDM_ASSERT(send_info->large_message_capacity >= transport_header_size);
     405           16 :         spdm_request = (spdm_chunk_send_request_t *)((uint8_t *)message + transport_header_size);
     406           16 :         spdm_request_size = message_size - transport_header_size;
     407              : 
     408           16 :         spdm_request->header.spdm_version = libspdm_get_connection_version(spdm_context);
     409           16 :         spdm_request->header.request_response_code = SPDM_CHUNK_SEND;
     410           16 :         spdm_request->header.param1 = 0;
     411           16 :         spdm_request->header.param2 = send_info->chunk_handle;
     412              : 
     413           16 :         if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_14) {
     414           14 :             spdm_request->chunk_seq_no = (uint16_t) send_info->chunk_seq_no;
     415           14 :             spdm_request->reserved = 0;
     416           14 :             chunk_ptr = (uint8_t *)(spdm_request + 1);
     417              :         } else {
     418            2 :             spdm_request_14 = (spdm_chunk_send_request_14_t *)spdm_request;
     419            2 :             spdm_request_14->chunk_seq_no = send_info->chunk_seq_no;
     420            2 :             chunk_ptr = (uint8_t *)(spdm_request_14 + 1);
     421              :         }
     422              : 
     423              :         LIBSPDM_ASSERT(sizeof(spdm_chunk_send_request_t) == sizeof(spdm_chunk_send_request_14_t));
     424           16 :         if ((min_data_transfer_size - sizeof(spdm_chunk_send_request_t)) <
     425           16 :             (send_info->large_message_size - send_info->chunk_bytes_transferred)) {
     426           13 :             copy_size = min_data_transfer_size - sizeof(spdm_chunk_send_request_t);
     427              :         } else {
     428            3 :             copy_size = (send_info->large_message_size - send_info->chunk_bytes_transferred);
     429              :         }
     430              : 
     431           16 :         if (send_info->chunk_seq_no == 0) {
     432           13 :             *(uint32_t *)(spdm_request + 1) = (uint32_t)send_info->large_message_size;
     433           13 :             chunk_ptr += sizeof(uint32_t);
     434           13 :             copy_size -= sizeof(uint32_t);
     435              :         }
     436              : 
     437           16 :         spdm_request->chunk_size = (uint32_t)copy_size;
     438              : 
     439           16 :         libspdm_copy_mem(
     440           16 :             chunk_ptr, spdm_request_size - ((uint8_t *)spdm_request - (uint8_t *)message),
     441           16 :             (uint8_t *)send_info->large_message + send_info->chunk_bytes_transferred, copy_size);
     442              : 
     443           16 :         send_info->chunk_bytes_transferred += copy_size;
     444           16 :         if (send_info->chunk_bytes_transferred >= send_info->large_message_size) {
     445            3 :             spdm_request->header.param1 |= SPDM_CHUNK_SEND_REQUEST_ATTRIBUTE_LAST_CHUNK;
     446              :         }
     447              : 
     448           16 :         spdm_request_size = (chunk_ptr + copy_size) - (uint8_t *)spdm_request;
     449           16 :         status = libspdm_send_request(
     450              :             spdm_context, session_id, false,
     451              :             spdm_request_size, spdm_request);
     452              : 
     453           16 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     454            1 :             break;
     455              :         }
     456              : 
     457           15 :         response = message;
     458           15 :         response_size = message_size;
     459              : 
     460           15 :         libspdm_zero_mem(response, response_size);
     461              : 
     462           15 :         status = libspdm_receive_response(
     463              :             spdm_context, session_id, false,
     464              :             &response_size, &response);
     465              : 
     466           15 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     467            1 :             break;
     468              :         }
     469           14 :         spdm_response = (void *)(response);
     470              : 
     471           14 :         if (response_size < sizeof(spdm_message_header_t)) {
     472            0 :             status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     473            0 :             break;
     474              :         }
     475              : 
     476           14 :         if (spdm_response->header.request_response_code == SPDM_ERROR
     477            2 :             && spdm_response->header.param1 != SPDM_ERROR_CODE_LARGE_RESPONSE) {
     478            2 :             status = libspdm_handle_simple_error_response(spdm_context,
     479            2 :                                                           spdm_response->header.param1);
     480            2 :             break;
     481              :         }
     482              : 
     483           12 :         if (spdm_response->header.spdm_version != libspdm_get_connection_version(spdm_context)) {
     484            1 :             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     485            1 :             break;
     486              :         }
     487              : 
     488           11 :         if (spdm_response->header.request_response_code == SPDM_ERROR
     489            0 :             && spdm_response->header.param1 == SPDM_ERROR_CODE_LARGE_RESPONSE) {
     490              : 
     491              :             /* It is possible that the CHUNK_SEND_ACK + chunk response is larger
     492              :              * than the DATA_TRANSFER_SIZE. In this case an ERROR_LARGE_RESPONSE
     493              :              * is returned directly in the response buffer rather than part of
     494              :              * the CHUNK_SEND_ACK. Store this error response in scratch buffer
     495              :              * to be handled when reading response. Also note that in this case
     496              :              * of large response, the CHUNK_SEND_ACK portion is not sent.
     497              :              * Only the response portion that requires the CHUNK_GET is sent */
     498            0 :             if (response_size < send_info->large_message_capacity) {
     499            0 :                 libspdm_copy_mem(
     500              :                     send_info->large_message, send_info->large_message_capacity,
     501              :                     spdm_response, response_size);
     502            0 :                 send_info->large_message_size = response_size;
     503            0 :                 break;
     504              :             } else {
     505            0 :                 status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     506            0 :                 break;
     507              :             }
     508              :         } else {
     509           11 :             if (spdm_response->header.request_response_code != SPDM_CHUNK_SEND_ACK) {
     510            0 :                 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     511            0 :                 break;
     512              :             }
     513              : 
     514           11 :             if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_14) {
     515            9 :                 response_header_size = sizeof(spdm_chunk_send_ack_response_t);
     516              :             } else {
     517            2 :                 response_header_size = sizeof(spdm_chunk_send_ack_response_14_t);
     518            2 :                 spdm_response_14 = (spdm_chunk_send_ack_response_14_t *)spdm_response;
     519              :             }
     520              : 
     521           11 :             if (response_size < response_header_size) {
     522            1 :                 status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     523            1 :                 break;
     524              :             }
     525           10 :             if (spdm_response->header.param1
     526           10 :                 & SPDM_CHUNK_SEND_ACK_RESPONSE_ATTRIBUTE_EARLY_ERROR_DETECTED) {
     527              : 
     528            2 :                 spdm_error = (spdm_error_response_t *)((uint8_t *)spdm_response + response_header_size);
     529            2 :                 if (response_size < (response_header_size +
     530              :                                      sizeof(spdm_error_response_t))) {
     531            0 :                     status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     532            0 :                     break;
     533              :                 }
     534            2 :                 if ((spdm_error->header.spdm_version !=
     535            2 :                      libspdm_get_connection_version(spdm_context)) ||
     536            2 :                     (spdm_error->header.request_response_code != SPDM_ERROR)) {
     537            0 :                     status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     538            0 :                     break;
     539              :                 }
     540            2 :                 if (spdm_error->header.param1 == SPDM_ERROR_CODE_LARGE_RESPONSE) {
     541            1 :                     status = LIBSPDM_STATUS_ERROR_PEER;
     542            1 :                     break;
     543              :                 }
     544              : 
     545              :                 /* Store the error response in scratch buffer to be read by
     546              :                  * libspdm_receive_spdm_response and returned to its caller
     547              :                  * and handled in the error response handling flow */
     548            1 :                 libspdm_copy_mem(
     549              :                     send_info->large_message,
     550              :                     send_info->large_message_capacity,
     551              :                     (uint8_t *)spdm_response + response_header_size,
     552              :                     response_size - response_header_size);
     553              : 
     554            1 :                 send_info->large_message_size =
     555            1 :                     (response_size - response_header_size);
     556            1 :                 status = LIBSPDM_STATUS_SUCCESS;
     557            1 :                 break;
     558              :             }
     559            8 :             if (spdm_response->header.param2 != send_info->chunk_handle) {
     560            1 :                 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     561            1 :                 break;
     562              :             }
     563            7 :             if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_14) {
     564            5 :                 if (send_info->chunk_seq_no != spdm_response->chunk_seq_no) {
     565            1 :                     status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     566            1 :                     break;
     567              :                 }
     568              :             } else {
     569            2 :                 if (send_info->chunk_seq_no != spdm_response_14->chunk_seq_no) {
     570            0 :                     status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     571            0 :                     break;
     572              :                 }
     573              :             }
     574              : 
     575            6 :             chunk_ptr = (uint8_t *)spdm_response + response_header_size;
     576            6 :             send_info->chunk_seq_no++;
     577              : 
     578            6 :             if (send_info->chunk_bytes_transferred >= send_info->large_message_size) {
     579              :                 /* All bytes have been transferred. Store response in scratch buffer
     580              :                  * to be read by libspdm_receive_spdm_response */
     581            3 :                 libspdm_copy_mem(
     582              :                     send_info->large_message, send_info->large_message_capacity,
     583              :                     chunk_ptr, response_size - response_header_size);
     584            3 :                 send_info->large_message_size =
     585            3 :                     (response_size - response_header_size);
     586            3 :                 break;
     587              :             }
     588              :         }
     589              : 
     590            3 :     } while (LIBSPDM_STATUS_IS_SUCCESS(status)
     591            3 :              && send_info->chunk_bytes_transferred < send_info->large_message_size);
     592              : 
     593           13 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     594            9 :         send_info->chunk_in_use = false;
     595            9 :         send_info->chunk_handle++; /* Implicit wrap-around*/
     596            9 :         send_info->chunk_seq_no = 0;
     597            9 :         send_info->chunk_bytes_transferred = 0;
     598            9 :         send_info->large_message = NULL;
     599            9 :         send_info->large_message_size = 0;
     600              :     }
     601              : 
     602           13 :     return status;
     603              : }
     604              : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
     605              : 
     606        68203 : libspdm_return_t libspdm_send_spdm_request(libspdm_context_t *spdm_context,
     607              :                                            const uint32_t *session_id,
     608              :                                            size_t request_size, void *request)
     609              : {
     610              :     libspdm_session_info_t *session_info;
     611              :     libspdm_session_state_t session_state;
     612              :     libspdm_return_t status;
     613              :     #if LIBSPDM_ENABLE_MSG_LOG
     614              :     size_t msg_log_size;
     615              :     #endif /* LIBSPDM_ENABLE_MSG_LOG */
     616              : 
     617              :     /* If chunking is not supported then message must fit in both the send buffer and the receive
     618              :      * buffer. */
     619        68203 :     if (!libspdm_is_capabilities_flag_supported(
     620              :             spdm_context, true,
     621              :             SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP,
     622              :             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP)) {
     623         2563 :         if ((spdm_context->connection_info.capability.data_transfer_size != 0) &&
     624            0 :             (request_size > spdm_context->connection_info.capability.data_transfer_size)) {
     625            0 :             return LIBSPDM_STATUS_PEER_BUFFER_TOO_SMALL;
     626              :         }
     627         2563 :         if ((spdm_context->local_context.capability.sender_data_transfer_size != 0) &&
     628         2563 :             (request_size > spdm_context->local_context.capability.sender_data_transfer_size)) {
     629            0 :             return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
     630              :         }
     631              :     }
     632              : 
     633        68485 :     if ((session_id != NULL) &&
     634          282 :         libspdm_is_capabilities_flag_supported(
     635              :             spdm_context, true,
     636              :             SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP,
     637              :             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) {
     638           38 :         session_info = libspdm_get_session_info_via_session_id(spdm_context, *session_id);
     639           38 :         LIBSPDM_ASSERT(session_info != NULL);
     640           38 :         if (session_info == NULL) {
     641            0 :             return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
     642              :         }
     643           38 :         session_state = libspdm_secured_message_get_session_state(
     644              :             session_info->secured_message_context);
     645           38 :         if ((session_state == LIBSPDM_SESSION_STATE_HANDSHAKING) && !session_info->use_psk) {
     646           38 :             session_id = NULL;
     647              :         }
     648              :     }
     649              : 
     650        68203 :     if ((spdm_context->connection_info.capability.max_spdm_msg_size != 0) &&
     651        65567 :         (request_size > spdm_context->connection_info.capability.max_spdm_msg_size)) {
     652            1 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "request_size > rsp max_spdm_msg_size\n"));
     653            1 :         return LIBSPDM_STATUS_PEER_BUFFER_TOO_SMALL;
     654              :     }
     655        68202 :     LIBSPDM_ASSERT (request_size <= spdm_context->local_context.capability.max_spdm_msg_size);
     656              : 
     657              :     #if LIBSPDM_ENABLE_MSG_LOG
     658              :     /* First save the size of the message log buffer. If there is an error it will be reverted. */
     659        68202 :     msg_log_size = libspdm_get_msg_log_size(spdm_context);
     660        68202 :     libspdm_append_msg_log(spdm_context, request, request_size);
     661              :     #endif /* LIBSPDM_ENABLE_MSG_LOG */
     662              : 
     663              :     /* large SPDM message is the SPDM message whose size is greater than the DataTransferSize of the receiving
     664              :      * SPDM endpoint or greater than the transmit buffer size of the sending SPDM endpoint */
     665        68202 :     if (((const spdm_message_header_t *)request)->request_response_code != SPDM_GET_VERSION
     666        68164 :         && ((const spdm_message_header_t *)request)->request_response_code != SPDM_GET_CAPABILITIES
     667        68097 :         && ((spdm_context->connection_info.capability.data_transfer_size != 0 &&
     668        65564 :              request_size > spdm_context->connection_info.capability.data_transfer_size) ||
     669        68084 :             (spdm_context->local_context.capability.sender_data_transfer_size != 0 &&
     670        68084 :              request_size > spdm_context->local_context.capability.sender_data_transfer_size))) {
     671              : 
     672              :         #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
     673              :         /* libspdm_send_request is not called with the original request in this flow.
     674              :          * This leads to the last_spdm_request field not having the original request value.
     675              :          * The caller assumes the request has been copied to last_spdm_request,
     676              :          * so that it can compare last_spdm_request's fields with response fields
     677              :          * Therefore the request must be copied to last_spdm_request here. */
     678              : 
     679           14 :         if (((const spdm_message_header_t *)request)->request_response_code != SPDM_RESPOND_IF_READY
     680           14 :             && ((const spdm_message_header_t *)request)->request_response_code != SPDM_CHUNK_GET
     681           14 :             && ((const spdm_message_header_t *)request)->request_response_code != SPDM_CHUNK_SEND) {
     682           14 :             libspdm_copy_mem(
     683              :                 spdm_context->last_spdm_request,
     684           14 :                 libspdm_get_scratch_buffer_last_spdm_request_capacity(spdm_context),
     685              :                 request, request_size);
     686           14 :             spdm_context->last_spdm_request_size = request_size;
     687              :         }
     688              : 
     689           14 :         status = libspdm_handle_large_request(
     690              :             spdm_context, session_id, request_size, request);
     691              :         #else  /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP*/
     692              :         status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
     693              :         #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP*/
     694              :     } else {
     695        68188 :         status = libspdm_send_request(spdm_context, session_id, false, request_size, request);
     696              :     }
     697              : 
     698              :     #if LIBSPDM_ENABLE_MSG_LOG
     699              :     /* If there is an error in sending the request then revert the request in the message log. */
     700        68202 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     701           34 :         spdm_context->msg_log.buffer_size = msg_log_size;
     702              :     }
     703              :     #endif /* LIBSPDM_ENABLE_MSG_LOG */
     704              : 
     705        68202 :     return status;
     706              : }
     707              : 
     708        68161 : libspdm_return_t libspdm_receive_spdm_response(libspdm_context_t *spdm_context,
     709              :                                                const uint32_t *session_id,
     710              :                                                size_t *response_size,
     711              :                                                void **response)
     712              : {
     713              :     libspdm_return_t status;
     714              :     libspdm_session_info_t *session_info;
     715              :     libspdm_session_state_t session_state;
     716              : 
     717              :     #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
     718              :     spdm_message_header_t *spdm_response;
     719              :     size_t response_capacity;
     720              :     libspdm_chunk_info_t *send_info;
     721              :     #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
     722              : 
     723        68436 :     if ((session_id != NULL) &&
     724          275 :         libspdm_is_capabilities_flag_supported(
     725              :             spdm_context, true,
     726              :             SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP,
     727              :             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) {
     728           37 :         session_info = libspdm_get_session_info_via_session_id(spdm_context, *session_id);
     729           37 :         LIBSPDM_ASSERT(session_info != NULL);
     730           37 :         if (session_info == NULL) {
     731            0 :             return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
     732              :         }
     733           37 :         session_state = libspdm_secured_message_get_session_state(
     734              :             session_info->secured_message_context);
     735           37 :         if ((session_state == LIBSPDM_SESSION_STATE_HANDSHAKING) && !session_info->use_psk) {
     736           37 :             session_id = NULL;
     737              :         }
     738              :     }
     739              : 
     740              :     #if !(LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP)
     741              :     status = libspdm_receive_response(spdm_context, session_id, false, response_size, response);
     742              :     #else /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
     743        68161 :     send_info = &spdm_context->chunk_context.send;
     744        68161 :     if (send_info->chunk_in_use) {
     745            4 :         libspdm_copy_mem(*response, *response_size,
     746            4 :                          send_info->large_message, send_info->large_message_size);
     747            4 :         *response_size = send_info->large_message_size;
     748            4 :         response_capacity = send_info->large_message_capacity;
     749              : 
     750              :         /* This response may either be an actual response or ERROR_LARGE_RESPONSE,
     751              :          * the latter which should be handled in the large response handler. */
     752            4 :         send_info->chunk_in_use = false;
     753            4 :         send_info->chunk_handle++; /* Implicit wrap-around*/
     754            4 :         send_info->chunk_seq_no = 0;
     755            4 :         send_info->chunk_bytes_transferred = 0;
     756            4 :         send_info->large_message = NULL;
     757            4 :         send_info->large_message_size = 0;
     758            4 :         send_info->large_message_capacity = 0;
     759            4 :         status = LIBSPDM_STATUS_SUCCESS;
     760              :     } else {
     761        68157 :         response_capacity = *response_size;
     762        68157 :         status = libspdm_receive_response(spdm_context, session_id, false, response_size, response);
     763        68157 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     764            8 :             goto receive_done;
     765              :         }
     766              :     }
     767              : 
     768        68153 :     spdm_response = (spdm_message_header_t *)(*response);
     769              : 
     770        68153 :     if (*response_size < sizeof(spdm_message_header_t)) {
     771            0 :         status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     772            0 :         goto receive_done;
     773              :     }
     774              : 
     775        68153 :     if (spdm_response->request_response_code == SPDM_ERROR
     776          475 :         && spdm_response->param1 == SPDM_ERROR_CODE_LARGE_RESPONSE) {
     777            8 :         status = libspdm_handle_error_large_response(
     778              :             spdm_context, session_id,
     779              :             response_size, (void *)spdm_response, response_capacity);
     780              : 
     781            8 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     782            2 :             goto receive_done;
     783              :         }
     784              : 
     785            6 :         if (*response_size < sizeof(spdm_message_header_t)) {
     786            0 :             status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     787            0 :             goto receive_done;
     788              :         }
     789              : 
     790              :         /* Per the spec, SPDM_VERSION and SPDM_CAPABILITIES shall not be chunked
     791              :          * and should be an unexpected error. */
     792            6 :         if (spdm_response->request_response_code == SPDM_VERSION ||
     793            6 :             spdm_response->request_response_code == SPDM_CAPABILITIES) {
     794            0 :             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     795            0 :             goto receive_done;
     796              :         }
     797              :     }
     798              : 
     799        68151 : receive_done:
     800              :     #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
     801              : 
     802        68161 :     return status;
     803              : }
        

Generated by: LCOV version 2.0-1