LCOV - code coverage report
Current view: top level - library/spdm_requester_lib - libspdm_req_get_digests.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 93.6 % 171 160
Test Date: 2025-06-29 08:09:00 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              : 
       9              : #if LIBSPDM_SEND_GET_CERTIFICATE_SUPPORT
      10              : 
      11              : #pragma pack(1)
      12              : typedef struct {
      13              :     spdm_message_header_t header;
      14              :     uint8_t digest[LIBSPDM_MAX_HASH_SIZE * SPDM_MAX_SLOT_COUNT];
      15              :     spdm_key_pair_id_t key_pair_id[SPDM_MAX_SLOT_COUNT];
      16              :     spdm_certificate_info_t cert_info[SPDM_MAX_SLOT_COUNT];
      17              :     spdm_key_usage_bit_mask_t key_usage_bit_mask[SPDM_MAX_SLOT_COUNT];
      18              : } libspdm_digests_response_max_t;
      19              : #pragma pack()
      20              : 
      21              : /**
      22              :  * This function sends GET_DIGESTS and receives DIGESTS *
      23              :  *
      24              :  * @param  context             A pointer to the SPDM context.
      25              :  * @param  slot_mask           Bitmask of the slots that contain certificates.
      26              :  * @param  total_digest_buffer A pointer to a destination buffer to store the digests.
      27              :  *
      28              :  * @retval LIBSPDM_STATUS_SUCCESS
      29              :  *         GET_DIGESTS was sent and DIGESTS was received.
      30              :  * @retval LIBSPDM_STATUS_INVALID_STATE_LOCAL
      31              :  *         Cannot send GET_DIGESTS due to Requester's state.
      32              :  * @retval LIBSPDM_STATUS_UNSUPPORTED_CAP
      33              :  *         Cannot send GET_DIGESTS because the Requester's and/or Responder's CERT_CAP = 0.
      34              :  * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE
      35              :  *         The size of the DIGESTS response is invalid.
      36              :  * @retval LIBSPDM_STATUS_INVALID_MSG_FIELD
      37              :  *         The DIGESTS response contains one or more invalid fields.
      38              :  * @retval LIBSPDM_STATUS_ERROR_PEER
      39              :  *         The Responder returned an unexpected error.
      40              :  * @retval LIBSPDM_STATUS_BUSY_PEER
      41              :  *         The Responder continually returned Busy error messages.
      42              :  * @retval LIBSPDM_STATUS_RESYNCH_PEER
      43              :  *         The Responder returned a RequestResynch error message.
      44              :  * @retval LIBSPDM_STATUS_BUFFER_FULL
      45              :  *         The buffer used to store transcripts is exhausted.
      46              :  **/
      47           45 : static libspdm_return_t libspdm_try_get_digest(libspdm_context_t *spdm_context,
      48              :                                                const uint32_t *session_id,
      49              :                                                uint8_t *slot_mask,
      50              :                                                void *total_digest_buffer)
      51              : {
      52              :     libspdm_return_t status;
      53              :     spdm_get_digest_request_t *spdm_request;
      54              :     size_t spdm_request_size;
      55              :     libspdm_digests_response_max_t *spdm_response;
      56              :     size_t spdm_response_size;
      57              :     size_t digest_size;
      58              :     size_t digest_count;
      59              :     size_t index;
      60              :     uint8_t *message;
      61              :     size_t message_size;
      62              :     size_t transport_header_size;
      63              :     libspdm_session_info_t *session_info;
      64              :     libspdm_session_state_t session_state;
      65              :     size_t additional_size;
      66              :     spdm_key_pair_id_t *key_pair_id;
      67              :     spdm_certificate_info_t *cert_info;
      68              :     spdm_key_usage_bit_mask_t *key_usage_bit_mask;
      69              :     size_t slot_index;
      70              :     uint8_t cert_model;
      71           45 :     uint8_t zero_digest[LIBSPDM_MAX_HASH_SIZE] = {0};
      72              : 
      73              :     /* -=[Verify State Phase]=- */
      74           45 :     if (!libspdm_is_capabilities_flag_supported(
      75              :             spdm_context, true, 0,
      76              :             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP)) {
      77            1 :         return LIBSPDM_STATUS_UNSUPPORTED_CAP;
      78              :     }
      79           44 :     if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
      80            1 :         return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
      81              :     }
      82              : 
      83           43 :     session_info = NULL;
      84           43 :     if (session_id != NULL) {
      85            1 :         session_info = libspdm_get_session_info_via_session_id(spdm_context, *session_id);
      86            1 :         if (session_info == NULL) {
      87            0 :             return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
      88              :         }
      89            1 :         session_state = libspdm_secured_message_get_session_state(
      90              :             session_info->secured_message_context);
      91            1 :         if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
      92            0 :             return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
      93              :         }
      94              :     }
      95              : 
      96           43 :     libspdm_reset_message_buffer_via_request_code(spdm_context, session_info, SPDM_GET_DIGESTS);
      97              : 
      98              :     /* -=[Construct Request Phase]=- */
      99           43 :     transport_header_size = spdm_context->local_context.capability.transport_header_size;
     100           43 :     status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
     101           43 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     102            1 :         return status;
     103              :     }
     104           42 :     LIBSPDM_ASSERT (message_size >= transport_header_size +
     105              :                     spdm_context->local_context.capability.transport_tail_size);
     106           42 :     spdm_request = (void *)(message + transport_header_size);
     107           42 :     spdm_request_size = message_size - transport_header_size -
     108           42 :                         spdm_context->local_context.capability.transport_tail_size;
     109              : 
     110           42 :     LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_get_digest_request_t));
     111           42 :     spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
     112           42 :     spdm_request->header.request_response_code = SPDM_GET_DIGESTS;
     113           42 :     spdm_request->header.param1 = 0;
     114           42 :     spdm_request->header.param2 = 0;
     115           42 :     spdm_request_size = sizeof(spdm_get_digest_request_t);
     116              : 
     117              :     /* -=[Send Request Phase]=- */
     118           42 :     status = libspdm_send_spdm_request(spdm_context, session_id, spdm_request_size, spdm_request);
     119           42 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     120            1 :         libspdm_release_sender_buffer (spdm_context);
     121            1 :         return status;
     122              :     }
     123           41 :     libspdm_release_sender_buffer (spdm_context);
     124           41 :     spdm_request = (void *)spdm_context->last_spdm_request;
     125              : 
     126              :     /* -=[Receive Response Phase]=- */
     127           41 :     status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
     128           41 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     129            1 :         return status;
     130              :     }
     131           40 :     LIBSPDM_ASSERT (message_size >= transport_header_size);
     132           40 :     spdm_response = (void *)(message);
     133           40 :     spdm_response_size = message_size;
     134              : 
     135           40 :     status = libspdm_receive_spdm_response(
     136              :         spdm_context, session_id, &spdm_response_size, (void **)&spdm_response);
     137           40 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     138            1 :         goto receive_done;
     139              :     }
     140              : 
     141              :     /* -=[Validate Response Phase]=- */
     142           39 :     if (spdm_response_size < sizeof(spdm_message_header_t)) {
     143            0 :         status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     144            0 :         goto receive_done;
     145              :     }
     146           39 :     if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
     147            1 :         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     148            1 :         goto receive_done;
     149              :     }
     150           38 :     if (spdm_response->header.request_response_code == SPDM_ERROR) {
     151           22 :         status = libspdm_handle_error_response_main(
     152              :             spdm_context, session_id,
     153              :             &spdm_response_size,
     154              :             (void **)&spdm_response, SPDM_GET_DIGESTS, SPDM_DIGESTS);
     155           22 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     156           22 :             goto receive_done;
     157              :         }
     158           16 :     } else if (spdm_response->header.request_response_code != SPDM_DIGESTS) {
     159            1 :         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     160            1 :         goto receive_done;
     161              :     }
     162           15 :     if (spdm_response_size < sizeof(spdm_digest_response_t)) {
     163            0 :         status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     164            0 :         goto receive_done;
     165              :     }
     166              : 
     167           15 :     digest_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
     168           15 :     if (slot_mask != NULL) {
     169           15 :         *slot_mask = spdm_response->header.param2;
     170              :     }
     171              : 
     172           15 :     LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "provisioned_slot_mask - 0x%02x\n",
     173              :                    spdm_response->header.param2));
     174           15 :     if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
     175            7 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "supported_slot_mask - 0x%02x\n",
     176              :                        spdm_response->header.param1));
     177              :         /* If bit is set in ProvisionedSlotMask then it must also be set in SupportedSlotMask. */
     178            7 :         if ((spdm_response->header.param1 & spdm_response->header.param2) !=
     179            7 :             spdm_response->header.param2) {
     180            1 :             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     181            1 :             goto receive_done;
     182              :         }
     183              :     }
     184              : 
     185           14 :     digest_count = 0;
     186          126 :     for (index = 0; index < SPDM_MAX_SLOT_COUNT; index++) {
     187          112 :         if (spdm_response->header.param2 & (1 << index)) {
     188           31 :             digest_count++;
     189              :         }
     190              :     }
     191           14 :     if (digest_count == 0) {
     192            1 :         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     193            1 :         goto receive_done;
     194              :     }
     195              : 
     196           13 :     additional_size = 0;
     197           13 :     if ((spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) &&
     198            6 :         spdm_context->connection_info.multi_key_conn_rsp) {
     199            5 :         additional_size = sizeof(spdm_key_pair_id_t) + sizeof(spdm_certificate_info_t) +
     200              :                           sizeof(spdm_key_usage_bit_mask_t);
     201              :     }
     202           13 :     if (spdm_response_size <
     203           13 :         sizeof(spdm_digest_response_t) + digest_count * (digest_size + additional_size)) {
     204            1 :         status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     205            1 :         goto receive_done;
     206              :     }
     207           12 :     spdm_response_size =
     208           12 :         sizeof(spdm_digest_response_t) + digest_count * (digest_size + additional_size);
     209              : 
     210              :     /* -=[Process Response Phase]=- */
     211           12 :     if (session_id == NULL) {
     212           11 :         status = libspdm_append_message_b(spdm_context, spdm_request, spdm_request_size);
     213           11 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     214            0 :             goto receive_done;
     215              :         }
     216              : 
     217           11 :         status = libspdm_append_message_b(spdm_context, spdm_response, spdm_response_size);
     218           11 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     219            0 :             goto receive_done;
     220              :         }
     221              : 
     222           11 :         if (spdm_context->connection_info.multi_key_conn_rsp) {
     223            5 :             status = libspdm_append_message_d(spdm_context, spdm_response, spdm_response_size);
     224            5 :             if (LIBSPDM_STATUS_IS_ERROR(status)) {
     225            0 :                 goto receive_done;
     226              :             }
     227              :         }
     228              :     }
     229              : 
     230           12 :     key_pair_id =
     231           12 :         (spdm_key_pair_id_t *)((uint8_t *)spdm_response->digest + digest_size * digest_count);
     232           12 :     cert_info =
     233              :         (spdm_certificate_info_t *)((uint8_t *)key_pair_id + sizeof(spdm_key_pair_id_t) *
     234              :                                     digest_count);
     235           12 :     key_usage_bit_mask =
     236              :         (spdm_key_usage_bit_mask_t *)((uint8_t *)cert_info + sizeof(spdm_certificate_info_t) *
     237              :                                       digest_count);
     238           39 :     for (index = 0; index < digest_count; index++) {
     239           27 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "digest (0x%zx) - ", index));
     240           27 :         LIBSPDM_INTERNAL_DUMP_DATA(&spdm_response->digest[digest_size * index], digest_size);
     241           27 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
     242              :     }
     243           12 :     if ((spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) &&
     244            6 :         spdm_context->connection_info.multi_key_conn_rsp) {
     245           18 :         for (index = 0; index < digest_count; index++) {
     246           13 :             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "key_pair_id (0x%zx) - 0x%02x\n", index,
     247              :                            key_pair_id[index]));
     248              :         }
     249           18 :         for (index = 0; index < digest_count; index++) {
     250           13 :             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "cert_info (0x%zx) - 0x%02x\n", index,
     251              :                            cert_info[index]));
     252              :         }
     253           18 :         for (index = 0; index < digest_count; index++) {
     254           13 :             LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "key_usage_bit_mask (0x%zx) - 0x%04x\n", index,
     255              :                            key_usage_bit_mask[index]));
     256              :         }
     257              :     }
     258              : 
     259           12 :     if (total_digest_buffer != NULL) {
     260           12 :         libspdm_copy_mem(total_digest_buffer, digest_size * digest_count,
     261           12 :                          spdm_response->digest, digest_size * digest_count);
     262              :     }
     263              : 
     264           12 :     spdm_context->connection_info.peer_provisioned_slot_mask = spdm_response->header.param2;
     265           12 :     if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
     266            6 :         spdm_context->connection_info.peer_supported_slot_mask = spdm_response->header.param1;
     267              :     } else {
     268            6 :         spdm_context->connection_info.peer_supported_slot_mask = spdm_response->header.param2;
     269              :     }
     270           12 :     libspdm_copy_mem(
     271           12 :         spdm_context->connection_info.peer_total_digest_buffer,
     272              :         sizeof(spdm_context->connection_info.peer_total_digest_buffer),
     273           12 :         spdm_response->digest, digest_size * digest_count);
     274           12 :     libspdm_zero_mem(spdm_context->connection_info.peer_key_pair_id,
     275              :                      sizeof(spdm_context->connection_info.peer_key_pair_id));
     276           12 :     libspdm_zero_mem(spdm_context->connection_info.peer_cert_info,
     277              :                      sizeof(spdm_context->connection_info.peer_cert_info));
     278           12 :     libspdm_zero_mem(spdm_context->connection_info.peer_key_usage_bit_mask,
     279              :                      sizeof(spdm_context->connection_info.peer_key_usage_bit_mask));
     280           12 :     if ((spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) &&
     281            6 :         spdm_context->connection_info.multi_key_conn_rsp) {
     282            5 :         slot_index = 0;
     283           22 :         for (index = 0; index < SPDM_MAX_SLOT_COUNT; index++) {
     284           20 :             if (spdm_response->header.param2 & (1 << index)) {
     285           13 :                 spdm_context->connection_info.peer_key_pair_id[index] = key_pair_id[slot_index];
     286           13 :                 cert_model = cert_info[slot_index] & SPDM_CERTIFICATE_INFO_CERT_MODEL_MASK;
     287           13 :                 if (cert_model > SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT) {
     288            0 :                     status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     289            0 :                     goto receive_done;
     290              :                 }
     291           13 :                 if (index == 0) {
     292            5 :                     if (cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT) {
     293            1 :                         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     294            1 :                         goto receive_done;
     295              :                     }
     296            4 :                     if ((key_usage_bit_mask[slot_index] &
     297              :                          (SPDM_KEY_USAGE_BIT_MASK_KEY_EX_USE |
     298              :                           SPDM_KEY_USAGE_BIT_MASK_CHALLENGE_USE |
     299              :                           SPDM_KEY_USAGE_BIT_MASK_MEASUREMENT_USE |
     300              :                           SPDM_KEY_USAGE_BIT_MASK_ENDPOINT_INFO_USE)) == 0) {
     301            1 :                         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     302            1 :                         goto receive_done;
     303              :                     }
     304              :                 }
     305           11 :                 if ((cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) &&
     306            1 :                     (!libspdm_consttime_is_mem_equal(
     307            1 :                          spdm_response->digest + digest_size * slot_index,
     308              :                          zero_digest,
     309              :                          digest_size))) {
     310            1 :                     status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     311            1 :                     goto receive_done;
     312              :                 }
     313           10 :                 spdm_context->connection_info.peer_cert_info[index] = cert_model;
     314           10 :                 spdm_context->connection_info.peer_key_usage_bit_mask[index] =
     315           10 :                     key_usage_bit_mask[slot_index];
     316           10 :                 slot_index++;
     317              :             }
     318              :         }
     319              :     }
     320              : 
     321              :     /* -=[Update State Phase]=- */
     322            9 :     if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_AFTER_DIGESTS) {
     323            7 :         spdm_context->connection_info.connection_state = LIBSPDM_CONNECTION_STATE_AFTER_DIGESTS;
     324              :     }
     325            9 :     status = LIBSPDM_STATUS_SUCCESS;
     326              : 
     327              :     /* -=[Log Message Phase]=- */
     328              :     #if LIBSPDM_ENABLE_MSG_LOG
     329            9 :     libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
     330              :     #endif /* LIBSPDM_ENABLE_MSG_LOG */
     331              : 
     332           40 : receive_done:
     333           40 :     libspdm_release_receiver_buffer (spdm_context);
     334           40 :     return status;
     335              : }
     336              : 
     337           45 : libspdm_return_t libspdm_get_digest(void *spdm_context, const uint32_t *session_id,
     338              :                                     uint8_t *slot_mask, void *total_digest_buffer)
     339              : {
     340              :     libspdm_context_t *context;
     341              :     size_t retry;
     342              :     uint64_t retry_delay_time;
     343              :     libspdm_return_t status;
     344              : 
     345           45 :     context = spdm_context;
     346           45 :     context->crypto_request = true;
     347           45 :     retry = context->retry_times;
     348           45 :     retry_delay_time = context->retry_delay_time;
     349              :     do {
     350           45 :         status = libspdm_try_get_digest(context, session_id, slot_mask, total_digest_buffer);
     351           45 :         if (status != LIBSPDM_STATUS_BUSY_PEER) {
     352           44 :             return status;
     353              :         }
     354              : 
     355            1 :         libspdm_sleep(retry_delay_time);
     356            1 :     } while (retry-- != 0);
     357              : 
     358            1 :     return status;
     359              : }
     360              : 
     361              : #endif /* LIBSPDM_SEND_GET_CERTIFICATE_SUPPORT */
        

Generated by: LCOV version 2.0-1