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.4 % 355 296
Test Date: 2025-11-23 08:10:21 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        68219 : 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        68219 :     context = spdm_context;
      26              : 
      27        68219 :     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        68219 :     LIBSPDM_INTERNAL_DUMP_HEX(request, request_size);
      33              : 
      34        68219 :     transport_header_size = context->local_context.capability.transport_header_size;
      35        68219 :     libspdm_get_scratch_buffer(context, (void **)&scratch_buffer, &scratch_buffer_size);
      36        68219 :     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        68219 :     if ((uint8_t *)request >= sender_buffer &&
      45        68219 :         (uint8_t *)request < sender_buffer + sender_buffer_size) {
      46            0 :         message = sender_buffer;
      47            0 :         message_size = sender_buffer_size;
      48              :     } else {
      49        68219 :         if ((uint8_t *)request >=
      50        68219 :             scratch_buffer + libspdm_get_scratch_buffer_sender_receiver_offset(spdm_context)
      51        68219 :             && (uint8_t *)request <
      52       136438 :             scratch_buffer + libspdm_get_scratch_buffer_sender_receiver_offset(spdm_context)
      53        68219 :             + 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         2589 :         } else if ((uint8_t *)request >=
      58         5178 :                    scratch_buffer +
      59         2589 :                    libspdm_get_scratch_buffer_large_sender_receiver_offset(spdm_context)
      60         2589 :                    && (uint8_t *)request <
      61              :                    scratch_buffer +
      62         2589 :                    libspdm_get_scratch_buffer_large_sender_receiver_offset(spdm_context) +
      63         2589 :                    libspdm_get_scratch_buffer_large_sender_receiver_capacity(spdm_context)) {
      64         5178 :             message = scratch_buffer +
      65         2589 :                       libspdm_get_scratch_buffer_large_sender_receiver_offset(spdm_context);
      66         2589 :             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        68219 :     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        68219 :     if (((const spdm_message_header_t *)request)->request_response_code != SPDM_RESPOND_IF_READY
      86        68190 :         && ((const spdm_message_header_t *)request)->request_response_code != SPDM_CHUNK_GET
      87         2576 :         && ((const spdm_message_header_t *)request)->request_response_code != SPDM_CHUNK_SEND) {
      88         2560 :         libspdm_copy_mem (context->last_spdm_request,
      89         2560 :                           libspdm_get_scratch_buffer_last_spdm_request_capacity(context),
      90              :                           request,
      91              :                           request_size);
      92         2560 :         context->last_spdm_request_size = request_size;
      93              :     }
      94              : 
      95        68219 :     status = context->transport_encode_message(
      96              :         context, session_id, is_app_message, true, request_size,
      97              :         request, &message_size, (void **)&message);
      98        68219 :     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        68219 :     timeout = context->local_context.capability.rtt;
     109        68219 :     status = context->send_message(context, message_size, message, timeout);
     110              : 
     111        68219 :     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        68219 :     return status;
     117              : }
     118              : 
     119        68187 : 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        68187 :     context = spdm_context;
     142              : 
     143        68187 :     if (context->crypto_request) {
     144        67995 :         timeout = context->local_context.capability.rtt +
     145        67995 :                   ((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        68187 :     message = *response;
     151        68187 :     message_size = *response_size;
     152        68187 :     status = context->receive_message(context, &message_size, (void **)&message, timeout);
     153        68187 :     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        68178 :     if (session_id != NULL) {
     171          237 :         message_session_id = &message_id;
     172          237 :         message_id = *session_id;
     173              :     } else {
     174        67941 :         message_session_id = NULL;
     175              :     }
     176        68178 :     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        68178 :     transport_header_size = context->local_context.capability.transport_header_size;
     182        68178 :     libspdm_get_scratch_buffer (context, (void **)&scratch_buffer, &scratch_buffer_size);
     183              :     #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
     184        68178 :     *response = scratch_buffer + libspdm_get_scratch_buffer_secure_message_offset(context) +
     185              :                 transport_header_size;
     186        68178 :     *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        68178 :     backup_response = *response;
     194        68178 :     backup_response_size = *response_size;
     195              : 
     196        68178 :     status = context->transport_decode_message(
     197              :         context, &message_session_id, &is_message_app_message,
     198              :         false, message_size, message, response_size, response);
     199              : 
     200        68178 :     reset_key_update = false;
     201        68178 :     temp_session_context = NULL;
     202              : 
     203        68178 :     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              :     /*
     239              :      * decoded_message may contain padding zeros due to transport layer alignment requirements.
     240              :      * trim the decoded_message size to the maximum data_transfer_size.
     241              :      */
     242        68178 :     *response_size = LIBSPDM_MIN(*response_size, context->local_context.capability.data_transfer_size);
     243              : 
     244        68178 :     if (session_id != NULL) {
     245          237 :         if (message_session_id == NULL) {
     246            0 :             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
     247              :                            "libspdm_receive_spdm_response[%x] GetSessionId - NULL\n",
     248              :                            (session_id != NULL) ? *session_id : 0x0));
     249            0 :             goto error;
     250              :         }
     251          237 :         if (*message_session_id != *session_id) {
     252            0 :             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
     253              :                            "libspdm_receive_spdm_response[%x] GetSessionId - %x\n",
     254              :                            (session_id != NULL) ? *session_id : 0x0, *message_session_id));
     255            0 :             goto error;
     256              :         }
     257              :     } else {
     258        67941 :         if (message_session_id != NULL) {
     259            0 :             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
     260              :                            "libspdm_receive_spdm_response[%x] GetSessionId - %x\n",
     261              :                            (session_id != NULL) ? *session_id : 0x0, *message_session_id));
     262            0 :             goto error;
     263              :         }
     264              :     }
     265              : 
     266        68178 :     if ((is_app_message && !is_message_app_message) ||
     267        68178 :         (!is_app_message && is_message_app_message)) {
     268            0 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
     269              :                        "libspdm_receive_spdm_response[%x] app_message mismatch\n",
     270              :                        (session_id != NULL) ? *session_id : 0x0));
     271            0 :         goto error;
     272              :     }
     273              : 
     274        68178 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     275            0 :         if ((session_id != NULL) &&
     276            0 :             (context->last_spdm_error.error_code == SPDM_ERROR_CODE_DECRYPT_ERROR)) {
     277            0 :             libspdm_free_session_id(context, *session_id);
     278              :         }
     279            0 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
     280              :                        "libspdm_receive_spdm_response[%x] status - %xu\n",
     281              :                        (session_id != NULL) ? *session_id : 0x0, status));
     282              :     } else {
     283        68178 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
     284              :                        "libspdm_receive_spdm_response[%x] msg %s(0x%x), size (0x%zx): \n",
     285              :                        (session_id != NULL) ? *session_id : 0x0,
     286              :                        libspdm_get_code_str(((spdm_message_header_t *)*response)->
     287              :                                             request_response_code),
     288              :                        ((spdm_message_header_t *)*response)->request_response_code,
     289              :                        *response_size));
     290        68178 :         LIBSPDM_INTERNAL_DUMP_HEX(*response, *response_size);
     291              :     }
     292              : 
     293              :     /* Handle special case:
     294              :      * If the Responder returns RESPONSE_NOT_READY error to KEY_UPDATE, the Requester needs
     295              :      * to activate backup key to parse the error. Then later the Responder will return SUCCESS,
     296              :      * the Requester needs new key. So we need to restore the environment by
     297              :      * libspdm_create_update_session_data_key() again.*/
     298        68178 :     if (reset_key_update) {
     299              :         /* temp_session_context and message_session_id must necessarily
     300              :          * be valid for us to reach here. */
     301           27 :         if (temp_session_context == NULL || message_session_id == NULL) {
     302            0 :             return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
     303              :         }
     304           27 :         result = libspdm_create_update_session_data_key(
     305              :             temp_session_context, LIBSPDM_KEY_UPDATE_ACTION_RESPONDER);
     306           27 :         if (!result) {
     307            0 :             return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
     308              :         }
     309              :     }
     310              : 
     311        68178 :     return status;
     312              : 
     313            0 : error:
     314            0 :     if (context->last_spdm_error.error_code == SPDM_ERROR_CODE_DECRYPT_ERROR) {
     315            0 :         return LIBSPDM_STATUS_SESSION_MSG_ERROR;
     316              :     } else {
     317            0 :         return LIBSPDM_STATUS_RECEIVE_FAIL;
     318              :     }
     319              : }
     320              : 
     321              : #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
     322           14 : libspdm_return_t libspdm_handle_large_request(
     323              :     libspdm_context_t *spdm_context,
     324              :     const uint32_t *session_id,
     325              :     size_t request_size, void *request)
     326              : {
     327              :     libspdm_return_t status;
     328              : 
     329              :     spdm_chunk_send_request_t *spdm_request;
     330              :     spdm_chunk_send_request_14_t *spdm_request_14;
     331              :     size_t spdm_request_size;
     332              :     spdm_chunk_send_ack_response_t *spdm_response;
     333              :     spdm_chunk_send_ack_response_14_t *spdm_response_14;
     334              :     size_t response_header_size;
     335              :     uint8_t *message;
     336              :     size_t message_size;
     337              :     void *response;
     338              :     size_t response_size;
     339              :     size_t transport_header_size;
     340              : 
     341              :     uint8_t *scratch_buffer;
     342              :     size_t scratch_buffer_size;
     343              : 
     344              :     uint8_t *chunk_ptr;
     345              :     size_t copy_size;
     346              :     libspdm_chunk_info_t *send_info;
     347              :     uint32_t min_data_transfer_size;
     348              :     uint64_t max_chunk_data_transfer_size;
     349              :     spdm_error_response_t *spdm_error;
     350              : 
     351           14 :     if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_12) {
     352            0 :         return LIBSPDM_STATUS_UNSUPPORTED_CAP;
     353              :     }
     354              : 
     355              :     /* Fail if requester or responder does not support chunk cap */
     356           14 :     if (!libspdm_is_capabilities_flag_supported(
     357              :             spdm_context, true,
     358              :             SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP,
     359              :             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP)) {
     360            0 :         return LIBSPDM_STATUS_ERROR_PEER;
     361              :     }
     362              : 
     363              :     /* Fail if exceed max chunks */
     364           14 :     min_data_transfer_size = LIBSPDM_MIN(
     365              :         spdm_context->connection_info.capability.data_transfer_size,
     366              :         spdm_context->local_context.capability.sender_data_transfer_size);
     367              : 
     368           14 :     if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_14) {
     369              :         /* chunk seq no wrap not considered in spdm 1.4+ */
     370              : 
     371           13 :         max_chunk_data_transfer_size =
     372           13 :             ((size_t) min_data_transfer_size - sizeof(spdm_chunk_send_request_t)) * 65536 -
     373              :             sizeof(uint32_t);
     374              :         /* max_spdm_msg_size is already checked in caller */
     375              : 
     376           13 :         if (request_size > max_chunk_data_transfer_size) {
     377            1 :             return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
     378              :         }
     379              :     }
     380              :     /* now we can get sender buffer */
     381           13 :     transport_header_size = spdm_context->local_context.capability.transport_header_size;
     382              : 
     383           13 :     libspdm_get_scratch_buffer(spdm_context, (void **)&scratch_buffer, &scratch_buffer_size);
     384              : 
     385              :     /* Temporary send/receive buffers for chunking are in the scratch space */
     386           13 :     message = scratch_buffer + libspdm_get_scratch_buffer_sender_receiver_offset(spdm_context);
     387           13 :     message_size = libspdm_get_scratch_buffer_sender_receiver_capacity(spdm_context);
     388              : 
     389           13 :     send_info = &spdm_context->chunk_context.send;
     390           13 :     send_info->chunk_in_use = true;
     391              : 
     392              :     /* The first section of the scratch
     393              :      * buffer may be used for other purposes. Use only after that section. */
     394           26 :     send_info->large_message = scratch_buffer +
     395           13 :                                libspdm_get_scratch_buffer_large_message_offset(spdm_context);
     396           13 :     send_info->large_message_capacity =
     397           13 :         libspdm_get_scratch_buffer_large_message_capacity(spdm_context);
     398              : 
     399           13 :     libspdm_zero_mem(send_info->large_message, send_info->large_message_capacity);
     400           13 :     libspdm_copy_mem(send_info->large_message, send_info->large_message_capacity,
     401              :                      request, request_size);
     402              : 
     403           13 :     send_info->large_message_size = request_size;
     404           13 :     send_info->chunk_bytes_transferred = 0;
     405           13 :     send_info->chunk_seq_no = 0;
     406           13 :     request = NULL; /* Invalidate to prevent accidental use. */
     407           13 :     request_size = 0;
     408              : 
     409              :     do {
     410           16 :         LIBSPDM_ASSERT(send_info->large_message_capacity >= transport_header_size);
     411           16 :         spdm_request = (spdm_chunk_send_request_t *)((uint8_t *)message + transport_header_size);
     412           16 :         spdm_request_size = message_size - transport_header_size;
     413              : 
     414           16 :         spdm_request->header.spdm_version = libspdm_get_connection_version(spdm_context);
     415           16 :         spdm_request->header.request_response_code = SPDM_CHUNK_SEND;
     416           16 :         spdm_request->header.param1 = 0;
     417           16 :         spdm_request->header.param2 = send_info->chunk_handle;
     418              : 
     419           16 :         if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_14) {
     420           14 :             spdm_request->chunk_seq_no = (uint16_t) send_info->chunk_seq_no;
     421           14 :             spdm_request->reserved = 0;
     422           14 :             chunk_ptr = (uint8_t *)(spdm_request + 1);
     423              :         } else {
     424            2 :             spdm_request_14 = (spdm_chunk_send_request_14_t *)spdm_request;
     425            2 :             spdm_request_14->chunk_seq_no = send_info->chunk_seq_no;
     426            2 :             chunk_ptr = (uint8_t *)(spdm_request_14 + 1);
     427              :         }
     428              : 
     429              :         LIBSPDM_ASSERT(sizeof(spdm_chunk_send_request_t) == sizeof(spdm_chunk_send_request_14_t));
     430           16 :         if ((min_data_transfer_size - sizeof(spdm_chunk_send_request_t)) <
     431           16 :             (send_info->large_message_size - send_info->chunk_bytes_transferred)) {
     432           13 :             copy_size = min_data_transfer_size - sizeof(spdm_chunk_send_request_t);
     433              :         } else {
     434            3 :             copy_size = (send_info->large_message_size - send_info->chunk_bytes_transferred);
     435              :         }
     436              : 
     437           16 :         if (send_info->chunk_seq_no == 0) {
     438           13 :             *(uint32_t *)(spdm_request + 1) = (uint32_t)send_info->large_message_size;
     439           13 :             chunk_ptr += sizeof(uint32_t);
     440           13 :             copy_size -= sizeof(uint32_t);
     441              :         }
     442              : 
     443           16 :         spdm_request->chunk_size = (uint32_t)copy_size;
     444              : 
     445           16 :         libspdm_copy_mem(
     446           16 :             chunk_ptr, spdm_request_size - ((uint8_t *)spdm_request - (uint8_t *)message),
     447           16 :             (uint8_t *)send_info->large_message + send_info->chunk_bytes_transferred, copy_size);
     448              : 
     449           16 :         send_info->chunk_bytes_transferred += copy_size;
     450           16 :         if (send_info->chunk_bytes_transferred >= send_info->large_message_size) {
     451            3 :             spdm_request->header.param1 |= SPDM_CHUNK_SEND_REQUEST_ATTRIBUTE_LAST_CHUNK;
     452              :         }
     453              : 
     454           16 :         spdm_request_size = (chunk_ptr + copy_size) - (uint8_t *)spdm_request;
     455           16 :         status = libspdm_send_request(
     456              :             spdm_context, session_id, false,
     457              :             spdm_request_size, spdm_request);
     458              : 
     459           16 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     460            1 :             break;
     461              :         }
     462              : 
     463           15 :         response = message;
     464           15 :         response_size = message_size;
     465              : 
     466           15 :         libspdm_zero_mem(response, response_size);
     467              : 
     468           15 :         status = libspdm_receive_response(
     469              :             spdm_context, session_id, false,
     470              :             &response_size, &response);
     471              : 
     472           15 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     473            1 :             break;
     474              :         }
     475           14 :         spdm_response = (void *)(response);
     476              : 
     477           14 :         if (response_size < sizeof(spdm_message_header_t)) {
     478            0 :             status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     479            0 :             break;
     480              :         }
     481              : 
     482           14 :         if (spdm_response->header.request_response_code == SPDM_ERROR
     483            2 :             && spdm_response->header.param1 != SPDM_ERROR_CODE_LARGE_RESPONSE) {
     484            2 :             status = libspdm_handle_simple_error_response(spdm_context,
     485            2 :                                                           spdm_response->header.param1);
     486            2 :             break;
     487              :         }
     488              : 
     489           12 :         if (spdm_response->header.spdm_version != libspdm_get_connection_version(spdm_context)) {
     490            1 :             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     491            1 :             break;
     492              :         }
     493              : 
     494           11 :         if (spdm_response->header.request_response_code == SPDM_ERROR
     495            0 :             && spdm_response->header.param1 == SPDM_ERROR_CODE_LARGE_RESPONSE) {
     496              : 
     497              :             /* It is possible that the CHUNK_SEND_ACK + chunk response is larger
     498              :              * than the DATA_TRANSFER_SIZE. In this case an ERROR_LARGE_RESPONSE
     499              :              * is returned directly in the response buffer rather than part of
     500              :              * the CHUNK_SEND_ACK. Store this error response in scratch buffer
     501              :              * to be handled when reading response. Also note that in this case
     502              :              * of large response, the CHUNK_SEND_ACK portion is not sent.
     503              :              * Only the response portion that requires the CHUNK_GET is sent */
     504            0 :             if (response_size < send_info->large_message_capacity) {
     505            0 :                 libspdm_copy_mem(
     506              :                     send_info->large_message, send_info->large_message_capacity,
     507              :                     spdm_response, response_size);
     508            0 :                 send_info->large_message_size = response_size;
     509            0 :                 break;
     510              :             } else {
     511            0 :                 status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     512            0 :                 break;
     513              :             }
     514              :         } else {
     515           11 :             if (spdm_response->header.request_response_code != SPDM_CHUNK_SEND_ACK) {
     516            0 :                 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     517            0 :                 break;
     518              :             }
     519              : 
     520           11 :             if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_14) {
     521            9 :                 response_header_size = sizeof(spdm_chunk_send_ack_response_t);
     522              :             } else {
     523            2 :                 response_header_size = sizeof(spdm_chunk_send_ack_response_14_t);
     524            2 :                 spdm_response_14 = (spdm_chunk_send_ack_response_14_t *)spdm_response;
     525              :             }
     526              : 
     527           11 :             if (response_size < response_header_size) {
     528            1 :                 status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     529            1 :                 break;
     530              :             }
     531           10 :             if (spdm_response->header.param1
     532           10 :                 & SPDM_CHUNK_SEND_ACK_RESPONSE_ATTRIBUTE_EARLY_ERROR_DETECTED) {
     533              : 
     534            2 :                 spdm_error = (spdm_error_response_t *)((uint8_t *)spdm_response + response_header_size);
     535            2 :                 if (response_size < (response_header_size +
     536              :                                      sizeof(spdm_error_response_t))) {
     537            0 :                     status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     538            0 :                     break;
     539              :                 }
     540            2 :                 if ((spdm_error->header.spdm_version !=
     541            2 :                      libspdm_get_connection_version(spdm_context)) ||
     542            2 :                     (spdm_error->header.request_response_code != SPDM_ERROR)) {
     543            0 :                     status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     544            0 :                     break;
     545              :                 }
     546            2 :                 if (spdm_error->header.param1 == SPDM_ERROR_CODE_LARGE_RESPONSE) {
     547            1 :                     status = LIBSPDM_STATUS_ERROR_PEER;
     548            1 :                     break;
     549              :                 }
     550              : 
     551              :                 /* Store the error response in scratch buffer to be read by
     552              :                  * libspdm_receive_spdm_response and returned to its caller
     553              :                  * and handled in the error response handling flow */
     554            1 :                 libspdm_copy_mem(
     555              :                     send_info->large_message,
     556              :                     send_info->large_message_capacity,
     557              :                     (uint8_t *)spdm_response + response_header_size,
     558              :                     response_size - response_header_size);
     559              : 
     560            1 :                 send_info->large_message_size =
     561            1 :                     (response_size - response_header_size);
     562            1 :                 status = LIBSPDM_STATUS_SUCCESS;
     563            1 :                 break;
     564              :             }
     565            8 :             if (spdm_response->header.param2 != send_info->chunk_handle) {
     566            1 :                 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     567            1 :                 break;
     568              :             }
     569            7 :             if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_14) {
     570            5 :                 if (send_info->chunk_seq_no != spdm_response->chunk_seq_no) {
     571            1 :                     status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     572            1 :                     break;
     573              :                 }
     574              :             } else {
     575            2 :                 if (send_info->chunk_seq_no != spdm_response_14->chunk_seq_no) {
     576            0 :                     status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     577            0 :                     break;
     578              :                 }
     579              :             }
     580              : 
     581            6 :             chunk_ptr = (uint8_t *)spdm_response + response_header_size;
     582            6 :             send_info->chunk_seq_no++;
     583              : 
     584            6 :             if (send_info->chunk_bytes_transferred >= send_info->large_message_size) {
     585              :                 /* All bytes have been transferred. Store response in scratch buffer
     586              :                  * to be read by libspdm_receive_spdm_response */
     587            3 :                 libspdm_copy_mem(
     588              :                     send_info->large_message, send_info->large_message_capacity,
     589              :                     chunk_ptr, response_size - response_header_size);
     590            3 :                 send_info->large_message_size =
     591            3 :                     (response_size - response_header_size);
     592            3 :                 break;
     593              :             }
     594              :         }
     595              : 
     596            3 :     } while (LIBSPDM_STATUS_IS_SUCCESS(status)
     597            3 :              && send_info->chunk_bytes_transferred < send_info->large_message_size);
     598              : 
     599           13 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     600            9 :         send_info->chunk_in_use = false;
     601            9 :         send_info->chunk_handle++; /* Implicit wrap-around*/
     602            9 :         send_info->chunk_seq_no = 0;
     603            9 :         send_info->chunk_bytes_transferred = 0;
     604            9 :         send_info->large_message = NULL;
     605            9 :         send_info->large_message_size = 0;
     606              :     }
     607              : 
     608           13 :     return status;
     609              : }
     610              : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
     611              : 
     612        68218 : libspdm_return_t libspdm_send_spdm_request(libspdm_context_t *spdm_context,
     613              :                                            const uint32_t *session_id,
     614              :                                            size_t request_size, void *request)
     615              : {
     616              :     libspdm_session_info_t *session_info;
     617              :     libspdm_session_state_t session_state;
     618              :     libspdm_return_t status;
     619              :     #if LIBSPDM_ENABLE_MSG_LOG
     620              :     size_t msg_log_size;
     621              :     #endif /* LIBSPDM_ENABLE_MSG_LOG */
     622              : 
     623              :     /* If chunking is not supported then message must fit in both the send buffer and the receive
     624              :      * buffer. */
     625        68218 :     if (!libspdm_is_capabilities_flag_supported(
     626              :             spdm_context, true,
     627              :             SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP,
     628              :             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP)) {
     629         2578 :         if ((spdm_context->connection_info.capability.data_transfer_size != 0) &&
     630            0 :             (request_size > spdm_context->connection_info.capability.data_transfer_size)) {
     631            0 :             return LIBSPDM_STATUS_PEER_BUFFER_TOO_SMALL;
     632              :         }
     633         2578 :         if ((spdm_context->local_context.capability.sender_data_transfer_size != 0) &&
     634         2578 :             (request_size > spdm_context->local_context.capability.sender_data_transfer_size)) {
     635            0 :             return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
     636              :         }
     637              :     }
     638              : 
     639        68500 :     if ((session_id != NULL) &&
     640          282 :         libspdm_is_capabilities_flag_supported(
     641              :             spdm_context, true,
     642              :             SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP,
     643              :             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) {
     644           38 :         session_info = libspdm_get_session_info_via_session_id(spdm_context, *session_id);
     645           38 :         LIBSPDM_ASSERT(session_info != NULL);
     646           38 :         if (session_info == NULL) {
     647            0 :             return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
     648              :         }
     649           38 :         session_state = libspdm_secured_message_get_session_state(
     650              :             session_info->secured_message_context);
     651           38 :         if ((session_state == LIBSPDM_SESSION_STATE_HANDSHAKING) && !session_info->use_psk) {
     652           38 :             session_id = NULL;
     653              :         }
     654              :     }
     655              : 
     656        68218 :     if ((spdm_context->connection_info.capability.max_spdm_msg_size != 0) &&
     657        65567 :         (request_size > spdm_context->connection_info.capability.max_spdm_msg_size)) {
     658            1 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "request_size > rsp max_spdm_msg_size\n"));
     659            1 :         return LIBSPDM_STATUS_PEER_BUFFER_TOO_SMALL;
     660              :     }
     661        68217 :     LIBSPDM_ASSERT (request_size <= spdm_context->local_context.capability.max_spdm_msg_size);
     662              : 
     663              :     #if LIBSPDM_ENABLE_MSG_LOG
     664              :     /* First save the size of the message log buffer. If there is an error it will be reverted. */
     665        68217 :     msg_log_size = libspdm_get_msg_log_size(spdm_context);
     666        68217 :     libspdm_append_msg_log(spdm_context, request, request_size);
     667              :     #endif /* LIBSPDM_ENABLE_MSG_LOG */
     668              : 
     669              :     /* large SPDM message is the SPDM message whose size is greater than the DataTransferSize of the receiving
     670              :      * SPDM endpoint or greater than the transmit buffer size of the sending SPDM endpoint */
     671        68217 :     if (((const spdm_message_header_t *)request)->request_response_code != SPDM_GET_VERSION
     672        68179 :         && ((const spdm_message_header_t *)request)->request_response_code != SPDM_GET_CAPABILITIES
     673        68112 :         && ((spdm_context->connection_info.capability.data_transfer_size != 0 &&
     674        65564 :              request_size > spdm_context->connection_info.capability.data_transfer_size) ||
     675        68099 :             (spdm_context->local_context.capability.sender_data_transfer_size != 0 &&
     676        68099 :              request_size > spdm_context->local_context.capability.sender_data_transfer_size))) {
     677              : 
     678              :         #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
     679              :         /* libspdm_send_request is not called with the original request in this flow.
     680              :          * This leads to the last_spdm_request field not having the original request value.
     681              :          * The caller assumes the request has been copied to last_spdm_request,
     682              :          * so that it can compare last_spdm_request's fields with response fields
     683              :          * Therefore the request must be copied to last_spdm_request here. */
     684              : 
     685           14 :         if (((const spdm_message_header_t *)request)->request_response_code != SPDM_RESPOND_IF_READY
     686           14 :             && ((const spdm_message_header_t *)request)->request_response_code != SPDM_CHUNK_GET
     687           14 :             && ((const spdm_message_header_t *)request)->request_response_code != SPDM_CHUNK_SEND) {
     688           14 :             libspdm_copy_mem(
     689              :                 spdm_context->last_spdm_request,
     690           14 :                 libspdm_get_scratch_buffer_last_spdm_request_capacity(spdm_context),
     691              :                 request, request_size);
     692           14 :             spdm_context->last_spdm_request_size = request_size;
     693              :         }
     694              : 
     695           14 :         status = libspdm_handle_large_request(
     696              :             spdm_context, session_id, request_size, request);
     697              :         #else  /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP*/
     698              :         status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
     699              :         #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP*/
     700              :     } else {
     701        68203 :         status = libspdm_send_request(spdm_context, session_id, false, request_size, request);
     702              :     }
     703              : 
     704              :     #if LIBSPDM_ENABLE_MSG_LOG
     705              :     /* If there is an error in sending the request then revert the request in the message log. */
     706        68217 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     707           34 :         spdm_context->msg_log.buffer_size = msg_log_size;
     708              :     }
     709              :     #endif /* LIBSPDM_ENABLE_MSG_LOG */
     710              : 
     711        68217 :     return status;
     712              : }
     713              : 
     714        68176 : libspdm_return_t libspdm_receive_spdm_response(libspdm_context_t *spdm_context,
     715              :                                                const uint32_t *session_id,
     716              :                                                size_t *response_size,
     717              :                                                void **response)
     718              : {
     719              :     libspdm_return_t status;
     720              :     libspdm_session_info_t *session_info;
     721              :     libspdm_session_state_t session_state;
     722              : 
     723              :     #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
     724              :     spdm_message_header_t *spdm_response;
     725              :     size_t response_capacity;
     726              :     libspdm_chunk_info_t *send_info;
     727              :     #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
     728              : 
     729        68451 :     if ((session_id != NULL) &&
     730          275 :         libspdm_is_capabilities_flag_supported(
     731              :             spdm_context, true,
     732              :             SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP,
     733              :             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) {
     734           37 :         session_info = libspdm_get_session_info_via_session_id(spdm_context, *session_id);
     735           37 :         LIBSPDM_ASSERT(session_info != NULL);
     736           37 :         if (session_info == NULL) {
     737            0 :             return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
     738              :         }
     739           37 :         session_state = libspdm_secured_message_get_session_state(
     740              :             session_info->secured_message_context);
     741           37 :         if ((session_state == LIBSPDM_SESSION_STATE_HANDSHAKING) && !session_info->use_psk) {
     742           37 :             session_id = NULL;
     743              :         }
     744              :     }
     745              : 
     746              :     #if !(LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP)
     747              :     status = libspdm_receive_response(spdm_context, session_id, false, response_size, response);
     748              :     #else /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
     749        68176 :     send_info = &spdm_context->chunk_context.send;
     750        68176 :     if (send_info->chunk_in_use) {
     751            4 :         libspdm_copy_mem(*response, *response_size,
     752            4 :                          send_info->large_message, send_info->large_message_size);
     753            4 :         *response_size = send_info->large_message_size;
     754            4 :         response_capacity = send_info->large_message_capacity;
     755              : 
     756              :         /* This response may either be an actual response or ERROR_LARGE_RESPONSE,
     757              :          * the latter which should be handled in the large response handler. */
     758            4 :         send_info->chunk_in_use = false;
     759            4 :         send_info->chunk_handle++; /* Implicit wrap-around*/
     760            4 :         send_info->chunk_seq_no = 0;
     761            4 :         send_info->chunk_bytes_transferred = 0;
     762            4 :         send_info->large_message = NULL;
     763            4 :         send_info->large_message_size = 0;
     764            4 :         send_info->large_message_capacity = 0;
     765            4 :         status = LIBSPDM_STATUS_SUCCESS;
     766              :     } else {
     767        68172 :         response_capacity = *response_size;
     768        68172 :         status = libspdm_receive_response(spdm_context, session_id, false, response_size, response);
     769        68172 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     770            8 :             goto receive_done;
     771              :         }
     772              :     }
     773              : 
     774        68168 :     spdm_response = (spdm_message_header_t *)(*response);
     775              : 
     776        68168 :     if (*response_size < sizeof(spdm_message_header_t)) {
     777            0 :         status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     778            0 :         goto receive_done;
     779              :     }
     780              : 
     781        68168 :     if (spdm_response->request_response_code == SPDM_ERROR
     782          475 :         && spdm_response->param1 == SPDM_ERROR_CODE_LARGE_RESPONSE) {
     783            8 :         status = libspdm_handle_error_large_response(
     784              :             spdm_context, session_id,
     785              :             response_size, (void *)spdm_response, response_capacity);
     786              : 
     787            8 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     788            2 :             goto receive_done;
     789              :         }
     790              : 
     791            6 :         if (*response_size < sizeof(spdm_message_header_t)) {
     792            0 :             status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     793            0 :             goto receive_done;
     794              :         }
     795              : 
     796              :         /* Per the spec, SPDM_VERSION and SPDM_CAPABILITIES shall not be chunked
     797              :          * and should be an unexpected error. */
     798            6 :         if (spdm_response->request_response_code == SPDM_VERSION ||
     799            6 :             spdm_response->request_response_code == SPDM_CAPABILITIES) {
     800            0 :             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     801            0 :             goto receive_done;
     802              :         }
     803              :     }
     804              : 
     805        68166 : receive_done:
     806              :     #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
     807              : 
     808        68176 :     return status;
     809              : }
        

Generated by: LCOV version 2.0-1