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: 69.3 % 176 122
Test Date: 2025-08-24 08:11:14 Functions: 75.0 % 4 3

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

Generated by: LCOV version 2.0-1