LCOV - code coverage report
Current view: top level - spdm_requester_lib - libspdm_req_key_update.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 80.4 % 163 131
Test Date: 2026-10-01 20:56:25 Functions: 100.0 % 2 2
Branches: 72.3 % 94 68

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

Generated by: LCOV version 2.0-1