LCOV - code coverage report
Current view: top level - library/spdm_requester_lib - libspdm_req_key_update.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 80.4 % 163 131
Test Date: 2025-07-27 08:10:33 Functions: 100.0 % 2 2

            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_KEY_EX_CAP) || (LIBSPDM_ENABLE_CAPABILITY_PSK_CAP)
      11              : 
      12              : #pragma pack(1)
      13              : typedef struct {
      14              :     spdm_message_header_t header;
      15              :     uint8_t dummy_data[sizeof(spdm_error_data_response_not_ready_t)];
      16              : } libspdm_key_update_response_mine_t;
      17              : #pragma pack()
      18              : 
      19              : /**
      20              :  * This function sends KEY_UPDATE
      21              :  * to update keys for an SPDM Session.
      22              :  *
      23              :  * After keys are updated, this function also uses VERIFY_NEW_KEY to verify the key.
      24              :  *
      25              :  * @param  spdm_context                  A pointer to the SPDM context.
      26              :  * @param  session_id                    The session ID of the session.
      27              :  * @param  single_direction              true means the operation is UPDATE_KEY.
      28              :  *                                     false means the operation is UPDATE_ALL_KEYS.
      29              :  * @param  key_updated                   true means the operation is to verify key(s).
      30              :  *                                     false means the operation is to update and verify key(s).
      31              :  *
      32              :  * @retval RETURN_SUCCESS               The keys of the session are updated.
      33              :  * @retval RETURN_DEVICE_ERROR          A device error occurs when communicates with the device.
      34              :  * @retval RETURN_SECURITY_VIOLATION    Any verification fails.
      35              :  **/
      36           92 : static libspdm_return_t libspdm_try_key_update(libspdm_context_t *spdm_context,
      37              :                                                uint32_t session_id,
      38              :                                                bool single_direction, bool *key_updated)
      39              : {
      40              :     libspdm_return_t status;
      41              :     bool result;
      42              :     spdm_key_update_request_t *spdm_request;
      43              :     size_t spdm_request_size;
      44              :     libspdm_key_update_response_mine_t *spdm_response;
      45              :     size_t spdm_response_size;
      46              :     libspdm_session_info_t *session_info;
      47              :     libspdm_session_state_t session_state;
      48              :     uint8_t *message;
      49              :     size_t message_size;
      50              :     size_t transport_header_size;
      51              : 
      52           92 :     if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_11) {
      53            0 :         return LIBSPDM_STATUS_UNSUPPORTED_CAP;
      54              :     }
      55              : 
      56           92 :     if (!libspdm_is_capabilities_flag_supported(
      57              :             spdm_context, true,
      58              :             SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_UPD_CAP,
      59              :             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_UPD_CAP)) {
      60            1 :         return LIBSPDM_STATUS_UNSUPPORTED_CAP;
      61              :     }
      62              : 
      63           91 :     if (spdm_context->connection_info.connection_state <
      64              :         LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
      65            1 :         return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
      66              :     }
      67              :     session_info =
      68           90 :         libspdm_get_session_info_via_session_id(spdm_context, session_id);
      69           90 :     if (session_info == NULL) {
      70            0 :         LIBSPDM_ASSERT(false);
      71            0 :         return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
      72              :     }
      73           90 :     session_state = libspdm_secured_message_get_session_state(
      74              :         session_info->secured_message_context);
      75           90 :     if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
      76            1 :         return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
      77              :     }
      78              : 
      79           89 :     libspdm_reset_message_buffer_via_request_code(spdm_context, session_info, SPDM_KEY_UPDATE);
      80              : 
      81           89 :     if(!(*key_updated)) {
      82              : 
      83              :         /* Update key*/
      84              : 
      85           85 :         transport_header_size = spdm_context->local_context.capability.transport_header_size;
      86           85 :         status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
      87           85 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
      88            0 :             return status;
      89              :         }
      90           85 :         LIBSPDM_ASSERT (message_size >= transport_header_size +
      91              :                         spdm_context->local_context.capability.transport_tail_size);
      92           85 :         spdm_request = (void *)(message + transport_header_size);
      93           85 :         spdm_request_size = message_size - transport_header_size -
      94           85 :                             spdm_context->local_context.capability.transport_tail_size;
      95              : 
      96           85 :         LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_key_update_request_t));
      97           85 :         spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
      98           85 :         spdm_request->header.request_response_code = SPDM_KEY_UPDATE;
      99           85 :         if (single_direction) {
     100           57 :             spdm_request->header.param1 = SPDM_KEY_UPDATE_OPERATIONS_TABLE_UPDATE_KEY;
     101              :         } else {
     102           28 :             spdm_request->header.param1 = SPDM_KEY_UPDATE_OPERATIONS_TABLE_UPDATE_ALL_KEYS;
     103              :         }
     104           85 :         spdm_request->header.param2 = 0;
     105              : 
     106           85 :         if(!libspdm_get_random_number(sizeof(spdm_request->header.param2),
     107              :                                       &spdm_request->header.param2)) {
     108            0 :             libspdm_release_sender_buffer (spdm_context);
     109            0 :             return LIBSPDM_STATUS_LOW_ENTROPY;
     110              :         }
     111              : 
     112           85 :         spdm_request_size = sizeof(spdm_key_update_request_t);
     113              : 
     114              :         /* If updating both, create new responder key*/
     115           85 :         if (!single_direction) {
     116           28 :             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
     117              :                            "libspdm_create_update_session_data_key[%x] Responder\n",
     118              :                            session_id));
     119           28 :             result = libspdm_create_update_session_data_key(
     120              :                 session_info->secured_message_context,
     121              :                 LIBSPDM_KEY_UPDATE_ACTION_RESPONDER);
     122           28 :             if (!result) {
     123            0 :                 libspdm_release_sender_buffer (spdm_context);
     124            0 :                 return LIBSPDM_STATUS_CRYPTO_ERROR;
     125              :             }
     126              :         }
     127              : 
     128           85 :         status = libspdm_send_spdm_request(spdm_context, &session_id,
     129              :                                            spdm_request_size, spdm_request);
     130           85 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     131            1 :             libspdm_release_sender_buffer (spdm_context);
     132            1 :             return status;
     133              :         }
     134              : 
     135           84 :         libspdm_release_sender_buffer (spdm_context);
     136           84 :         spdm_request = (void *)spdm_context->last_spdm_request;
     137              : 
     138              :         /* receive */
     139              : 
     140           84 :         status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
     141           84 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     142            0 :             return status;
     143              :         }
     144           84 :         LIBSPDM_ASSERT (message_size >= transport_header_size);
     145           84 :         spdm_response = (void *)(message);
     146           84 :         spdm_response_size = message_size;
     147              : 
     148           84 :         status = libspdm_receive_spdm_response(
     149              :             spdm_context, &session_id, &spdm_response_size, (void **)&spdm_response);
     150              : 
     151           84 :         if (!LIBSPDM_STATUS_IS_ERROR(status)) {
     152           84 :             if (spdm_response->header.request_response_code == SPDM_ERROR) {
     153           50 :                 status = libspdm_handle_error_response_main(
     154              :                     spdm_context, &session_id,
     155              :                     &spdm_response_size, (void **)&spdm_response,
     156              :                     SPDM_KEY_UPDATE, SPDM_KEY_UPDATE_ACK);
     157           34 :             } else if (spdm_response_size != sizeof(spdm_key_update_response_t)) {
     158              :                 /* this message can only be in secured session thus
     159              :                  * don't need to consider transport layer padding, just check its exact size */
     160            0 :                 status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     161           34 :             } else if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
     162            0 :                 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     163           34 :             } else if ((spdm_response->header.request_response_code !=
     164           33 :                         SPDM_KEY_UPDATE_ACK) ||
     165           33 :                        (spdm_response->header.param1 != spdm_request->header.param1) ||
     166           32 :                        (spdm_response->header.param2 != spdm_request->header.param2)) {
     167            3 :                 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     168              :             }
     169              :         }
     170              : 
     171           84 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     172           51 :             if (!single_direction) {
     173           25 :                 LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
     174              :                                "libspdm_activate_update_session_data_key[%x] Responder old\n",
     175              :                                session_id));
     176           25 :                 result = libspdm_activate_update_session_data_key(
     177              :                     session_info->secured_message_context,
     178              :                     LIBSPDM_KEY_UPDATE_ACTION_RESPONDER, false);
     179           25 :                 if (!result) {
     180            0 :                     libspdm_release_receiver_buffer (spdm_context);
     181            0 :                     return LIBSPDM_STATUS_CRYPTO_ERROR;
     182              :                 }
     183              :             }
     184           51 :             libspdm_release_receiver_buffer (spdm_context);
     185           51 :             return status;
     186              :         }
     187              : 
     188           33 :         if (!single_direction) {
     189            3 :             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
     190              :                            "libspdm_activate_update_session_data_key[%x] Responder new\n",
     191              :                            session_id));
     192            3 :             result = libspdm_activate_update_session_data_key(
     193              :                 session_info->secured_message_context,
     194              :                 LIBSPDM_KEY_UPDATE_ACTION_RESPONDER, true);
     195            3 :             if (!result) {
     196            0 :                 libspdm_release_receiver_buffer (spdm_context);
     197            0 :                 return LIBSPDM_STATUS_CRYPTO_ERROR;
     198              :             }
     199              :         }
     200              : 
     201           33 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
     202              :                        "libspdm_create_update_session_data_key[%x] Requester\n",
     203              :                        session_id));
     204           33 :         result = libspdm_create_update_session_data_key(
     205              :             session_info->secured_message_context,
     206              :             LIBSPDM_KEY_UPDATE_ACTION_REQUESTER);
     207           33 :         if (!result) {
     208            0 :             libspdm_release_receiver_buffer (spdm_context);
     209            0 :             return LIBSPDM_STATUS_CRYPTO_ERROR;
     210              :         }
     211           33 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
     212              :                        "libspdm_activate_update_session_data_key[%x] Requester new\n",
     213              :                        session_id));
     214           33 :         result = libspdm_activate_update_session_data_key(
     215              :             session_info->secured_message_context,
     216              :             LIBSPDM_KEY_UPDATE_ACTION_REQUESTER, true);
     217           33 :         if (!result) {
     218            0 :             libspdm_release_receiver_buffer (spdm_context);
     219            0 :             return LIBSPDM_STATUS_CRYPTO_ERROR;
     220              :         }
     221              : 
     222              :         /* -=[Log Message Phase]=- */
     223              :         #if LIBSPDM_ENABLE_MSG_LOG
     224           33 :         libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
     225              :         #endif /* LIBSPDM_ENABLE_MSG_LOG */
     226              : 
     227           33 :         libspdm_release_receiver_buffer (spdm_context);
     228              :     }
     229              : 
     230           37 :     *key_updated = true;
     231              : 
     232              : 
     233              :     /* Verify key*/
     234              : 
     235           37 :     transport_header_size = spdm_context->local_context.capability.transport_header_size;
     236           37 :     status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
     237           37 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     238            0 :         return status;
     239              :     }
     240           37 :     LIBSPDM_ASSERT (message_size >= transport_header_size +
     241              :                     spdm_context->local_context.capability.transport_tail_size);
     242           37 :     spdm_request = (void *)(message + transport_header_size);
     243           37 :     spdm_request_size = message_size - transport_header_size -
     244           37 :                         spdm_context->local_context.capability.transport_tail_size;
     245              : 
     246           37 :     LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_key_update_request_t));
     247           37 :     spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
     248           37 :     spdm_request->header.request_response_code = SPDM_KEY_UPDATE;
     249           37 :     spdm_request->header.param1 = SPDM_KEY_UPDATE_OPERATIONS_TABLE_VERIFY_NEW_KEY;
     250           37 :     spdm_request->header.param2 = 1;
     251           37 :     if(!libspdm_get_random_number(sizeof(spdm_request->header.param2),
     252              :                                   &spdm_request->header.param2)) {
     253            0 :         libspdm_release_sender_buffer (spdm_context);
     254            0 :         return LIBSPDM_STATUS_LOW_ENTROPY;
     255              :     }
     256           37 :     spdm_request_size = sizeof(spdm_key_update_request_t);
     257              : 
     258           37 :     status = libspdm_send_spdm_request(spdm_context, &session_id,
     259              :                                        spdm_request_size, spdm_request);
     260           37 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     261            0 :         libspdm_release_sender_buffer (spdm_context);
     262            0 :         return status;
     263              :     }
     264           37 :     libspdm_release_sender_buffer (spdm_context);
     265           37 :     spdm_request = (void *)spdm_context->last_spdm_request;
     266              : 
     267              :     /* receive */
     268              : 
     269           37 :     status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
     270           37 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     271            0 :         return status;
     272              :     }
     273           37 :     LIBSPDM_ASSERT (message_size >= transport_header_size);
     274           37 :     spdm_response = (void *)(message);
     275           37 :     spdm_response_size = message_size;
     276              : 
     277           37 :     status = libspdm_receive_spdm_response(
     278              :         spdm_context, &session_id, &spdm_response_size, (void **)&spdm_response);
     279           37 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     280            0 :         libspdm_release_receiver_buffer (spdm_context);
     281            0 :         return status;
     282              :     }
     283              : 
     284           37 :     if (spdm_response->header.request_response_code == SPDM_ERROR) {
     285           26 :         status = libspdm_handle_error_response_main(
     286              :             spdm_context, &session_id,
     287              :             &spdm_response_size, (void **)&spdm_response,
     288              :             SPDM_KEY_UPDATE, SPDM_KEY_UPDATE_ACK);
     289           26 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     290           25 :             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmVerifyKey[%x] Failed\n", session_id));
     291           25 :             libspdm_release_receiver_buffer (spdm_context);
     292           25 :             return status;
     293              :         }
     294              :     }
     295              : 
     296              :     /* this message can only be in secured session
     297              :      * thus don't need to consider transport layer padding, just check its exact size */
     298           12 :     if (spdm_response_size != sizeof(spdm_key_update_response_t)) {
     299            0 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmVerifyKey[%x] Failed\n", session_id));
     300            0 :         libspdm_release_receiver_buffer (spdm_context);
     301            0 :         return LIBSPDM_STATUS_INVALID_MSG_SIZE;
     302              :     }
     303              : 
     304           12 :     if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
     305            0 :         libspdm_release_receiver_buffer (spdm_context);
     306            0 :         return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     307              :     }
     308              : 
     309           12 :     if ((spdm_response->header.request_response_code !=
     310           11 :          SPDM_KEY_UPDATE_ACK) ||
     311           11 :         (spdm_response->header.param1 != spdm_request->header.param1) ||
     312           10 :         (spdm_response->header.param2 != spdm_request->header.param2)) {
     313            3 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmVerifyKey[%x] Failed\n", session_id));
     314            3 :         libspdm_release_receiver_buffer (spdm_context);
     315            3 :         return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     316              :     }
     317            9 :     LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmVerifyKey[%x] Success\n", session_id));
     318              : 
     319              :     /* -=[Log Message Phase]=- */
     320              :     #if LIBSPDM_ENABLE_MSG_LOG
     321            9 :     libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
     322              :     #endif /* LIBSPDM_ENABLE_MSG_LOG */
     323              : 
     324            9 :     libspdm_release_receiver_buffer (spdm_context);
     325            9 :     return LIBSPDM_STATUS_SUCCESS;
     326              : }
     327              : 
     328           83 : libspdm_return_t libspdm_key_update(void *spdm_context, uint32_t session_id,
     329              :                                     bool single_direction)
     330              : {
     331              :     libspdm_context_t *context;
     332              :     size_t retry;
     333              :     uint64_t retry_delay_time;
     334              :     libspdm_return_t status;
     335              :     bool key_updated;
     336              : 
     337           83 :     context = spdm_context;
     338           83 :     key_updated = false;
     339           83 :     context->crypto_request = true;
     340           83 :     retry = context->retry_times;
     341           83 :     retry_delay_time = context->retry_delay_time;
     342              :     do {
     343           92 :         status = libspdm_try_key_update(spdm_context, session_id,
     344              :                                         single_direction, &key_updated);
     345           92 :         if (status != LIBSPDM_STATUS_BUSY_PEER) {
     346           80 :             return status;
     347              :         }
     348              : 
     349           12 :         libspdm_sleep(retry_delay_time);
     350           12 :     } while (retry-- != 0);
     351              : 
     352            3 :     return status;
     353              : }
     354              : 
     355              : #endif /* (LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP) || (LIBSPDM_ENABLE_CAPABILITY_PSK_CAP) */
        

Generated by: LCOV version 2.0-1