LCOV - code coverage report
Current view: top level - library/spdm_requester_lib - libspdm_req_psk_finish.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 79.4 % 126 100
Test Date: 2025-06-29 08:09:00 Functions: 100.0 % 3 3

            Line data    Source code
       1              : /**
       2              :  *  Copyright Notice:
       3              :  *  Copyright 2021-2024 DMTF. All rights reserved.
       4              :  *  License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md
       5              :  **/
       6              : 
       7              : #include "internal/libspdm_requester_lib.h"
       8              : #include "internal/libspdm_secured_message_lib.h"
       9              : 
      10              : #if LIBSPDM_ENABLE_CAPABILITY_PSK_CAP
      11              : 
      12              : #pragma pack(1)
      13              : typedef struct {
      14              :     spdm_message_header_t header;
      15              :     uint8_t verify_data[LIBSPDM_MAX_HASH_SIZE];
      16              : } libspdm_psk_finish_request_mine_t;
      17              : 
      18              : typedef struct {
      19              :     spdm_message_header_t header;
      20              :     uint8_t dummy_data[sizeof(spdm_error_data_response_not_ready_t)];
      21              : } libspdm_psk_finish_response_max_t;
      22              : #pragma pack()
      23              : 
      24              : /**
      25              :  * This function generates the PSK finish HMAC based upon TH.
      26              :  *
      27              :  * @param  spdm_context                  A pointer to the SPDM context.
      28              :  * @param  session_info                  The session info of an SPDM session.
      29              :  * @param  hmac                         The buffer to store the finish HMAC.
      30              :  *
      31              :  * @retval true  PSK finish HMAC is generated.
      32              :  * @retval false PSK finish HMAC is not generated.
      33              :  **/
      34           31 : bool libspdm_generate_psk_exchange_req_hmac(libspdm_context_t *spdm_context,
      35              :                                             libspdm_session_info_t *session_info,
      36              :                                             void *hmac)
      37              : {
      38              :     size_t hash_size;
      39              :     uint8_t calc_hmac_data[LIBSPDM_MAX_HASH_SIZE];
      40              :     bool result;
      41              : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
      42              :     uint8_t *th_curr_data;
      43              :     size_t th_curr_data_size;
      44              :     libspdm_th_managed_buffer_t th_curr;
      45              :     uint8_t hash_data[LIBSPDM_MAX_HASH_SIZE];
      46              : #endif
      47              : 
      48           31 :     hash_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
      49              : 
      50              : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
      51              :     result = libspdm_calculate_th_for_finish(spdm_context, session_info, NULL,
      52              :                                              0, NULL, 0, &th_curr);
      53              :     if (!result) {
      54              :         return false;
      55              :     }
      56              :     th_curr_data = libspdm_get_managed_buffer(&th_curr);
      57              :     th_curr_data_size = libspdm_get_managed_buffer_size(&th_curr);
      58              : 
      59              :     result = libspdm_hash_all (spdm_context->connection_info.algorithm.base_hash_algo,
      60              :                                th_curr_data, th_curr_data_size, hash_data);
      61              :     if (!result) {
      62              :         return false;
      63              :     }
      64              : 
      65              :     result = libspdm_hmac_all_with_request_finished_key(
      66              :         session_info->secured_message_context, hash_data,
      67              :         hash_size, calc_hmac_data);
      68              :     if (!result) {
      69              :         return false;
      70              :     }
      71              : #else
      72           31 :     result = libspdm_calculate_th_hmac_for_finish_req(
      73              :         spdm_context, session_info, &hash_size, calc_hmac_data);
      74           31 :     if (!result) {
      75            0 :         return false;
      76              :     }
      77              : #endif
      78           31 :     LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "th_curr hmac - "));
      79           31 :     LIBSPDM_INTERNAL_DUMP_DATA(calc_hmac_data, hash_size);
      80           31 :     LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
      81              : 
      82           31 :     libspdm_copy_mem(hmac, hash_size, calc_hmac_data, hash_size);
      83              : 
      84           31 :     return true;
      85              : }
      86              : 
      87              : /**
      88              :  * This function sends PSK_FINISH and receives PSK_FINISH_RSP for SPDM PSK finish.
      89              :  *
      90              :  * @param  spdm_context                  A pointer to the SPDM context.
      91              :  * @param  session_id                    session_id to the PSK_FINISH request.
      92              :  *
      93              :  * @retval RETURN_SUCCESS               The PSK_FINISH is sent and the PSK_FINISH_RSP is received.
      94              :  * @retval RETURN_DEVICE_ERROR          A device error occurs when communicates with the device.
      95              :  **/
      96           34 : static libspdm_return_t libspdm_try_send_receive_psk_finish(libspdm_context_t *spdm_context,
      97              :                                                             uint32_t session_id)
      98              : {
      99              :     libspdm_return_t status;
     100              :     libspdm_psk_finish_request_mine_t *spdm_request;
     101              :     size_t spdm_request_size;
     102              :     size_t hmac_size;
     103              :     libspdm_psk_finish_response_max_t *spdm_response;
     104              :     size_t spdm_response_size;
     105              :     libspdm_session_info_t *session_info;
     106              :     uint8_t th2_hash_data[LIBSPDM_MAX_HASH_SIZE];
     107              :     libspdm_session_state_t session_state;
     108              :     bool result;
     109              :     uint8_t *message;
     110              :     size_t message_size;
     111              :     size_t transport_header_size;
     112              : 
     113           34 :     if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_11) {
     114            0 :         return LIBSPDM_STATUS_UNSUPPORTED_CAP;
     115              :     }
     116              : 
     117           34 :     if (!libspdm_is_capabilities_flag_supported(
     118              :             spdm_context, true,
     119              :             SPDM_GET_CAPABILITIES_REQUEST_FLAGS_PSK_CAP,
     120              :             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PSK_CAP_RESPONDER_WITH_CONTEXT)) {
     121            1 :         status = LIBSPDM_STATUS_UNSUPPORTED_CAP;
     122            1 :         goto error;
     123              :     }
     124              : 
     125           33 :     if (spdm_context->connection_info.connection_state <
     126              :         LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
     127            1 :         status = LIBSPDM_STATUS_INVALID_STATE_LOCAL;
     128            1 :         goto error;
     129              :     }
     130              : 
     131              :     session_info =
     132           32 :         libspdm_get_session_info_via_session_id(spdm_context, session_id);
     133           32 :     if (session_info == NULL) {
     134            0 :         LIBSPDM_ASSERT(false);
     135            0 :         status = LIBSPDM_STATUS_INVALID_STATE_LOCAL;
     136            0 :         goto error;
     137              :     }
     138           32 :     session_state = libspdm_secured_message_get_session_state(
     139              :         session_info->secured_message_context);
     140           32 :     if (session_state != LIBSPDM_SESSION_STATE_HANDSHAKING) {
     141            1 :         status = LIBSPDM_STATUS_INVALID_STATE_LOCAL;
     142            1 :         goto error;
     143              :     }
     144              : 
     145           31 :     transport_header_size = spdm_context->local_context.capability.transport_header_size;
     146           31 :     status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
     147           31 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     148            0 :         return status;
     149              :     }
     150           31 :     LIBSPDM_ASSERT (message_size >= transport_header_size +
     151              :                     spdm_context->local_context.capability.transport_tail_size);
     152           31 :     spdm_request = (void *)(message + transport_header_size);
     153           31 :     spdm_request_size = message_size - transport_header_size -
     154           31 :                         spdm_context->local_context.capability.transport_tail_size;
     155              : 
     156           31 :     LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_request->header));
     157           31 :     spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
     158           31 :     spdm_request->header.request_response_code = SPDM_PSK_FINISH;
     159           31 :     spdm_request->header.param1 = 0;
     160           31 :     spdm_request->header.param2 = 0;
     161              : 
     162           31 :     hmac_size = libspdm_get_hash_size(
     163              :         spdm_context->connection_info.algorithm.base_hash_algo);
     164           31 :     LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_request->header) + hmac_size);
     165           31 :     spdm_request_size = sizeof(spdm_psk_finish_request_t) + hmac_size;
     166              : 
     167           31 :     status = libspdm_append_message_f(spdm_context, session_info, true, (uint8_t *)spdm_request,
     168              :                                       spdm_request_size - hmac_size);
     169           31 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     170            0 :         libspdm_release_sender_buffer (spdm_context);
     171            0 :         goto error;
     172              :     }
     173              : 
     174           31 :     result = libspdm_generate_psk_exchange_req_hmac(spdm_context, session_info,
     175           31 :                                                     spdm_request->verify_data);
     176           31 :     if (!result) {
     177            0 :         libspdm_release_sender_buffer (spdm_context);
     178            0 :         status = LIBSPDM_STATUS_CRYPTO_ERROR;
     179            0 :         goto error;
     180              :     }
     181              : 
     182           31 :     status = libspdm_append_message_f(spdm_context, session_info, true,
     183              :                                       (uint8_t *)spdm_request +
     184           31 :                                       spdm_request_size - hmac_size,
     185              :                                       hmac_size);
     186           31 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     187            0 :         libspdm_release_sender_buffer (spdm_context);
     188            0 :         goto error;
     189              :     }
     190              : 
     191           31 :     status = libspdm_send_spdm_request(spdm_context, &session_id,
     192              :                                        spdm_request_size, spdm_request);
     193           31 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     194            1 :         libspdm_release_sender_buffer (spdm_context);
     195            1 :         goto error;
     196              :     }
     197              : 
     198           30 :     libspdm_reset_message_buffer_via_request_code(spdm_context, session_info,
     199              :                                                   SPDM_PSK_FINISH);
     200              : 
     201           30 :     libspdm_release_sender_buffer (spdm_context);
     202           30 :     spdm_request = (void *)spdm_context->last_spdm_request;
     203              : 
     204              :     /* receive */
     205              : 
     206           30 :     status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
     207           30 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     208            0 :         goto error;
     209              :     }
     210           30 :     LIBSPDM_ASSERT (message_size >= transport_header_size);
     211           30 :     spdm_response = (void *)(message);
     212           30 :     spdm_response_size = message_size;
     213              : 
     214           30 :     status = libspdm_receive_spdm_response(
     215              :         spdm_context, &session_id, &spdm_response_size, (void **)&spdm_response);
     216           30 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     217            0 :         goto receive_done;
     218              :     }
     219           30 :     if (spdm_response_size < sizeof(spdm_message_header_t)) {
     220            0 :         status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     221            0 :         goto receive_done;
     222              :     }
     223           30 :     if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
     224            0 :         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     225            0 :         goto receive_done;
     226              :     }
     227           30 :     if (spdm_response->header.request_response_code == SPDM_ERROR) {
     228           25 :         if (spdm_response->header.param1 == SPDM_ERROR_CODE_DECRYPT_ERROR) {
     229            2 :             status = LIBSPDM_STATUS_SESSION_MSG_ERROR;
     230            2 :             goto receive_done;
     231              :         }
     232           23 :         status = libspdm_handle_error_response_main(
     233              :             spdm_context, &session_id,
     234              :             &spdm_response_size, (void **)&spdm_response,
     235              :             SPDM_PSK_FINISH, SPDM_PSK_FINISH_RSP);
     236           23 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     237           22 :             goto receive_done;
     238              :         }
     239            5 :     } else if (spdm_response->header.request_response_code !=
     240              :                SPDM_PSK_FINISH_RSP) {
     241            1 :         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     242            1 :         goto receive_done;
     243              :     }
     244              :     /* this message can only be in secured session
     245              :      * thus don't need to consider transport layer padding, just check its exact size */
     246            5 :     if (spdm_response_size != sizeof(spdm_psk_finish_response_t)) {
     247            0 :         status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     248            0 :         goto receive_done;
     249              :     }
     250              : 
     251            5 :     status = libspdm_append_message_f(spdm_context, session_info, true, spdm_response,
     252              :                                       spdm_response_size);
     253            5 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     254            0 :         goto receive_done;
     255              :     }
     256              : 
     257            5 :     LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "libspdm_generate_session_data_key[%x]\n", session_id));
     258            5 :     result = libspdm_calculate_th2_hash(spdm_context, session_info, true,
     259              :                                         th2_hash_data);
     260            5 :     if (!result) {
     261            0 :         status = LIBSPDM_STATUS_CRYPTO_ERROR;
     262            0 :         goto receive_done;
     263              :     }
     264            5 :     result = libspdm_generate_session_data_key(
     265              :         session_info->secured_message_context, th2_hash_data);
     266            5 :     if (!result) {
     267            0 :         status = LIBSPDM_STATUS_CRYPTO_ERROR;
     268            0 :         goto receive_done;
     269              :     }
     270              : 
     271            5 :     libspdm_secured_message_set_session_state(
     272              :         session_info->secured_message_context,
     273              :         LIBSPDM_SESSION_STATE_ESTABLISHED);
     274              : 
     275              :     /* -=[Log Message Phase]=- */
     276              :     #if LIBSPDM_ENABLE_MSG_LOG
     277            5 :     libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
     278              :     #endif /* LIBSPDM_ENABLE_MSG_LOG */
     279              : 
     280            5 :     libspdm_release_receiver_buffer (spdm_context);
     281            5 :     return LIBSPDM_STATUS_SUCCESS;
     282              : 
     283           25 : receive_done:
     284           25 :     libspdm_release_receiver_buffer (spdm_context);
     285           29 : error:
     286           29 :     if (LIBSPDM_STATUS_BUSY_PEER != status) {
     287           27 :         libspdm_free_session_id(spdm_context, session_id);
     288              :     }
     289           29 :     return status;
     290              : }
     291              : 
     292           33 : libspdm_return_t libspdm_send_receive_psk_finish(libspdm_context_t *spdm_context,
     293              :                                                  uint32_t session_id)
     294              : {
     295              :     size_t retry;
     296              :     uint64_t retry_delay_time;
     297              :     libspdm_return_t status;
     298              : 
     299           33 :     spdm_context->crypto_request = true;
     300           33 :     retry = spdm_context->retry_times;
     301           33 :     retry_delay_time = spdm_context->retry_delay_time;
     302              :     do {
     303           34 :         status = libspdm_try_send_receive_psk_finish(spdm_context,
     304              :                                                      session_id);
     305           34 :         if (status != LIBSPDM_STATUS_BUSY_PEER) {
     306           32 :             return status;
     307              :         }
     308              : 
     309            2 :         libspdm_sleep(retry_delay_time);
     310            2 :     } while (retry-- != 0);
     311              : 
     312            1 :     return status;
     313              : }
     314              : 
     315              : #endif /* LIBSPDM_ENABLE_CAPABILITY_PSK_CAP*/
        

Generated by: LCOV version 2.0-1