Code coverage report for DMTF/libspdm
Current view: top level - library/spdm_responder_lib - libspdm_rsp_receive_send.c (source / functions) Coverage Total Hit
Test: 36148b912f76d231c18d216d6dee5c0858575bb1 Lines: 77.7 % 431 335
Test Date: 2026-10-25 08:40:22 Functions: 100.0 % 16 16
Branches: 66.2 % 296 196

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

Generated by: LCOV version 2.0-1