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

Generated by: LCOV version 2.0-1