LCOV - code coverage report
Current view: top level - spdm_responder_lib - libspdm_rsp_receive_send.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 75.7 % 419 317
Test Date: 2026-10-01 20:56:25 Functions: 100.0 % 16 16
Branches: 62.2 % 288 179

             Branch data     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_responder_lib.h"
       8                 :             : #include "internal/libspdm_secured_message_lib.h"
       9                 :             : 
      10                 :          46 : libspdm_get_spdm_response_func libspdm_get_response_func_via_request_code(uint8_t request_code)
      11                 :             : {
      12   [ +  +  +  +  :          46 :     switch (request_code) {
          +  +  +  -  +  
          +  +  +  -  +  
          +  -  -  -  -  
          -  -  -  -  +  
          -  -  -  -  +  
                      + ]
      13                 :          11 :     case SPDM_GET_VERSION: return libspdm_get_response_version;
      14                 :           8 :     case SPDM_GET_CAPABILITIES: return libspdm_get_response_capabilities;
      15                 :           3 :     case SPDM_NEGOTIATE_ALGORITHMS: return libspdm_get_response_algorithms;
      16                 :             : 
      17                 :             :     #if LIBSPDM_ENABLE_CAPABILITY_CERT_CAP
      18                 :           4 :     case SPDM_GET_DIGESTS: return libspdm_get_response_digests;
      19                 :           1 :     case SPDM_GET_CERTIFICATE: return libspdm_get_response_certificate;
      20                 :             :     #endif /* LIBSPDM_ENABLE_CAPABILITY_CERT_CAP */
      21                 :             : 
      22                 :             :     #if LIBSPDM_ENABLE_CAPABILITY_CHAL_CAP
      23                 :           1 :     case SPDM_CHALLENGE: return libspdm_get_response_challenge_auth;
      24                 :             :     #endif /* LIBSPDM_ENABLE_CAPABILITY_CHAL_CAP*/
      25                 :             : 
      26                 :             :     #if LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP
      27                 :           3 :     case SPDM_GET_MEASUREMENTS: return libspdm_get_response_measurements;
      28                 :             :     #endif /* LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP*/
      29                 :             : 
      30                 :             :     #if LIBSPDM_ENABLE_CAPABILITY_MEL_CAP
      31                 :           0 :     case SPDM_GET_MEASUREMENT_EXTENSION_LOG: return libspdm_get_response_measurement_extension_log;
      32                 :             :     #endif /* LIBSPDM_ENABLE_CAPABILITY_MEL_CAP */
      33                 :             : 
      34                 :             :     #if LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP
      35                 :           1 :     case SPDM_KEY_EXCHANGE: return libspdm_get_response_key_exchange;
      36                 :             :     #endif /* LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP*/
      37                 :             : 
      38                 :             :     #if LIBSPDM_ENABLE_CAPABILITY_PSK_CAP
      39                 :           1 :     case SPDM_PSK_EXCHANGE: return libspdm_get_response_psk_exchange;
      40                 :             :     #endif /* LIBSPDM_ENABLE_CAPABILITY_PSK_CAP*/
      41                 :             : 
      42                 :             :     #if LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP
      43                 :           4 :     case SPDM_GET_ENCAPSULATED_REQUEST: return libspdm_get_response_encapsulated_request;
      44                 :           3 :     case SPDM_DELIVER_ENCAPSULATED_RESPONSE: return libspdm_get_response_encapsulated_response_ack;
      45                 :             :     #endif /* LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP */
      46                 :             : 
      47                 :             :     #if LIBSPDM_RESPOND_IF_READY_SUPPORT
      48                 :           0 :     case SPDM_RESPOND_IF_READY: return libspdm_get_response_respond_if_ready;
      49                 :             :     #endif /* LIBSPDM_RESPOND_IF_READY_SUPPORT */
      50                 :             : 
      51                 :             :     #if LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP
      52                 :           1 :     case SPDM_FINISH: return libspdm_get_response_finish;
      53                 :             :     #endif /* LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP*/
      54                 :             : 
      55                 :             :     #if LIBSPDM_ENABLE_CAPABILITY_PSK_CAP
      56                 :           1 :     case SPDM_PSK_FINISH: return libspdm_get_response_psk_finish;
      57                 :             :     #endif /* LIBSPDM_ENABLE_CAPABILITY_PSK_CAP*/
      58                 :             : 
      59                 :             :     #if (LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP) || (LIBSPDM_ENABLE_CAPABILITY_PSK_CAP)
      60                 :           0 :     case SPDM_END_SESSION: return libspdm_get_response_end_session;
      61                 :           0 :     case SPDM_HEARTBEAT: return libspdm_get_response_heartbeat;
      62                 :           0 :     case SPDM_KEY_UPDATE: return libspdm_get_response_key_update;
      63                 :             :     #endif /* LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP || LIBSPDM_ENABLE_CAPABILITY_PSK_CAP*/
      64                 :             : 
      65                 :             :     #if LIBSPDM_ENABLE_CAPABILITY_ENDPOINT_INFO_CAP
      66                 :           0 :     case SPDM_GET_ENDPOINT_INFO: return libspdm_get_response_endpoint_info;
      67                 :             :     #endif /*LIBSPDM_ENABLE_CAPABILITY_ENDPOINT_INFO_CAP*/
      68                 :             : 
      69                 :             :     #if LIBSPDM_ENABLE_CAPABILITY_CSR_CAP
      70                 :           0 :     case SPDM_GET_CSR: return libspdm_get_response_csr;
      71                 :             :     #endif /*LIBSPDM_ENABLE_CAPABILITY_CSR_CAP*/
      72                 :             : 
      73                 :             :     #if LIBSPDM_ENABLE_CAPABILITY_SET_CERT_CAP
      74                 :           0 :     case SPDM_SET_CERTIFICATE: return libspdm_get_response_set_certificate;
      75                 :             :     #endif /*LIBSPDM_ENABLE_CAPABILITY_SET_CERT_CAP*/
      76                 :             : 
      77                 :             :     #if LIBSPDM_ENABLE_CAPABILITY_GET_KEY_PAIR_INFO_CAP
      78                 :           0 :     case SPDM_GET_KEY_PAIR_INFO: return libspdm_get_response_key_pair_info;
      79                 :             :     #endif /*LIBSPDM_ENABLE_CAPABILITY_GET_KEY_PAIR_INFO_CAP*/
      80                 :             : 
      81                 :             :     #if LIBSPDM_ENABLE_CAPABILITY_SET_KEY_PAIR_INFO_CAP
      82                 :           0 :     case SPDM_SET_KEY_PAIR_INFO: return libspdm_get_response_set_key_pair_info_ack;
      83                 :             :     #endif /*LIBSPDM_ENABLE_CAPABILITY_SET_KEY_PAIR_INFO_CAP*/
      84                 :             : 
      85                 :             :     #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
      86                 :           1 :     case SPDM_CHUNK_GET: return libspdm_get_response_chunk_get;
      87                 :           0 :     case SPDM_CHUNK_SEND: return libspdm_get_response_chunk_send;
      88                 :             :     #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
      89                 :             : 
      90                 :             :     #if LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP
      91                 :           0 :     case SPDM_GET_SUPPORTED_EVENT_TYPES: return libspdm_get_response_supported_event_types;
      92                 :           0 :     case SPDM_SUBSCRIBE_EVENT_TYPES: return libspdm_get_response_subscribe_event_types_ack;
      93                 :             :     #endif /* LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP */
      94                 :             : 
      95                 :             :     #if LIBSPDM_EVENT_RECIPIENT_SUPPORT
      96                 :           0 :     case SPDM_SEND_EVENT: return libspdm_get_response_event_ack;
      97                 :             :     #endif /* LIBSPDM_EVENT_RECIPIENT_SUPPORT */
      98                 :             : 
      99                 :             :     #if LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES
     100                 :           2 :     case SPDM_VENDOR_DEFINED_REQUEST: return libspdm_get_vendor_defined_response;
     101                 :             :     #endif /*LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES*/
     102                 :             : 
     103                 :           1 :     default: return NULL;
     104                 :             :     }
     105                 :             : }
     106                 :             : 
     107                 :             : /**
     108                 :             :  * Return the GET_SPDM_RESPONSE function via last request.
     109                 :             :  *
     110                 :             :  * @param  spdm_context                  The SPDM context for the device.
     111                 :             :  *
     112                 :             :  * @return GET_SPDM_RESPONSE function according to the last request.
     113                 :             :  **/
     114                 :          32 : static libspdm_get_spdm_response_func libspdm_get_response_func_via_last_request(
     115                 :             :     libspdm_context_t *spdm_context)
     116                 :             : {
     117                 :             :     spdm_message_header_t *spdm_request;
     118                 :             : 
     119                 :          32 :     spdm_request = (void *)spdm_context->last_spdm_request;
     120                 :          32 :     return libspdm_get_response_func_via_request_code(spdm_request->request_response_code);
     121                 :             : }
     122                 :             : 
     123                 :             : #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
     124                 :             : /**
     125                 :             :  * Return whether a request would interrupt a chunk transfer that is in progress. Only the chunk
     126                 :             :  * messages of that transfer and GET_VERSION may be received during one.
     127                 :             :  *
     128                 :             :  * @param  spdm_context       The SPDM context for the device.
     129                 :             :  * @param  get_response_func  The GET_SPDM_RESPONSE function of the request.
     130                 :             :  **/
     131                 :          32 : static bool libspdm_request_interrupts_chunk_transfer(
     132                 :             :     const libspdm_context_t *spdm_context, libspdm_get_spdm_response_func get_response_func)
     133                 :             : {
     134         [ +  + ]:          32 :     if (get_response_func == libspdm_get_response_version) {
     135                 :          11 :         return false;
     136                 :             :     }
     137   [ +  +  +  + ]:          21 :     if (spdm_context->chunk_context.get.chunk_in_use &&
     138                 :             :         (get_response_func != libspdm_get_response_chunk_get)) {
     139                 :           1 :         return true;
     140                 :             :     }
     141   [ +  +  +  - ]:          20 :     if (spdm_context->chunk_context.send.chunk_in_use &&
     142                 :             :         (get_response_func != libspdm_get_response_chunk_send)) {
     143                 :           1 :         return true;
     144                 :             :     }
     145                 :          19 :     return false;
     146                 :             : }
     147                 :             : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
     148                 :             : 
     149                 :           4 : libspdm_return_t libspdm_process_request(void *spdm_context, uint32_t **session_id,
     150                 :             :                                          bool *is_app_message,
     151                 :             :                                          size_t request_size, void *request)
     152                 :             : {
     153                 :             :     libspdm_context_t *context;
     154                 :             :     void *temp_session_context;
     155                 :             :     libspdm_return_t status;
     156                 :             :     libspdm_session_info_t *session_info;
     157                 :             :     uint32_t *message_session_id;
     158                 :             :     uint8_t *decoded_message_ptr;
     159                 :             :     size_t decoded_message_size;
     160                 :             :     uint8_t *backup_decoded_message_ptr;
     161                 :             :     size_t backup_decoded_message_size;
     162                 :             :     bool result;
     163                 :             :     bool reset_key_update;
     164                 :             : 
     165                 :           4 :     context = spdm_context;
     166                 :             :     size_t transport_header_size;
     167                 :             :     uint8_t *scratch_buffer;
     168                 :             :     size_t scratch_buffer_size;
     169                 :             : 
     170         [ +  + ]:           4 :     if (request == NULL) {
     171                 :           1 :         return LIBSPDM_STATUS_INVALID_PARAMETER;
     172                 :             :     }
     173         [ +  + ]:           3 :     if (request_size == 0) {
     174                 :           1 :         return LIBSPDM_STATUS_INVALID_PARAMETER;
     175                 :             :     }
     176                 :             : 
     177                 :           2 :     LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmReceiveRequest[.] ...\n"));
     178                 :             : 
     179                 :           2 :     message_session_id = NULL;
     180                 :           2 :     context->last_spdm_request_session_id_valid = false;
     181                 :           2 :     context->last_spdm_request_size =
     182                 :           2 :         libspdm_get_scratch_buffer_last_spdm_request_capacity(context);
     183                 :             : 
     184                 :             :     /* always use scratch buffer for the request.
     185                 :             :      * if it is secured message, this scratch buffer will be used.
     186                 :             :      * if it is normal message, the request ptr will point to receiver buffer. */
     187                 :           2 :     transport_header_size = context->local_context.capability.transport_header_size;
     188                 :           2 :     libspdm_get_scratch_buffer (context, (void **)&scratch_buffer, &scratch_buffer_size);
     189                 :             :     #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
     190                 :           2 :     decoded_message_ptr = scratch_buffer +
     191                 :           2 :                           libspdm_get_scratch_buffer_secure_message_offset() +
     192                 :             :                           transport_header_size;
     193                 :           2 :     decoded_message_size = libspdm_get_scratch_buffer_secure_message_capacity(context) -
     194                 :             :                            transport_header_size;
     195                 :             :     #else
     196                 :             :     decoded_message_ptr = scratch_buffer + transport_header_size;
     197                 :             :     decoded_message_size = scratch_buffer_size - transport_header_size;
     198                 :             :     #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
     199                 :             : 
     200                 :           2 :     backup_decoded_message_ptr = decoded_message_ptr;
     201                 :           2 :     backup_decoded_message_size = decoded_message_size;
     202                 :             : 
     203                 :           2 :     status = context->transport_decode_message(
     204                 :             :         context, &message_session_id, is_app_message, true,
     205                 :             :         request_size, request, &decoded_message_size,
     206                 :             :         (void **)&decoded_message_ptr);
     207                 :             : 
     208                 :           2 :     reset_key_update = false;
     209                 :           2 :     temp_session_context = NULL;
     210                 :             : 
     211         [ -  + ]:           2 :     if (status == LIBSPDM_STATUS_SESSION_TRY_DISCARD_KEY_UPDATE) {
     212                 :             :         /* Failed to decode, but have backup keys. Try rolling back before aborting.
     213                 :             :          * message_session_id must be valid for us to have attempted decryption. */
     214         [ #  # ]:           0 :         if (message_session_id == NULL) {
     215                 :           0 :             return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
     216                 :             :         }
     217                 :           0 :         temp_session_context = libspdm_get_secured_message_context_via_session_id(
     218                 :             :             context, *message_session_id);
     219         [ #  # ]:           0 :         if (temp_session_context == NULL) {
     220                 :           0 :             return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
     221                 :             :         }
     222                 :             : 
     223                 :           0 :         result = libspdm_activate_update_session_data_key(
     224                 :             :             temp_session_context, LIBSPDM_KEY_UPDATE_ACTION_REQUESTER, false);
     225         [ #  # ]:           0 :         if (!result) {
     226                 :           0 :             return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
     227                 :             :         }
     228                 :           0 :         libspdm_trigger_key_update_callback(
     229                 :             :             context, *message_session_id,
     230                 :             :             LIBSPDM_KEY_UPDATE_OPERATION_DISCARD_UPDATE,
     231                 :             :             LIBSPDM_KEY_UPDATE_ACTION_REQUESTER);
     232                 :             : 
     233                 :             :         /* Retry decoding message with backup Requester key.
     234                 :             :          * Must reset some of the parameters in case they were modified */
     235                 :           0 :         message_session_id = NULL;
     236                 :           0 :         decoded_message_ptr = backup_decoded_message_ptr;
     237                 :           0 :         decoded_message_size = backup_decoded_message_size;
     238                 :           0 :         status = context->transport_decode_message(
     239                 :             :             context, &message_session_id, is_app_message, true,
     240                 :             :             request_size, request, &decoded_message_size,
     241                 :             :             (void **)&decoded_message_ptr);
     242                 :             : 
     243                 :           0 :         reset_key_update = true;
     244                 :             :     }
     245                 :             : 
     246         [ +  + ]:           2 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     247                 :           1 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "transport_decode_message : %x\n", status));
     248         [ +  - ]:           1 :         if (context->last_spdm_error.error_code != 0) {
     249                 :             :             /* If the SPDM error code is Non-Zero, that means we need send the error message back to requester.
     250                 :             :              * In this case, we need return SUCCESS and let caller invoke libspdm_build_response() to send an ERROR message.*/
     251                 :           1 :             *session_id = &context->last_spdm_error.session_id;
     252                 :           1 :             *is_app_message = false;
     253                 :           1 :             return LIBSPDM_STATUS_SUCCESS;
     254                 :             :         }
     255                 :           0 :         return status;
     256                 :             :     }
     257                 :             : 
     258                 :             :     /* Handle special case for bi-directional communication:
     259                 :             :      * If the Requester returns RESPONSE_NOT_READY error to KEY_UPDATE, the Responder needs
     260                 :             :      * to activate backup key to parse the error. Then later the Requester will return SUCCESS,
     261                 :             :      * the Responder needs new key. So we need to restore the environment by
     262                 :             :      * libspdm_create_update_session_data_key() again.*/
     263         [ -  + ]:           1 :     if (reset_key_update) {
     264                 :             :         /* temp_session_context and message_session_id must necessarily
     265                 :             :          * be valid for us to reach here. */
     266   [ #  #  #  # ]:           0 :         if (temp_session_context == NULL || message_session_id == NULL) {
     267                 :           0 :             return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
     268                 :             :         }
     269                 :           0 :         result = libspdm_create_update_session_data_key(
     270                 :             :             temp_session_context, LIBSPDM_KEY_UPDATE_ACTION_REQUESTER);
     271         [ #  # ]:           0 :         if (!result) {
     272                 :           0 :             return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
     273                 :             :         }
     274                 :           0 :         libspdm_trigger_key_update_callback(
     275                 :             :             context, *message_session_id,
     276                 :             :             LIBSPDM_KEY_UPDATE_OPERATION_CREATE_UPDATE,
     277                 :             :             LIBSPDM_KEY_UPDATE_ACTION_REQUESTER);
     278                 :             :     }
     279                 :             : 
     280                 :             :     /*
     281                 :             :      * decoded_message may contain padding zeros due to transport layer alignment requirements.
     282                 :             :      * trim the decoded_message size to the maximum data_transfer_size.
     283                 :             :      */
     284                 :           1 :     decoded_message_size = LIBSPDM_MIN(decoded_message_size,
     285                 :             :                                        context->local_context.capability.data_transfer_size);
     286                 :             : 
     287                 :           1 :     context->last_spdm_request_size = decoded_message_size;
     288                 :           1 :     libspdm_copy_mem (context->last_spdm_request,
     289                 :           1 :                       libspdm_get_scratch_buffer_last_spdm_request_capacity(context),
     290                 :             :                       decoded_message_ptr,
     291                 :             :                       decoded_message_size);
     292                 :           1 :     libspdm_zero_mem (decoded_message_ptr, decoded_message_size);
     293                 :             : 
     294         [ +  - ]:           1 :     if (!(*is_app_message)) {
     295                 :             :         /* Check for minimal SPDM message size. */
     296         [ -  + ]:           1 :         if (context->last_spdm_request_size < sizeof(spdm_message_header_t)) {
     297                 :           0 :             return LIBSPDM_STATUS_UNSUPPORTED_CAP;
     298                 :             :         }
     299                 :             :     }
     300                 :             : 
     301                 :           1 :     *session_id = message_session_id;
     302                 :             : 
     303         [ -  + ]:           1 :     if (message_session_id != NULL) {
     304                 :           0 :         session_info = libspdm_get_session_info_via_session_id(context, *message_session_id);
     305         [ #  # ]:           0 :         if (session_info == NULL) {
     306                 :           0 :             return LIBSPDM_STATUS_UNSUPPORTED_CAP;
     307                 :             :         }
     308                 :           0 :         context->last_spdm_request_session_id = *message_session_id;
     309                 :           0 :         context->last_spdm_request_session_id_valid = true;
     310                 :             :     }
     311                 :             : 
     312         [ -  + ]:           1 :     LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmReceiveRequest[%x] msg %s(0x%x), size (0x%zx): \n",
     313                 :             :                    (message_session_id != NULL) ? *message_session_id : 0,
     314                 :             :                    libspdm_get_code_str(((spdm_message_header_t *)context->last_spdm_request)->
     315                 :             :                                         request_response_code),
     316                 :             :                    ((spdm_message_header_t *)context->last_spdm_request)->request_response_code,
     317                 :             :                    context->last_spdm_request_size));
     318                 :           1 :     LIBSPDM_INTERNAL_DUMP_HEX((uint8_t *)context->last_spdm_request,
     319                 :             :                               context->last_spdm_request_size);
     320                 :             : 
     321                 :           1 :     return LIBSPDM_STATUS_SUCCESS;
     322                 :             : }
     323                 :             : 
     324                 :             : /**
     325                 :             :  * Notify the session state to a session APP.
     326                 :             :  *
     327                 :             :  * @param  spdm_context                  A pointer to the SPDM context.
     328                 :             :  * @param  session_id                    The session_id of a session.
     329                 :             :  * @param  session_state                 The state of a session.
     330                 :             :  **/
     331                 :          38 : static void libspdm_trigger_session_state_callback(libspdm_context_t *spdm_context,
     332                 :             :                                                    uint32_t session_id,
     333                 :             :                                                    libspdm_session_state_t session_state)
     334                 :             : {
     335         [ +  + ]:          38 :     if (spdm_context->spdm_session_state_callback != NULL) {
     336                 :           2 :         ((libspdm_session_state_callback_func)
     337                 :           2 :          spdm_context->spdm_session_state_callback)(spdm_context, session_id, session_state);
     338                 :             :     }
     339                 :          38 : }
     340                 :             : 
     341                 :          39 : void libspdm_set_session_state(libspdm_context_t *spdm_context,
     342                 :             :                                uint32_t session_id,
     343                 :             :                                libspdm_session_state_t session_state)
     344                 :             : {
     345                 :             :     libspdm_session_info_t *session_info;
     346                 :             :     libspdm_session_state_t old_session_state;
     347                 :             : 
     348                 :          39 :     session_info = libspdm_get_session_info_via_session_id(spdm_context, session_id);
     349         [ -  + ]:          39 :     if (session_info == NULL) {
     350                 :           0 :         LIBSPDM_ASSERT(false);
     351                 :           0 :         return;
     352                 :             :     }
     353                 :             : 
     354                 :          39 :     old_session_state = libspdm_secured_message_get_session_state(
     355                 :             :         session_info->secured_message_context);
     356         [ +  + ]:          39 :     if (old_session_state != session_state) {
     357                 :          38 :         libspdm_secured_message_set_session_state(
     358                 :             :             session_info->secured_message_context, session_state);
     359                 :          38 :         libspdm_trigger_session_state_callback(
     360                 :             :             spdm_context, session_info->session_id, session_state);
     361                 :             :     }
     362                 :             : }
     363                 :             : 
     364                 :           2 : libspdm_return_t libspdm_terminate_session(
     365                 :             :     void *spdm_context, uint32_t session_id)
     366                 :             : {
     367                 :             :     libspdm_session_info_t *session_info;
     368                 :             : 
     369                 :           2 :     session_info = libspdm_get_session_info_via_session_id(spdm_context, session_id);
     370         [ +  + ]:           2 :     if (session_info == NULL) {
     371                 :           1 :         return LIBSPDM_STATUS_INVALID_PARAMETER;
     372                 :             :     }
     373                 :             : 
     374                 :           1 :     libspdm_set_session_state(spdm_context, session_id, LIBSPDM_SESSION_STATE_NOT_STARTED);
     375                 :           1 :     libspdm_free_session_id(spdm_context, session_id);
     376                 :           1 :     return LIBSPDM_STATUS_SUCCESS;
     377                 :             : }
     378                 :             : 
     379                 :             : /**
     380                 :             :  * Notify the connection state to an SPDM context register.
     381                 :             :  *
     382                 :             :  * @param  spdm_context                  A pointer to the SPDM context.
     383                 :             :  * @param  connection_state              Indicate the SPDM connection state.
     384                 :             :  **/
     385                 :         117 : static void libspdm_trigger_connection_state_callback(libspdm_context_t *spdm_context,
     386                 :             :                                                       libspdm_connection_state_t connection_state)
     387                 :             : {
     388         [ +  + ]:         117 :     if (spdm_context->spdm_connection_state_callback != NULL) {
     389                 :           1 :         ((libspdm_connection_state_callback_func)
     390                 :           1 :          spdm_context->spdm_connection_state_callback)(spdm_context, connection_state);
     391                 :             :     }
     392                 :         117 : }
     393                 :             : 
     394                 :         124 : void libspdm_set_connection_state(libspdm_context_t *spdm_context,
     395                 :             :                                   libspdm_connection_state_t connection_state)
     396                 :             : {
     397         [ +  + ]:         124 :     if (spdm_context->connection_info.connection_state != connection_state) {
     398                 :         117 :         spdm_context->connection_info.connection_state = connection_state;
     399                 :         117 :         libspdm_trigger_connection_state_callback(spdm_context, connection_state);
     400                 :             :     }
     401                 :         124 : }
     402                 :             : 
     403                 :          20 : void libspdm_trigger_key_update_callback(void *spdm_context, uint32_t session_id,
     404                 :             :                                          libspdm_key_update_operation_t key_update_op,
     405                 :             :                                          libspdm_key_update_action_t key_update_action)
     406                 :             : {
     407                 :             :     libspdm_context_t *context;
     408                 :             : 
     409                 :          20 :     context = spdm_context;
     410         [ +  + ]:          20 :     if (context->spdm_key_update_callback != NULL) {
     411                 :           1 :         ((libspdm_key_update_callback_func)
     412                 :           1 :          context->spdm_key_update_callback)(context, session_id, key_update_op, key_update_action);
     413                 :             :     }
     414                 :          20 : }
     415                 :             : 
     416                 :          32 : bool libspdm_is_request_unexpected_for_mut_auth_encap(libspdm_context_t *spdm_context,
     417                 :             :                                                       const uint32_t *session_id,
     418                 :             :                                                       uint8_t request_code,
     419                 :             :                                                       uint8_t *error_code)
     420                 :             : {
     421                 :             : #if LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP
     422                 :             :     /* During session-based mutual authentication, enforce that the Requester sends
     423                 :             :      * the next request required by the mut_auth_requested bits, before the flow
     424                 :             :      * advances (while response_state is still NORMAL).
     425                 :             :      *
     426                 :             :      * This keys off session_info->mut_auth_requested rather than the encapsulated
     427                 :             :      * context's flow_type. MUT_AUTH_REQUESTED (bit 0) has no encapsulated flow, so its
     428                 :             :      * flow_type is never set, and it is legal without ENCAP_CAP. */
     429                 :          32 :     libspdm_session_info_t *mut_auth_session_info = NULL;
     430                 :             : 
     431         [ +  + ]:          32 :     if (session_id != NULL) {
     432                 :           6 :         mut_auth_session_info = libspdm_get_session_info_via_session_id(spdm_context, *session_id);
     433   [ +  +  +  - ]:          36 :     } else if ((spdm_context->latest_session_id != INVALID_SESSION_ID) &&
     434                 :          10 :                libspdm_is_capabilities_flag_supported(
     435                 :             :                    spdm_context, false,
     436                 :             :                    SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP,
     437                 :             :                    SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) {
     438                 :             :         /* With handshake in the clear the session's handshake messages, including the
     439                 :             :          * encapsulated flow, are sent outside of a session, so the enforcement below
     440                 :             :          * applies to the channel outside of a session. */
     441                 :          10 :         mut_auth_session_info = libspdm_get_session_info_via_session_id(
     442                 :             :             spdm_context, spdm_context->latest_session_id);
     443                 :             :     }
     444                 :             : 
     445         [ +  + ]:          32 :     if ((mut_auth_session_info != NULL) &&
     446         [ +  - ]:          16 :         (spdm_context->response_state == LIBSPDM_RESPONSE_STATE_NORMAL)) {
     447                 :             :         libspdm_session_state_t session_state;
     448                 :          16 :         uint8_t expected_code = 0;
     449                 :          16 :         uint8_t reject_error_code = SPDM_ERROR_CODE_UNEXPECTED_REQUEST;
     450                 :          16 :         bool encap_flow_started = false;
     451                 :             : 
     452                 :             :         #if LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP
     453                 :             :         /* This only constrains the first request after KEY_EXCHANGE_RSP. Once the
     454                 :             :          * encapsulated flow has issued a request the messages that advance it are governed
     455                 :             :          * by the per-channel enforcement below. */
     456                 :          16 :         encap_flow_started = (mut_auth_session_info->encap_context.last_encap_request_size != 0);
     457                 :             :         #endif /* LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP */
     458                 :             : 
     459                 :          16 :         session_state = libspdm_secured_message_get_session_state(
     460                 :             :             mut_auth_session_info->secured_message_context);
     461   [ +  -  +  + ]:          16 :         if ((session_state == LIBSPDM_SESSION_STATE_HANDSHAKING) && !encap_flow_started) {
     462   [ +  +  +  - ]:          11 :             switch (mut_auth_session_info->mut_auth_requested) {
     463                 :           1 :             case SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED:
     464                 :           1 :                 expected_code = SPDM_FINISH;
     465                 :           1 :                 break;
     466                 :           5 :             case SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED_WITH_ENCAP_REQUEST:
     467                 :           5 :                 expected_code = SPDM_GET_ENCAPSULATED_REQUEST;
     468                 :           5 :                 break;
     469                 :           5 :             case SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED_WITH_GET_DIGESTS:
     470                 :           5 :                 expected_code = SPDM_DELIVER_ENCAPSULATED_RESPONSE;
     471                 :             :                 /* The optimized flow has already started, as the encapsulated request
     472                 :             :                  * accompanied KEY_EXCHANGE_RSP, so any other request is in flight rather
     473                 :             :                  * than unexpected. */
     474                 :           5 :                 reject_error_code = SPDM_ERROR_CODE_REQUEST_IN_FLIGHT;
     475                 :           5 :                 break;
     476                 :           0 :             default:
     477                 :           0 :                 break;
     478                 :             :             }
     479                 :             :         }
     480                 :             :         /* Outside of a session GET_VERSION is also legal, as it resets the connection.
     481                 :             :          * The chunk transfer messages are also legal, as they deliver the response that
     482                 :             :          * started the flow. */
     483   [ +  +  +  +  :          16 :         if ((expected_code != 0) && (request_code != expected_code) &&
                   +  - ]
     484   [ +  -  +  + ]:           9 :             (request_code != SPDM_CHUNK_GET) && (request_code != SPDM_CHUNK_SEND) &&
     485         [ +  + ]:           6 :             ((session_id != NULL) || (request_code != SPDM_GET_VERSION))) {
     486                 :           7 :             *error_code = reject_error_code;
     487                 :           7 :             return true;
     488                 :             :         }
     489                 :             :     }
     490                 :             : 
     491                 :             : #if LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP
     492                 :             :     /* During basic mutual authentication, once the Responder has signaled mutual
     493                 :             :      * authentication in its CHALLENGE_AUTH response, the next request from the Requester
     494                 :             :      * must be GET_ENCAPSULATED_REQUEST. The flow has not yet issued an encapsulated
     495                 :             :      * request while last_encap_request_size is 0. GET_VERSION is excluded because it
     496                 :             :      * resets the connection, and the chunk transfer messages are excluded because a
     497                 :             :      * large CHALLENGE_AUTH is delivered by CHUNK_GET. */
     498         [ +  + ]:          25 :     if ((session_id == NULL) &&
     499         [ +  + ]:          22 :         (spdm_context->encap_context.flow_type == LIBSPDM_ENCAP_FLOW_BASIC_MUT_AUTH) &&
     500   [ +  -  +  - ]:           3 :         (spdm_context->encap_context.last_encap_request_size == 0) &&
     501   [ +  +  +  - ]:           3 :         (request_code != SPDM_GET_ENCAPSULATED_REQUEST) && (request_code != SPDM_CHUNK_GET) &&
     502         [ +  + ]:           2 :         (request_code != SPDM_CHUNK_SEND) && (request_code != SPDM_GET_VERSION)) {
     503                 :           1 :         *error_code = SPDM_ERROR_CODE_UNEXPECTED_REQUEST;
     504                 :           1 :         return true;
     505                 :             :     }
     506                 :             : #endif /* LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP */
     507                 :             : #endif /* LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP */
     508                 :             : 
     509                 :             : #if LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP
     510                 :             :     /* An encapsulated flow is tracked per channel, so a flow in one secure session does
     511                 :             :      * not block requests in another session or outside of a session. While a flow is in
     512                 :             :      * progress on this channel only the messages that advance it, or that reset the
     513                 :             :      * connection, are legal. */
     514                 :             :     {
     515                 :             :         const libspdm_encap_context_t *channel_encap_context =
     516                 :          24 :             libspdm_get_encap_context_via_last_request(spdm_context);
     517                 :             : 
     518         [ +  - ]:          24 :         if ((channel_encap_context != NULL) &&
     519         [ +  + ]:          24 :             (channel_encap_context->flow_type != LIBSPDM_ENCAP_FLOW_NONE)) {
     520         [ +  + ]:           9 :             switch (request_code) {
     521                 :           7 :             case SPDM_GET_ENCAPSULATED_REQUEST:
     522                 :             :             case SPDM_DELIVER_ENCAPSULATED_RESPONSE:
     523                 :             :             case SPDM_GET_VERSION:
     524                 :             :             case SPDM_CHUNK_GET:
     525                 :             :             case SPDM_CHUNK_SEND:
     526                 :           7 :                 break;
     527                 :           2 :             default:
     528                 :           2 :                 *error_code = SPDM_ERROR_CODE_REQUEST_IN_FLIGHT;
     529                 :           2 :                 return true;
     530                 :             :             }
     531                 :             :         }
     532                 :             : #if LIBSPDM_RESPOND_IF_READY_SUPPORT
     533   [ +  -  +  + ]:          15 :         else if ((channel_encap_context != NULL) && channel_encap_context->response_not_ready) {
     534                 :             :             /* The flow was terminated by an encapsulated ERROR(ResponseNotReady), but the
     535                 :             :              * encapsulated request is still outstanding. The Requester must return to the
     536                 :             :              * flow so the Responder can reissue it with RESPOND_IF_READY. GET_VERSION is
     537                 :             :              * also allowed outside of a session, as it resets the connection. */
     538   [ +  +  +  + ]:           6 :             if ((request_code != SPDM_GET_ENCAPSULATED_REQUEST) &&
     539         [ +  + ]:           2 :                 ((session_id != NULL) || (request_code != SPDM_GET_VERSION))) {
     540                 :           3 :                 *error_code = SPDM_ERROR_CODE_REQUEST_IN_FLIGHT;
     541                 :           3 :                 return true;
     542                 :             :             }
     543                 :             :         }
     544                 :             : #endif /* LIBSPDM_RESPOND_IF_READY_SUPPORT */
     545                 :             :     }
     546                 :             : #endif /* LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP */
     547                 :             : 
     548                 :          19 :     return false;
     549                 :             : }
     550                 :             : 
     551                 :          38 : libspdm_return_t libspdm_build_response(void *spdm_context, const uint32_t *session_id,
     552                 :             :                                         bool is_app_message,
     553                 :             :                                         size_t *response_size,
     554                 :             :                                         void **response)
     555                 :             : {
     556                 :             :     libspdm_context_t *context;
     557                 :             :     uint8_t *my_response;
     558                 :             :     size_t my_response_size;
     559                 :             :     libspdm_return_t status;
     560                 :             :     libspdm_get_spdm_response_func get_response_func;
     561                 :             :     libspdm_session_info_t *session_info;
     562                 :             :     spdm_message_header_t *spdm_request;
     563                 :             :     spdm_message_header_t *spdm_response;
     564                 :             :     size_t transport_header_size;
     565                 :             :     uint8_t *scratch_buffer;
     566                 :             :     size_t scratch_buffer_size;
     567                 :             :     uint8_t request_response_code;
     568                 :             :     uint32_t actual_size;
     569                 :             : 
     570                 :             :     #if LIBSPDM_ENABLE_CAPABILITY_HBEAT_CAP
     571                 :             :     bool result;
     572                 :             :     #endif /* LIBSPDM_ENABLE_CAPABILITY_HBEAT_CAP */
     573                 :             : 
     574                 :             :     #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
     575                 :             :     uint8_t *large_buffer;
     576                 :             :     size_t large_buffer_size;
     577                 :             :     libspdm_chunk_info_t *get_info;
     578                 :             :     spdm_chunk_response_response_t *chunk_rsp;
     579                 :             :     uint8_t *chunk_ptr;
     580                 :             :     size_t chunk_send_ack_response_header_size;
     581                 :             :     #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
     582                 :             : 
     583                 :          38 :     context = spdm_context;
     584                 :          38 :     status = LIBSPDM_STATUS_UNSUPPORTED_CAP;
     585                 :             : 
     586                 :             :     /* For secure message, set up my_response to scratch buffer
     587                 :             :      * For non-secure message, set up my_response to sender buffer*/
     588                 :          38 :     transport_header_size = context->local_context.capability.transport_header_size;
     589         [ +  + ]:          38 :     if (session_id != NULL) {
     590                 :          10 :         libspdm_get_scratch_buffer (context, (void **)&scratch_buffer, &scratch_buffer_size);
     591                 :             :         #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
     592                 :          10 :         my_response = scratch_buffer + libspdm_get_scratch_buffer_secure_message_offset() +
     593                 :             :                       transport_header_size;
     594                 :          10 :         my_response_size = libspdm_get_scratch_buffer_secure_message_capacity(context) -
     595                 :          10 :                            transport_header_size -
     596                 :          10 :                            context->local_context.capability.transport_tail_size;
     597                 :             :         #else
     598                 :             :         my_response = scratch_buffer + transport_header_size;
     599                 :             :         my_response_size = scratch_buffer_size - transport_header_size -
     600                 :             :                            context->local_context.capability.transport_tail_size;
     601                 :             :         #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
     602                 :             :     } else {
     603                 :          28 :         my_response = (uint8_t *)*response + transport_header_size;
     604                 :          28 :         my_response_size = *response_size - transport_header_size -
     605                 :          28 :                            context->local_context.capability.transport_tail_size;
     606                 :             :     }
     607                 :          38 :     libspdm_zero_mem(my_response, my_response_size);
     608                 :             : 
     609                 :          38 :     spdm_response = (void *)my_response;
     610                 :             : 
     611         [ +  + ]:          38 :     if (context->last_spdm_error.error_code != 0) {
     612                 :             :         /* Error in libspdm_process_request(), and we need send error message directly. */
     613      [ +  +  - ]:           3 :         switch (context->last_spdm_error.error_code) {
     614                 :           2 :         case SPDM_ERROR_CODE_DECRYPT_ERROR:
     615                 :             :             /* session ID is valid. Use it to encrypt the error message.*/
     616         [ +  + ]:           2 :             if ((context->handle_error_return_policy &
     617                 :             :                  LIBSPDM_DATA_HANDLE_ERROR_RETURN_POLICY_DROP_ON_DECRYPT_ERROR) == 0) {
     618                 :           1 :                 status = libspdm_generate_error_response(
     619                 :             :                     context, SPDM_ERROR_CODE_DECRYPT_ERROR, 0,
     620                 :             :                     &my_response_size, my_response);
     621                 :             :             } else {
     622                 :             :                 /**
     623                 :             :                  * just ignore this message
     624                 :             :                  * return UNSUPPORTED and clear response_size to continue the dispatch without send response
     625                 :             :                  **/
     626                 :           1 :                 *response_size = 0;
     627                 :           1 :                 status = LIBSPDM_STATUS_UNSUPPORTED_CAP;
     628                 :             :             }
     629                 :           2 :             break;
     630                 :           1 :         case SPDM_ERROR_CODE_INVALID_SESSION:
     631                 :             :             /**
     632                 :             :              * don't use session ID, because we don't know which session ID should be used.
     633                 :             :              * just ignore this message
     634                 :             :              * return UNSUPPORTED and clear response_size to continue the dispatch without send response
     635                 :             :              **/
     636                 :           1 :             *response_size = 0;
     637                 :           1 :             status = LIBSPDM_STATUS_UNSUPPORTED_CAP;
     638                 :           1 :             break;
     639                 :           0 :         default:
     640                 :           0 :             LIBSPDM_ASSERT(false);
     641                 :           0 :             status = LIBSPDM_STATUS_UNSUPPORTED_CAP;
     642                 :             :         }
     643                 :             : 
     644         [ +  + ]:           3 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     645         [ +  + ]:           2 :             if ((session_id != NULL) &&
     646         [ +  - ]:           1 :                 (context->last_spdm_error.error_code == SPDM_ERROR_CODE_DECRYPT_ERROR)) {
     647                 :           1 :                 libspdm_free_session_id(context, *session_id);
     648                 :             :             }
     649                 :           2 :             return status;
     650                 :             :         }
     651                 :             : 
     652         [ +  - ]:           1 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmSendResponse[%x]: msg %s(0x%x), size (0x%zx): \n",
     653                 :             :                        (session_id != NULL) ? *session_id : 0,
     654                 :             :                        libspdm_get_code_str(spdm_response->request_response_code),
     655                 :             :                        spdm_response->request_response_code, my_response_size));
     656                 :           1 :         LIBSPDM_INTERNAL_DUMP_HEX(my_response, my_response_size);
     657                 :             : 
     658                 :           1 :         status = context->transport_encode_message(
     659                 :             :             context, session_id, false, false,
     660                 :             :             my_response_size, my_response, response_size, response);
     661         [ -  + ]:           1 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     662   [ #  #  #  # ]:           0 :             if ((session_id != NULL) &&
     663         [ #  # ]:           0 :                 ((status == LIBSPDM_STATUS_SEQUENCE_NUMBER_OVERFLOW) ||
     664                 :             :                  (status == LIBSPDM_STATUS_CRYPTO_ERROR))) {
     665                 :           0 :                 libspdm_free_session_id(context, *session_id);
     666                 :             :             }
     667                 :           0 :             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "transport_encode_message : %x\n", status));
     668                 :           0 :             return status;
     669                 :             :         }
     670                 :             : 
     671         [ +  - ]:           1 :         if ((session_id != NULL) &&
     672         [ +  - ]:           1 :             (context->last_spdm_error.error_code == SPDM_ERROR_CODE_DECRYPT_ERROR)) {
     673                 :           1 :             libspdm_free_session_id(context, *session_id);
     674                 :             :         }
     675                 :             : 
     676                 :           1 :         libspdm_zero_mem(&context->last_spdm_error, sizeof(context->last_spdm_error));
     677                 :           1 :         return LIBSPDM_STATUS_SUCCESS;
     678                 :             :     }
     679                 :             : 
     680         [ +  + ]:          35 :     if (session_id != NULL) {
     681                 :           8 :         session_info = libspdm_get_session_info_via_session_id(context, *session_id);
     682         [ -  + ]:           8 :         if (session_info == NULL) {
     683                 :           0 :             LIBSPDM_ASSERT(false);
     684                 :           0 :             return LIBSPDM_STATUS_UNSUPPORTED_CAP;
     685                 :             :         }
     686                 :             :     }
     687                 :             : 
     688         [ +  + ]:          35 :     if (*response == NULL) {
     689                 :           1 :         return LIBSPDM_STATUS_INVALID_PARAMETER;
     690                 :             :     }
     691   [ +  -  +  + ]:          34 :     if ((response_size == NULL) || (*response_size == 0)) {
     692                 :           1 :         return LIBSPDM_STATUS_INVALID_PARAMETER;
     693                 :             :     }
     694                 :             : 
     695         [ +  + ]:          33 :     LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmSendResponse[%x] ...\n",
     696                 :             :                    (session_id != NULL) ? *session_id : 0));
     697                 :             : 
     698                 :          33 :     spdm_request = (void *)context->last_spdm_request;
     699         [ +  + ]:          33 :     if (context->last_spdm_request_size == 0) {
     700                 :           1 :         return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
     701                 :             :     }
     702                 :             : 
     703                 :          32 :     get_response_func = NULL;
     704         [ +  - ]:          32 :     if (!is_app_message) {
     705                 :          32 :         get_response_func = libspdm_get_response_func_via_last_request(context);
     706                 :             : 
     707                 :             :         #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
     708                 :             :         /* Per DSP0274: The chunked transfer shall not be interrupted by any commands
     709                 :             :          * that are not part of the chunk transfer sequence, with the exception of
     710                 :             :          * GET_VERSION. The Responder shall return ErrorCode=UnexpectedRequest if an
     711                 :             :          * unexpected command is received during the chunked transfer. These error codes
     712                 :             :          * shall not interrupt the chunk transfer sequence. */
     713         [ +  + ]:          32 :         if (libspdm_request_interrupts_chunk_transfer(context, get_response_func)) {
     714                 :           2 :             status = libspdm_generate_error_response(
     715                 :             :                 context, SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
     716                 :             :                 &my_response_size, my_response);
     717                 :           2 :             goto response_dispatched;
     718                 :             :         }
     719                 :             :         #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
     720                 :             : 
     721         [ +  + ]:          30 :         if (get_response_func != NULL) {
     722                 :          29 :             uint8_t reject_error_code = 0;
     723                 :             : 
     724         [ +  + ]:          29 :             if (libspdm_is_request_unexpected_for_mut_auth_encap(
     725                 :          29 :                     context, session_id, spdm_request->request_response_code, &reject_error_code)) {
     726                 :          12 :                 status = libspdm_generate_error_response(
     727                 :             :                     context, reject_error_code, 0, &my_response_size, my_response);
     728                 :             :             } else {
     729                 :          17 :                 status = get_response_func(
     730                 :             :                     context,
     731                 :             :                     context->last_spdm_request_size,
     732                 :          17 :                     context->last_spdm_request,
     733                 :             :                     &my_response_size, my_response);
     734                 :             :             }
     735                 :             :         }
     736                 :             :     }
     737   [ +  -  +  + ]:          30 :     if (is_app_message || (get_response_func == NULL)) {
     738         [ -  + ]:           1 :         if (context->get_response_func != NULL) {
     739                 :           0 :             status = ((libspdm_get_response_func) context->get_response_func)(
     740                 :             :                 context, session_id, is_app_message,
     741                 :             :                 context->last_spdm_request_size,
     742                 :           0 :                 context->last_spdm_request,
     743                 :             :                 &my_response_size, my_response);
     744                 :             :         } else {
     745                 :           1 :             status = LIBSPDM_STATUS_UNSUPPORTED_CAP;
     746                 :             :         }
     747                 :             :     }
     748                 :             : 
     749                 :             :     #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
     750                 :          29 : response_dispatched:
     751         [ +  - ]:          32 :     if (libspdm_get_connection_version(context) < SPDM_MESSAGE_VERSION_14) {
     752                 :          32 :         chunk_send_ack_response_header_size = sizeof(spdm_chunk_send_ack_response_t);
     753                 :             :     } else {
     754                 :           0 :         chunk_send_ack_response_header_size = sizeof(spdm_chunk_send_ack_response_14_t);
     755                 :             :     }
     756                 :             :     #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
     757                 :             : 
     758         [ +  + ]:          32 :     if (status == LIBSPDM_STATUS_SUCCESS) {
     759         [ -  + ]:          31 :         LIBSPDM_ASSERT (my_response_size <= context->local_context.capability.max_spdm_msg_size);
     760                 :             :         /* large SPDM message is the SPDM message whose size is greater than the DataTransferSize of the receiving
     761                 :             :          * SPDM endpoint or greater than the transmit buffer size of the sending SPDM endpoint */
     762         [ +  + ]:          31 :         if ((context->connection_info.capability.max_spdm_msg_size != 0) &&
     763         [ +  + ]:           7 :             (my_response_size > context->connection_info.capability.max_spdm_msg_size)) {
     764                 :           1 :             LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "my_response_size > req max_spdm_msg_size\n"));
     765                 :           1 :             actual_size = (uint32_t)my_response_size;
     766                 :           1 :             status = libspdm_generate_extended_error_response(context,
     767                 :             :                                                               SPDM_ERROR_CODE_RESPONSE_TOO_LARGE,
     768                 :             :                                                               0,
     769                 :             :                                                               sizeof(uint32_t),
     770                 :             :                                                               (uint8_t *)&actual_size,
     771                 :             :                                                               &my_response_size, my_response);
     772         [ +  + ]:          30 :         } else if ((((context->connection_info.capability.data_transfer_size != 0) &&
     773         [ +  + ]:           7 :                      (my_response_size > context->connection_info.capability.data_transfer_size)) ||
     774         [ +  - ]:          29 :                     ((context->local_context.capability.sender_data_transfer_size != 0) &&
     775                 :          29 :                      (my_response_size >
     776   [ +  +  +  - ]:          32 :                       context->local_context.capability.sender_data_transfer_size))) &&
     777                 :           3 :                    libspdm_is_capabilities_flag_supported(
     778                 :             :                        context, false, SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP,
     779                 :             :                        SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP)) {
     780                 :             :             #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
     781                 :             : 
     782                 :           3 :             get_info = &context->chunk_context.get;
     783                 :             : 
     784                 :             :             /* Saving multiple large responses is not an expected use case.
     785                 :             :              * Therefore, if the requester did not perform chunk_get requests for
     786                 :             :              * previous large responses, they will be lost. */
     787         [ -  + ]:           3 :             if (get_info->chunk_in_use) {
     788                 :           0 :                 LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR,
     789                 :             :                                "Warning: Overwriting previous unrequested chunk_get info.\n"));
     790                 :             :             }
     791                 :             : 
     792                 :           3 :             libspdm_get_scratch_buffer(context, (void **)&scratch_buffer, &scratch_buffer_size);
     793                 :             : 
     794                 :             :             /* The first section of the scratch
     795                 :             :              * buffer may be used for other purposes. Use only after that section. */
     796                 :           6 :             large_buffer = (uint8_t *)scratch_buffer +
     797                 :           3 :                            libspdm_get_scratch_buffer_large_message_offset(spdm_context);
     798                 :           3 :             large_buffer_size = libspdm_get_scratch_buffer_large_message_capacity(spdm_context);
     799                 :             : 
     800                 :           3 :             get_info->chunk_in_use = true;
     801                 :             :             /* Increment chunk_handle here as opposed to end of chunk_get handler
     802                 :             :              * in case requester never issues chunk_get. */
     803                 :           3 :             get_info->chunk_handle++;
     804                 :           3 :             get_info->chunk_seq_no = 0;
     805                 :           3 :             get_info->chunk_bytes_transferred = 0;
     806                 :           3 :             get_info->large_message_capacity = large_buffer_size;
     807                 :             : 
     808                 :           3 :             libspdm_zero_mem(large_buffer, large_buffer_size);
     809                 :             : 
     810                 :             :             /* It's possible that the large response that was to be sent to the requester was
     811                 :             :              * a CHUNK_SEND_ACK + non-chunk response. In this case, to prevent chunking within
     812                 :             :              * chunking, only send back the actual response, by saving only non-chunk portion
     813                 :             :              * in the scratch buffer, used to respond to the next CHUNK_GET request. */
     814                 :           3 :             if (((spdm_message_header_t *)my_response)
     815         [ -  + ]:           3 :                 ->request_response_code == SPDM_CHUNK_SEND_ACK) {
     816                 :           0 :                 libspdm_copy_mem(large_buffer, large_buffer_size,
     817                 :           0 :                                  my_response + chunk_send_ack_response_header_size,
     818                 :             :                                  my_response_size - chunk_send_ack_response_header_size);
     819                 :           0 :                 get_info->large_message = large_buffer;
     820                 :           0 :                 get_info->large_message_size =
     821                 :           0 :                     my_response_size - chunk_send_ack_response_header_size;
     822                 :             :             } else {
     823                 :           3 :                 libspdm_copy_mem(large_buffer, large_buffer_size, my_response, my_response_size);
     824                 :             : 
     825                 :           3 :                 get_info->large_message = large_buffer;
     826                 :           3 :                 get_info->large_message_size = my_response_size;
     827                 :             :             }
     828                 :             : 
     829                 :           3 :             status = libspdm_generate_extended_error_response(context,
     830                 :             :                                                               SPDM_ERROR_CODE_LARGE_RESPONSE, 0,
     831                 :             :                                                               sizeof(uint8_t),
     832                 :           3 :                                                               &get_info->chunk_handle,
     833                 :             :                                                               &my_response_size, my_response);
     834                 :             :             #else
     835                 :             :             LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR,
     836                 :             :                            "Warning: Could not save chunk. Scratch buffer too small.\n"));
     837                 :             : 
     838                 :             :             status = libspdm_generate_extended_error_response(context,
     839                 :             :                                                               SPDM_ERROR_CODE_LARGE_RESPONSE,
     840                 :             :                                                               0, 0, NULL,
     841                 :             :                                                               &my_response_size, my_response);
     842                 :             :             #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
     843                 :             : 
     844         [ -  + ]:           3 :             if (LIBSPDM_STATUS_IS_ERROR(status)) {
     845                 :           0 :                 return status;
     846                 :             :             }
     847                 :             :         }
     848                 :             :     }
     849                 :             : 
     850                 :             :     /* if return the status: Responder drop the response
     851                 :             :      * just ignore this message
     852                 :             :      * return UNSUPPORTED and clear response_size to continue the dispatch without send response.*/
     853   [ -  +  -  - ]:          32 :     if ((my_response_size == 0) && (status == LIBSPDM_STATUS_UNSUPPORTED_CAP)) {
     854                 :           0 :         *response_size = 0;
     855                 :           0 :         status = LIBSPDM_STATUS_UNSUPPORTED_CAP;
     856                 :           0 :         goto done;
     857                 :             :     }
     858                 :             : 
     859         [ +  + ]:          32 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     860                 :           1 :         status = libspdm_generate_error_response(
     861                 :             :             context, SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
     862                 :           1 :             spdm_request->request_response_code, &my_response_size, my_response);
     863         [ -  + ]:           1 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     864                 :           0 :             goto done;
     865                 :             :         }
     866                 :             :     }
     867                 :             : 
     868         [ +  + ]:          32 :     LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmSendResponse[%x]: msg %s(0x%x), size (0x%zx): \n",
     869                 :             :                    (session_id != NULL) ? *session_id : 0,
     870                 :             :                    libspdm_get_code_str(spdm_response->request_response_code),
     871                 :             :                    spdm_response->request_response_code,
     872                 :             :                    my_response_size));
     873                 :          32 :     LIBSPDM_INTERNAL_DUMP_HEX(my_response, my_response_size);
     874                 :             : 
     875                 :          32 :     status = context->transport_encode_message(
     876                 :             :         context, session_id, is_app_message, false,
     877                 :             :         my_response_size, my_response, response_size, response);
     878         [ -  + ]:          32 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     879   [ #  #  #  # ]:           0 :         if ((session_id != NULL) &&
     880         [ #  # ]:           0 :             ((status == LIBSPDM_STATUS_SEQUENCE_NUMBER_OVERFLOW) ||
     881                 :             :              (status == LIBSPDM_STATUS_CRYPTO_ERROR))) {
     882                 :           0 :             libspdm_free_session_id(context, *session_id);
     883                 :             :         }
     884                 :           0 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "transport_encode_message : %x\n", status));
     885                 :           0 :         goto done;
     886                 :             :     }
     887                 :             : 
     888                 :          32 :     request_response_code = spdm_response->request_response_code;
     889                 :             :     #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
     890      [ -  +  + ]:          32 :     switch (request_response_code) {
     891                 :           0 :     case SPDM_CHUNK_SEND_ACK:
     892         [ #  # ]:           0 :         if (my_response_size > chunk_send_ack_response_header_size) {
     893                 :           0 :             request_response_code =
     894                 :           0 :                 ((spdm_message_header_t *)(my_response + chunk_send_ack_response_header_size))
     895                 :             :                 ->request_response_code;
     896                 :             :         }
     897                 :           0 :         break;
     898                 :           1 :     case SPDM_CHUNK_RESPONSE:
     899                 :           1 :         chunk_rsp = (spdm_chunk_response_response_t *)my_response;
     900                 :           1 :         chunk_ptr = (uint8_t *)(((uint32_t *)(chunk_rsp + 1)) + 1);
     901         [ +  - ]:           1 :         if (chunk_rsp->chunk_seq_no == 0) {
     902                 :           1 :             request_response_code = ((spdm_message_header_t *)chunk_ptr)->request_response_code;
     903                 :             :         }
     904                 :           1 :         break;
     905                 :          31 :     default:
     906                 :          31 :         break;
     907                 :             :     }
     908                 :             :     #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
     909                 :             : 
     910         [ +  + ]:          32 :     if (session_id != NULL) {
     911   [ -  -  -  + ]:           6 :         switch (request_response_code) {
     912                 :           0 :         case SPDM_FINISH_RSP:
     913         [ #  # ]:           0 :             if (!libspdm_is_capabilities_flag_supported(
     914                 :             :                     context, false,
     915                 :             :                     SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP,
     916                 :             :                     SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) {
     917                 :           0 :                 libspdm_set_session_state(
     918                 :             :                     context, *session_id,
     919                 :             :                     LIBSPDM_SESSION_STATE_ESTABLISHED);
     920                 :             :             }
     921                 :           0 :             break;
     922                 :           0 :         case SPDM_PSK_FINISH_RSP:
     923                 :           0 :             libspdm_set_session_state(context, *session_id, LIBSPDM_SESSION_STATE_ESTABLISHED);
     924                 :           0 :             break;
     925                 :           0 :         case SPDM_END_SESSION_ACK:
     926                 :             :             #if LIBSPDM_ENABLE_CAPABILITY_HBEAT_CAP
     927   [ #  #  #  # ]:           0 :             if ((session_info->heartbeat_period != 0) &&
     928                 :           0 :                 libspdm_is_capabilities_flag_supported(
     929                 :             :                     context, false,
     930                 :             :                     SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HBEAT_CAP,
     931                 :             :                     SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HBEAT_CAP)) {
     932                 :           0 :                 result = libspdm_stop_watchdog(spdm_context, *session_id);
     933         [ #  # ]:           0 :                 if (!result) {
     934                 :           0 :                     LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "libspdm_stop_watchdog error\n"));
     935                 :             :                     /* No need to return error for internal watchdog error. */
     936                 :             :                 }
     937                 :             :             }
     938                 :             :             #endif /* LIBSPDM_ENABLE_CAPABILITY_HBEAT_CAP */
     939                 :           0 :             libspdm_terminate_session(context, *session_id);
     940                 :           0 :             break;
     941                 :           6 :         default:
     942                 :             :             #if LIBSPDM_ENABLE_CAPABILITY_HBEAT_CAP
     943   [ -  +  -  - ]:           6 :             if ((session_info->heartbeat_period != 0) &&
     944                 :           0 :                 libspdm_is_capabilities_flag_supported(
     945                 :             :                     context, false,
     946                 :             :                     SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HBEAT_CAP,
     947                 :             :                     SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HBEAT_CAP)) {
     948                 :             :                 /* reset watchdog in any session messages. */
     949                 :           0 :                 result = libspdm_reset_watchdog(spdm_context, *session_id);
     950         [ #  # ]:           0 :                 if (!result) {
     951                 :           0 :                     LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "libspdm_reset_watchdog error\n"));
     952                 :             :                     /* No need to return error for internal watchdog error. */
     953                 :             :                 }
     954                 :             :             }
     955                 :             :             #endif /* LIBSPDM_ENABLE_CAPABILITY_HBEAT_CAP */
     956                 :           6 :             break;
     957                 :             :         }
     958                 :             :     } else {
     959         [ -  + ]:          26 :         switch (request_response_code) {
     960                 :           0 :         case SPDM_FINISH_RSP:
     961         [ #  # ]:           0 :             if (libspdm_is_capabilities_flag_supported(
     962                 :             :                     context, false,
     963                 :             :                     SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP,
     964                 :             :                     SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) {
     965                 :           0 :                 libspdm_set_session_state(
     966                 :             :                     context,
     967                 :             :                     context->latest_session_id,
     968                 :             :                     LIBSPDM_SESSION_STATE_ESTABLISHED);
     969                 :             :             }
     970                 :           0 :             break;
     971                 :          26 :         default:
     972                 :             :             /* No session state update needed */
     973                 :          26 :             break;
     974                 :             :         }
     975                 :             :     }
     976                 :             : 
     977                 :          32 :     status = LIBSPDM_STATUS_SUCCESS;
     978                 :          32 : done:
     979         [ +  + ]:          32 :     if (session_id != NULL) {
     980                 :             :         /* clean plain text in scratch buffer */
     981                 :           6 :         libspdm_zero_mem (my_response, my_response_size);
     982                 :             :     }
     983                 :          32 :     libspdm_zero_mem (context->last_spdm_request,
     984                 :          32 :                       libspdm_get_scratch_buffer_last_spdm_request_capacity(context));
     985                 :          32 :     context->last_spdm_request_size = 0;
     986                 :          32 :     context->last_spdm_request_session_id_valid = false;
     987                 :          32 :     return status;
     988                 :             : }
     989                 :             : 
     990                 :           1 : void libspdm_register_get_response_func(void *context, libspdm_get_response_func get_response_func)
     991                 :             : {
     992                 :             :     libspdm_context_t *spdm_context;
     993                 :             : 
     994                 :           1 :     spdm_context = context;
     995                 :           1 :     spdm_context->get_response_func = (void *)get_response_func;
     996                 :           1 : }
     997                 :             : 
     998                 :           1 : void libspdm_register_session_state_callback_func(
     999                 :             :     void *spdm_context,
    1000                 :             :     libspdm_session_state_callback_func spdm_session_state_callback)
    1001                 :             : {
    1002                 :             :     libspdm_context_t *context;
    1003                 :             : 
    1004         [ -  + ]:           1 :     LIBSPDM_ASSERT(spdm_context != NULL);
    1005                 :             : 
    1006                 :           1 :     context = spdm_context;
    1007                 :             : 
    1008                 :           1 :     context->spdm_session_state_callback = (void *)spdm_session_state_callback;
    1009                 :           1 : }
    1010                 :             : 
    1011                 :           1 : void libspdm_register_connection_state_callback_func(
    1012                 :             :     void *spdm_context,
    1013                 :             :     libspdm_connection_state_callback_func spdm_connection_state_callback)
    1014                 :             : {
    1015                 :             :     libspdm_context_t *context;
    1016                 :             : 
    1017         [ -  + ]:           1 :     LIBSPDM_ASSERT(spdm_context != NULL);
    1018                 :             : 
    1019                 :           1 :     context = spdm_context;
    1020                 :           1 :     context->spdm_connection_state_callback = (void *)spdm_connection_state_callback;
    1021                 :           1 : }
    1022                 :             : 
    1023                 :           1 : void libspdm_register_key_update_callback_func(
    1024                 :             :     void *spdm_context, libspdm_key_update_callback_func spdm_key_update_callback)
    1025                 :             : {
    1026                 :             :     libspdm_context_t *context;
    1027                 :             : 
    1028         [ -  + ]:           1 :     LIBSPDM_ASSERT(spdm_context != NULL);
    1029                 :             : 
    1030                 :           1 :     context = spdm_context;
    1031                 :           1 :     context->spdm_key_update_callback = (void *)spdm_key_update_callback;
    1032                 :           1 : }
        

Generated by: LCOV version 2.0-1