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: 85.1 % 362 308
Test Date: 2026-03-15 08:15:47 Functions: 100.0 % 5 5

            Line data    Source code
       1              : /**
       2              :  *  Copyright Notice:
       3              :  *  Copyright 2021-2026 DMTF. All rights reserved.
       4              :  *  License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md
       5              :  **/
       6              : 
       7              : #include "internal/libspdm_requester_lib.h"
       8              : #include "internal/libspdm_secured_message_lib.h"
       9              : 
      10        68223 : 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        68223 :     context = spdm_context;
      26              : 
      27        68223 :     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        68223 :     LIBSPDM_INTERNAL_DUMP_HEX(request, request_size);
      33              : 
      34        68223 :     transport_header_size = context->local_context.capability.transport_header_size;
      35        68223 :     libspdm_get_scratch_buffer(context, (void **)&scratch_buffer, &scratch_buffer_size);
      36        68223 :     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        68223 :     if ((uint8_t *)request >= sender_buffer &&
      45        68223 :         (uint8_t *)request < sender_buffer + sender_buffer_size) {
      46            0 :         message = sender_buffer;
      47            0 :         message_size = sender_buffer_size;
      48              :     } else {
      49        68223 :         if ((uint8_t *)request >=
      50        68223 :             scratch_buffer + libspdm_get_scratch_buffer_sender_receiver_offset(spdm_context)
      51        68223 :             && (uint8_t *)request <
      52       136446 :             scratch_buffer + libspdm_get_scratch_buffer_sender_receiver_offset(spdm_context)
      53        68223 :             + libspdm_get_scratch_buffer_sender_receiver_capacity(spdm_context)) {
      54       131266 :             message = scratch_buffer +
      55        65633 :                       libspdm_get_scratch_buffer_sender_receiver_offset(spdm_context);
      56        65633 :             message_size = libspdm_get_scratch_buffer_sender_receiver_capacity(spdm_context);
      57         2590 :         } else if ((uint8_t *)request >=
      58         5180 :                    scratch_buffer +
      59         2590 :                    libspdm_get_scratch_buffer_large_sender_receiver_offset(spdm_context)
      60         2590 :                    && (uint8_t *)request <
      61              :                    scratch_buffer +
      62         2590 :                    libspdm_get_scratch_buffer_large_sender_receiver_offset(spdm_context) +
      63         2590 :                    libspdm_get_scratch_buffer_large_sender_receiver_capacity(spdm_context)) {
      64         5180 :             message = scratch_buffer +
      65         2590 :                       libspdm_get_scratch_buffer_large_sender_receiver_offset(spdm_context);
      66         2590 :             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        68223 :     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        68223 :     if (((const spdm_message_header_t *)request)->request_response_code != SPDM_RESPOND_IF_READY
      86        68194 :         && ((const spdm_message_header_t *)request)->request_response_code != SPDM_CHUNK_GET
      87         2579 :         && ((const spdm_message_header_t *)request)->request_response_code != SPDM_CHUNK_SEND) {
      88         2561 :         libspdm_copy_mem (context->last_spdm_request,
      89         2561 :                           libspdm_get_scratch_buffer_last_spdm_request_capacity(context),
      90              :                           request,
      91              :                           request_size);
      92         2561 :         context->last_spdm_request_size = request_size;
      93              :     }
      94              : 
      95        68223 :     status = context->transport_encode_message(
      96              :         context, session_id, is_app_message, true, request_size,
      97              :         request, &message_size, (void **)&message);
      98        68223 :     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        68223 :     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        68223 :     timeout = context->local_context.capability.rtt;
     113        68223 :     status = context->send_message(context, message_size, message, timeout);
     114              : 
     115        68223 :     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        68223 :     return status;
     121              : }
     122              : 
     123        68191 : 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        68191 :     context = spdm_context;
     146              : 
     147        68191 :     if (context->crypto_request) {
     148        67995 :         timeout = context->local_context.capability.rtt +
     149        67995 :                   ((uint64_t)1 << context->connection_info.capability.ct_exponent);
     150              :     } else {
     151          196 :         timeout = context->local_context.capability.rtt + context->local_context.capability.st1;
     152              :     }
     153              : 
     154        68191 :     message = *response;
     155        68191 :     message_size = *response_size;
     156        68191 :     status = context->receive_message(context, &message_size, (void **)&message, timeout);
     157        68191 :     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        68182 :     if (session_id != NULL) {
     175          237 :         message_session_id = &message_id;
     176          237 :         message_id = *session_id;
     177              :     } else {
     178        67945 :         message_session_id = NULL;
     179              :     }
     180        68182 :     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        68182 :     transport_header_size = context->local_context.capability.transport_header_size;
     186        68182 :     libspdm_get_scratch_buffer (context, (void **)&scratch_buffer, &scratch_buffer_size);
     187              :     #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
     188        68182 :     *response = scratch_buffer + libspdm_get_scratch_buffer_secure_message_offset() +
     189              :                 transport_header_size;
     190        68182 :     *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        68182 :     backup_response = *response;
     198        68182 :     backup_response_size = *response_size;
     199              : 
     200        68182 :     status = context->transport_decode_message(
     201              :         context, &message_session_id, &is_message_app_message,
     202              :         false, message_size, message, response_size, response);
     203              : 
     204        68182 :     reset_key_update = false;
     205        68182 :     temp_session_context = NULL;
     206              : 
     207        68182 :     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        68182 :     *response_size = LIBSPDM_MIN(*response_size, context->local_context.capability.data_transfer_size);
     247              : 
     248        68182 :     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        67945 :         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        68182 :     if ((is_app_message && !is_message_app_message) ||
     271        68182 :         (!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        68182 :     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        68182 :         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        68182 :         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        68182 :     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        68182 :     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           15 : static 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           15 :     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           15 :     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           15 :     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           15 :     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           14 :     transport_header_size = spdm_context->local_context.capability.transport_header_size;
     386              : 
     387           14 :     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           14 :     message = scratch_buffer + libspdm_get_scratch_buffer_sender_receiver_offset(spdm_context);
     391           14 :     message_size = libspdm_get_scratch_buffer_sender_receiver_capacity(spdm_context);
     392              : 
     393           14 :     send_info = &spdm_context->chunk_context.send;
     394           14 :     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           28 :     send_info->large_message = scratch_buffer +
     399           14 :                                libspdm_get_scratch_buffer_large_message_offset(spdm_context);
     400           14 :     send_info->large_message_capacity =
     401           14 :         libspdm_get_scratch_buffer_large_message_capacity(spdm_context);
     402              : 
     403           14 :     libspdm_zero_mem(send_info->large_message, send_info->large_message_capacity);
     404           14 :     libspdm_copy_mem(send_info->large_message, send_info->large_message_capacity,
     405              :                      request, request_size);
     406              : 
     407           14 :     send_info->large_message_size = request_size;
     408           14 :     send_info->chunk_bytes_transferred = 0;
     409           14 :     send_info->chunk_seq_no = 0;
     410           14 :     request = NULL; /* Invalidate to prevent accidental use. */
     411           14 :     request_size = 0;
     412              : 
     413              :     do {
     414           18 :         LIBSPDM_ASSERT(send_info->large_message_capacity >= transport_header_size);
     415           18 :         spdm_request = (spdm_chunk_send_request_t *)((uint8_t *)message + transport_header_size);
     416           18 :         spdm_request_size = message_size - transport_header_size;
     417              : 
     418           18 :         spdm_request->header.spdm_version = libspdm_get_connection_version(spdm_context);
     419           18 :         spdm_request->header.request_response_code = SPDM_CHUNK_SEND;
     420           18 :         spdm_request->header.param1 = 0;
     421           18 :         spdm_request->header.param2 = send_info->chunk_handle;
     422              : 
     423           18 :         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            4 :             spdm_request_14 = (spdm_chunk_send_request_14_t *)spdm_request;
     429            4 :             spdm_request_14->chunk_seq_no = send_info->chunk_seq_no;
     430            4 :             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           18 :         if ((min_data_transfer_size - sizeof(spdm_chunk_send_request_t)) <
     435           18 :             (send_info->large_message_size - send_info->chunk_bytes_transferred)) {
     436           14 :             copy_size = min_data_transfer_size - sizeof(spdm_chunk_send_request_t);
     437              :         } else {
     438            4 :             copy_size = (send_info->large_message_size - send_info->chunk_bytes_transferred);
     439              :         }
     440              : 
     441           18 :         if (send_info->chunk_seq_no == 0) {
     442           14 :             libspdm_write_uint32((uint8_t *)(spdm_request + 1),
     443           14 :                                  (uint32_t)send_info->large_message_size);
     444           14 :             chunk_ptr += sizeof(uint32_t);
     445           14 :             copy_size -= sizeof(uint32_t);
     446              :         }
     447              : 
     448           18 :         spdm_request->chunk_size = (uint32_t)copy_size;
     449              : 
     450           18 :         libspdm_copy_mem(
     451           18 :             chunk_ptr, spdm_request_size - ((uint8_t *)spdm_request - (uint8_t *)message),
     452           18 :             (uint8_t *)send_info->large_message + send_info->chunk_bytes_transferred, copy_size);
     453              : 
     454           18 :         send_info->chunk_bytes_transferred += copy_size;
     455           18 :         if (send_info->chunk_bytes_transferred >= send_info->large_message_size) {
     456            4 :             spdm_request->header.param1 |= SPDM_CHUNK_SEND_REQUEST_ATTRIBUTE_LAST_CHUNK;
     457              :         }
     458              : 
     459           18 :         spdm_request_size = (chunk_ptr + copy_size) - (uint8_t *)spdm_request;
     460           18 :         status = libspdm_send_request(
     461              :             spdm_context, session_id, false,
     462              :             spdm_request_size, spdm_request);
     463              : 
     464           18 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     465            1 :             break;
     466              :         }
     467              : 
     468           17 :         response = message;
     469           17 :         response_size = message_size;
     470              : 
     471           17 :         libspdm_zero_mem(response, response_size);
     472              : 
     473           17 :         status = libspdm_receive_response(
     474              :             spdm_context, session_id, false,
     475              :             &response_size, &response);
     476              : 
     477           17 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     478            1 :             break;
     479              :         }
     480           16 :         spdm_response = (void *)(response);
     481              : 
     482           16 :         if (response_size < sizeof(spdm_message_header_t)) {
     483            0 :             status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     484            0 :             break;
     485              :         }
     486              : 
     487           16 :         if (spdm_response->header.request_response_code == SPDM_ERROR
     488            3 :             && spdm_response->header.param1 != SPDM_ERROR_CODE_LARGE_RESPONSE) {
     489            2 :             status = libspdm_handle_simple_error_response(spdm_context,
     490            2 :                                                           spdm_response->header.param1);
     491            2 :             break;
     492              :         }
     493              : 
     494           14 :         if (spdm_response->header.spdm_version != libspdm_get_connection_version(spdm_context)) {
     495            1 :             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     496            1 :             break;
     497              :         }
     498              : 
     499           13 :         if (spdm_response->header.request_response_code == SPDM_ERROR
     500            1 :             && spdm_response->header.param1 == SPDM_ERROR_CODE_LARGE_RESPONSE) {
     501              : 
     502              :             /* It is possible that the CHUNK_SEND_ACK + chunk response is larger
     503              :              * than the DATA_TRANSFER_SIZE. In this case an ERROR_LARGE_RESPONSE
     504              :              * is returned directly in the response buffer rather than part of
     505              :              * the CHUNK_SEND_ACK. Store this error response in scratch buffer
     506              :              * to be handled when reading response. Also note that in this case
     507              :              * of large response, the CHUNK_SEND_ACK portion is not sent.
     508              :              * Only the response portion that requires the CHUNK_GET is sent */
     509            1 :             if (response_size < send_info->large_message_capacity) {
     510            1 :                 libspdm_copy_mem(
     511              :                     send_info->large_message, send_info->large_message_capacity,
     512              :                     spdm_response, response_size);
     513            1 :                 send_info->large_message_size = response_size;
     514            1 :                 break;
     515              :             } else {
     516            0 :                 status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     517            0 :                 break;
     518              :             }
     519              :         } else {
     520           12 :             if (spdm_response->header.request_response_code != SPDM_CHUNK_SEND_ACK) {
     521            0 :                 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     522            0 :                 break;
     523              :             }
     524              : 
     525           12 :             if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_14) {
     526            9 :                 response_header_size = sizeof(spdm_chunk_send_ack_response_t);
     527              :             } else {
     528            3 :                 response_header_size = sizeof(spdm_chunk_send_ack_response_14_t);
     529            3 :                 spdm_response_14 = (spdm_chunk_send_ack_response_14_t *)spdm_response;
     530              :             }
     531              : 
     532           12 :             if (response_size < response_header_size) {
     533            1 :                 status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     534            1 :                 break;
     535              :             }
     536           11 :             if (spdm_response->header.param1
     537           11 :                 & SPDM_CHUNK_SEND_ACK_RESPONSE_ATTRIBUTE_EARLY_ERROR_DETECTED) {
     538              : 
     539            2 :                 spdm_error = (spdm_error_response_t *)((uint8_t *)spdm_response + response_header_size);
     540            2 :                 if (response_size < (response_header_size +
     541              :                                      sizeof(spdm_error_response_t))) {
     542            0 :                     status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     543            0 :                     break;
     544              :                 }
     545            2 :                 if ((spdm_error->header.spdm_version !=
     546            2 :                      libspdm_get_connection_version(spdm_context)) ||
     547            2 :                     (spdm_error->header.request_response_code != SPDM_ERROR)) {
     548            0 :                     status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     549            0 :                     break;
     550              :                 }
     551            2 :                 if (spdm_error->header.param1 == SPDM_ERROR_CODE_LARGE_RESPONSE) {
     552            1 :                     status = LIBSPDM_STATUS_ERROR_PEER;
     553            1 :                     break;
     554              :                 }
     555              : 
     556              :                 /* Store the error response in scratch buffer to be read by
     557              :                  * libspdm_receive_spdm_response and returned to its caller
     558              :                  * and handled in the error response handling flow */
     559            1 :                 libspdm_copy_mem(
     560              :                     send_info->large_message,
     561              :                     send_info->large_message_capacity,
     562              :                     (uint8_t *)spdm_response + response_header_size,
     563              :                     response_size - response_header_size);
     564              : 
     565            1 :                 send_info->large_message_size =
     566            1 :                     (response_size - response_header_size);
     567            1 :                 status = LIBSPDM_STATUS_SUCCESS;
     568            1 :                 break;
     569              :             }
     570            9 :             if (spdm_response->header.param2 != send_info->chunk_handle) {
     571            1 :                 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     572            1 :                 break;
     573              :             }
     574            8 :             if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_14) {
     575            5 :                 if (send_info->chunk_seq_no != spdm_response->chunk_seq_no) {
     576            1 :                     status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     577            1 :                     break;
     578              :                 }
     579              :             } else {
     580            3 :                 if (send_info->chunk_seq_no != spdm_response_14->chunk_seq_no) {
     581            0 :                     status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     582            0 :                     break;
     583              :                 }
     584              :             }
     585              : 
     586            7 :             chunk_ptr = (uint8_t *)spdm_response + response_header_size;
     587            7 :             send_info->chunk_seq_no++;
     588              : 
     589            7 :             if (send_info->chunk_bytes_transferred >= send_info->large_message_size) {
     590              :                 /* All bytes have been transferred. Store response in scratch buffer
     591              :                  * to be read by libspdm_receive_spdm_response */
     592            3 :                 libspdm_copy_mem(
     593              :                     send_info->large_message, send_info->large_message_capacity,
     594              :                     chunk_ptr, response_size - response_header_size);
     595            3 :                 send_info->large_message_size =
     596            3 :                     (response_size - response_header_size);
     597            3 :                 break;
     598              :             }
     599              :         }
     600              : 
     601            4 :     } while (LIBSPDM_STATUS_IS_SUCCESS(status)
     602            4 :              && send_info->chunk_bytes_transferred < send_info->large_message_size);
     603              : 
     604           14 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     605            9 :         libspdm_zero_mem(send_info->large_message, send_info->large_message_capacity);
     606            9 :         send_info->chunk_in_use = false;
     607            9 :         send_info->chunk_handle++; /* Implicit wrap-around*/
     608            9 :         send_info->chunk_seq_no = 0;
     609            9 :         send_info->chunk_bytes_transferred = 0;
     610            9 :         send_info->large_message = NULL;
     611            9 :         send_info->large_message_size = 0;
     612              :     }
     613              : 
     614           14 :     return status;
     615              : }
     616              : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
     617              : 
     618        68221 : libspdm_return_t libspdm_send_spdm_request(libspdm_context_t *spdm_context,
     619              :                                            const uint32_t *session_id,
     620              :                                            size_t request_size, void *request)
     621              : {
     622              :     libspdm_session_info_t *session_info;
     623              :     libspdm_session_state_t session_state;
     624              :     libspdm_return_t status;
     625              :     #if LIBSPDM_ENABLE_MSG_LOG
     626              :     size_t msg_log_size;
     627              :     #endif /* LIBSPDM_ENABLE_MSG_LOG */
     628              : 
     629              :     /* If chunking is not supported then message must fit in both the send buffer and the receive
     630              :      * buffer. */
     631        68221 :     if (!libspdm_is_capabilities_flag_supported(
     632              :             spdm_context, true,
     633              :             SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP,
     634              :             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP)) {
     635         2580 :         if ((spdm_context->connection_info.capability.data_transfer_size != 0) &&
     636            0 :             (request_size > spdm_context->connection_info.capability.data_transfer_size)) {
     637            0 :             return LIBSPDM_STATUS_PEER_BUFFER_TOO_SMALL;
     638              :         }
     639         2580 :         if ((spdm_context->local_context.capability.sender_data_transfer_size != 0) &&
     640         2580 :             (request_size > spdm_context->local_context.capability.sender_data_transfer_size)) {
     641            0 :             return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
     642              :         }
     643              :     }
     644              : 
     645        68503 :     if ((session_id != NULL) &&
     646          282 :         libspdm_is_capabilities_flag_supported(
     647              :             spdm_context, true,
     648              :             SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP,
     649              :             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) {
     650           38 :         session_info = libspdm_get_session_info_via_session_id(spdm_context, *session_id);
     651           38 :         LIBSPDM_ASSERT(session_info != NULL);
     652           38 :         if (session_info == NULL) {
     653            0 :             return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
     654              :         }
     655           38 :         session_state = libspdm_secured_message_get_session_state(
     656              :             session_info->secured_message_context);
     657           38 :         if ((session_state == LIBSPDM_SESSION_STATE_HANDSHAKING) && !session_info->use_psk) {
     658           38 :             session_id = NULL;
     659              :         }
     660              :     }
     661              : 
     662        68221 :     if ((spdm_context->connection_info.capability.max_spdm_msg_size != 0) &&
     663        65570 :         (request_size > spdm_context->connection_info.capability.max_spdm_msg_size)) {
     664            1 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "request_size > rsp max_spdm_msg_size\n"));
     665            1 :         return LIBSPDM_STATUS_PEER_BUFFER_TOO_SMALL;
     666              :     }
     667        68220 :     LIBSPDM_ASSERT (request_size <= spdm_context->local_context.capability.max_spdm_msg_size);
     668              : 
     669              :     #if LIBSPDM_ENABLE_MSG_LOG
     670              :     /* First save the size of the message log buffer. If there is an error it will be reverted. */
     671        68220 :     msg_log_size = libspdm_get_msg_log_size(spdm_context);
     672        68220 :     libspdm_append_msg_log(spdm_context, request, request_size);
     673              :     #endif /* LIBSPDM_ENABLE_MSG_LOG */
     674              : 
     675              :     /* large SPDM message is the SPDM message whose size is greater than the DataTransferSize of the receiving
     676              :      * SPDM endpoint or greater than the transmit buffer size of the sending SPDM endpoint */
     677        68220 :     if (((const spdm_message_header_t *)request)->request_response_code != SPDM_GET_VERSION
     678        68182 :         && ((const spdm_message_header_t *)request)->request_response_code != SPDM_GET_CAPABILITIES
     679        68115 :         && ((spdm_context->connection_info.capability.data_transfer_size != 0 &&
     680        65567 :              request_size > spdm_context->connection_info.capability.data_transfer_size) ||
     681        68101 :             (spdm_context->local_context.capability.sender_data_transfer_size != 0 &&
     682        68101 :              request_size > spdm_context->local_context.capability.sender_data_transfer_size))) {
     683              : 
     684              :         #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
     685              :         /* libspdm_send_request is not called with the original request in this flow.
     686              :          * This leads to the last_spdm_request field not having the original request value.
     687              :          * The caller assumes the request has been copied to last_spdm_request,
     688              :          * so that it can compare last_spdm_request's fields with response fields
     689              :          * Therefore the request must be copied to last_spdm_request here. */
     690              : 
     691           15 :         if (((const spdm_message_header_t *)request)->request_response_code != SPDM_RESPOND_IF_READY
     692           15 :             && ((const spdm_message_header_t *)request)->request_response_code != SPDM_CHUNK_GET
     693           15 :             && ((const spdm_message_header_t *)request)->request_response_code != SPDM_CHUNK_SEND) {
     694           15 :             libspdm_copy_mem(
     695              :                 spdm_context->last_spdm_request,
     696           15 :                 libspdm_get_scratch_buffer_last_spdm_request_capacity(spdm_context),
     697              :                 request, request_size);
     698           15 :             spdm_context->last_spdm_request_size = request_size;
     699              :         }
     700              : 
     701           15 :         status = libspdm_handle_large_request(
     702              :             spdm_context, session_id, request_size, request);
     703              :         #else  /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP*/
     704              :         status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
     705              :         #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP*/
     706              :     } else {
     707        68205 :         status = libspdm_send_request(spdm_context, session_id, false, request_size, request);
     708              :     }
     709              : 
     710              :     #if LIBSPDM_ENABLE_MSG_LOG
     711              :     /* If there is an error in sending the request then revert the request in the message log. */
     712        68220 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     713           34 :         spdm_context->msg_log.buffer_size = msg_log_size;
     714              :     }
     715              :     #endif /* LIBSPDM_ENABLE_MSG_LOG */
     716              : 
     717        68220 :     return status;
     718              : }
     719              : 
     720        68179 : libspdm_return_t libspdm_receive_spdm_response(libspdm_context_t *spdm_context,
     721              :                                                const uint32_t *session_id,
     722              :                                                size_t *response_size,
     723              :                                                void **response)
     724              : {
     725              :     libspdm_return_t status;
     726              :     libspdm_session_info_t *session_info;
     727              :     libspdm_session_state_t session_state;
     728              : 
     729              :     #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
     730              :     spdm_message_header_t *spdm_response;
     731              :     size_t response_capacity;
     732              :     libspdm_chunk_info_t *send_info;
     733        68179 :     bool response_from_chunk = false;
     734              :     #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
     735              : 
     736        68454 :     if ((session_id != NULL) &&
     737          275 :         libspdm_is_capabilities_flag_supported(
     738              :             spdm_context, true,
     739              :             SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP,
     740              :             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) {
     741           37 :         session_info = libspdm_get_session_info_via_session_id(spdm_context, *session_id);
     742           37 :         LIBSPDM_ASSERT(session_info != NULL);
     743           37 :         if (session_info == NULL) {
     744            0 :             return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
     745              :         }
     746           37 :         session_state = libspdm_secured_message_get_session_state(
     747              :             session_info->secured_message_context);
     748           37 :         if ((session_state == LIBSPDM_SESSION_STATE_HANDSHAKING) && !session_info->use_psk) {
     749           37 :             session_id = NULL;
     750              :         }
     751              :     }
     752              : 
     753              :     #if !(LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP)
     754              :     status = libspdm_receive_response(spdm_context, session_id, false, response_size, response);
     755              :     #else /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
     756        68179 :     send_info = &spdm_context->chunk_context.send;
     757        68179 :     if (send_info->chunk_in_use) {
     758            5 :         libspdm_copy_mem(*response, *response_size,
     759            5 :                          send_info->large_message, send_info->large_message_size);
     760            5 :         *response_size = send_info->large_message_size;
     761            5 :         response_capacity = send_info->large_message_capacity;
     762            5 :         response_from_chunk = true;
     763              : 
     764              :         /* This response may either be an actual response or ERROR_LARGE_RESPONSE,
     765              :          * the latter which should be handled in the large response handler. */
     766            5 :         libspdm_zero_mem(send_info->large_message, send_info->large_message_capacity);
     767            5 :         send_info->chunk_in_use = false;
     768            5 :         send_info->chunk_handle++; /* Implicit wrap-around*/
     769            5 :         send_info->chunk_seq_no = 0;
     770            5 :         send_info->chunk_bytes_transferred = 0;
     771            5 :         send_info->large_message = NULL;
     772            5 :         send_info->large_message_size = 0;
     773            5 :         send_info->large_message_capacity = 0;
     774            5 :         status = LIBSPDM_STATUS_SUCCESS;
     775              :     } else {
     776        68174 :         response_capacity = *response_size;
     777        68174 :         status = libspdm_receive_response(spdm_context, session_id, false, response_size, response);
     778        68174 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     779            8 :             goto receive_done;
     780              :         }
     781              :     }
     782              : 
     783        68171 :     spdm_response = (spdm_message_header_t *)(*response);
     784              : 
     785        68171 :     if (*response_size < sizeof(spdm_message_header_t)) {
     786            0 :         status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     787            0 :         goto receive_done;
     788              :     }
     789              : 
     790        68171 :     if (spdm_response->request_response_code == SPDM_ERROR
     791          475 :         && spdm_response->param1 == SPDM_ERROR_CODE_LARGE_RESPONSE) {
     792            8 :         status = libspdm_handle_error_large_response(
     793              :             spdm_context, session_id,
     794              :             response_size, (void *)spdm_response, response_capacity, response_from_chunk);
     795              : 
     796            8 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     797            2 :             goto receive_done;
     798              :         }
     799              : 
     800            6 :         if (*response_size < sizeof(spdm_message_header_t)) {
     801            0 :             status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     802            0 :             goto receive_done;
     803              :         }
     804              : 
     805              :         /* Per the spec, SPDM_VERSION and SPDM_CAPABILITIES shall not be chunked
     806              :          * and should be an unexpected error. */
     807            6 :         if (spdm_response->request_response_code == SPDM_VERSION ||
     808            6 :             spdm_response->request_response_code == SPDM_CAPABILITIES) {
     809            0 :             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     810            0 :             goto receive_done;
     811              :         }
     812              :     }
     813              : 
     814        68169 : receive_done:
     815              :     #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
     816              : 
     817        68179 :     return status;
     818              : }
        

Generated by: LCOV version 2.0-1