LCOV - code coverage report
Current view: top level - library/spdm_requester_lib - libspdm_req_get_capabilities.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 93.7 % 206 193
Test Date: 2025-06-29 08:09:00 Functions: 100.0 % 3 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              : 
       9              : /**
      10              :  * This function validates the Responder's capabilities.
      11              :  *
      12              :  * @param  capabilities_flag The Responder's CAPABILITIES.Flags field.
      13              :  * @param  version           The SPDM message version.
      14              :  *
      15              :  * @retval true  The field is valid.
      16              :  * @retval false The field is invalid.
      17              :  **/
      18           35 : static bool validate_responder_capability(uint32_t capabilities_flag, uint8_t version)
      19              : {
      20              :     /*uint8_t cache_cap = (uint8_t)(capabilities_flag)&0x01;*/
      21           35 :     const uint8_t cert_cap = (uint8_t)(capabilities_flag >> 1) & 0x01;
      22           35 :     const uint8_t chal_cap = (uint8_t)(capabilities_flag >> 2) & 0x01;
      23           35 :     const uint8_t meas_cap = (uint8_t)(capabilities_flag >> 3) & 0x03;
      24           35 :     const uint8_t meas_fresh_cap = (uint8_t)(capabilities_flag >> 5) & 0x01;
      25           35 :     const uint8_t encrypt_cap = (uint8_t)(capabilities_flag >> 6) & 0x01;
      26           35 :     const uint8_t mac_cap = (uint8_t)(capabilities_flag >> 7) & 0x01;
      27           35 :     const uint8_t mut_auth_cap = (uint8_t)(capabilities_flag >> 8) & 0x01;
      28           35 :     const uint8_t key_ex_cap = (uint8_t)(capabilities_flag >> 9) & 0x01;
      29           35 :     const uint8_t psk_cap = (uint8_t)(capabilities_flag >> 10) & 0x03;
      30           35 :     const uint8_t encap_cap = (uint8_t)(capabilities_flag >> 12) & 0x01;
      31           35 :     const uint8_t hbeat_cap = (uint8_t)(capabilities_flag >> 13) & 0x01;
      32           35 :     const uint8_t key_upd_cap = (uint8_t)(capabilities_flag >> 14) & 0x01;
      33           35 :     const uint8_t handshake_in_the_clear_cap = (uint8_t)(capabilities_flag >> 15) & 0x01;
      34           35 :     const uint8_t pub_key_id_cap = (uint8_t)(capabilities_flag >> 16) & 0x01;
      35              :     /* uint8_t chunk_cap = (uint8_t)(capabilities_flag >> 17) & 0x01; */
      36           35 :     const uint8_t alias_cert_cap = (uint8_t)(capabilities_flag >> 18) & 0x01;
      37           35 :     const uint8_t set_cert_cap = (uint8_t)(capabilities_flag >> 19) & 0x01;
      38           35 :     const uint8_t csr_cap = (uint8_t)(capabilities_flag >> 20) & 0x01;
      39           35 :     const uint8_t cert_install_reset_cap = (uint8_t)(capabilities_flag >> 21) & 0x01;
      40           35 :     const uint8_t ep_info_cap = (uint8_t)(capabilities_flag >> 22) & 0x03;
      41              :     /* const uint8_t mel_cap = (uint8_t)(capabilities_flag >> 24) & 0x01; */
      42           35 :     const uint8_t event_cap = (uint8_t)(capabilities_flag >> 25) & 0x01;
      43           35 :     const uint8_t multi_key_cap = (uint8_t)(capabilities_flag >> 26) & 0x03;
      44           35 :     const uint8_t get_key_pair_info_cap = (uint8_t)(capabilities_flag >> 28) & 0x01;
      45           35 :     const uint8_t set_key_pair_info_cap = (uint8_t)(capabilities_flag >> 29) & 0x01;
      46              : 
      47              :     /* Checks common to all SPDM versions. */
      48              : 
      49              :     /* Illegal to return reserved value. */
      50           35 :     if (meas_cap == 3) {
      51            1 :         return false;
      52              :     }
      53              : 
      54              :     /* If MEAS_FRESH_CAP is set then MEAS_CAP must be set. */
      55           34 :     if ((meas_cap == 0) && (meas_fresh_cap == 1)) {
      56            1 :         return false;
      57              :     }
      58              : 
      59           33 :     if (version == SPDM_MESSAGE_VERSION_10) {
      60              :         /* If measurements are not signed then CERT_CAP must equal CHAL_CAP.
      61              :          * If measurements are signed then CERT_CAP must be set. */
      62            7 :         if ((meas_cap == 0) || (meas_cap == 1)) {
      63            5 :             if (cert_cap != chal_cap) {
      64            1 :                 return false;
      65              :             }
      66            2 :         } else if (meas_cap == 2) {
      67            2 :             if (cert_cap == 0) {
      68            1 :                 return false;
      69              :             }
      70              :         }
      71            5 :         return true;
      72              :     }
      73              : 
      74              :     /* Checks common to 1.1 and higher. */
      75           26 :     if (version >= SPDM_MESSAGE_VERSION_11) {
      76              :         /* Illegal to return reserved values. */
      77           26 :         if (psk_cap == 3) {
      78            1 :             return false;
      79              :         }
      80              : 
      81              :         /* Checks that originate from key exchange capabilities. */
      82           25 :         if ((key_ex_cap == 1) || (psk_cap != 0)) {
      83           11 :             if ((mac_cap == 0) && (encrypt_cap == 0)) {
      84            4 :                 return false;
      85              :             }
      86              :         } else {
      87           14 :             if ((mac_cap == 1) || (encrypt_cap == 1) || (handshake_in_the_clear_cap == 1) ||
      88           11 :                 (hbeat_cap == 1) || (key_upd_cap == 1)) {
      89            3 :                 return false;
      90              :             }
      91           11 :             if (version >= SPDM_MESSAGE_VERSION_13) {
      92            1 :                 if (event_cap == 1) {
      93            0 :                     return false;
      94              :                 }
      95              :             }
      96              :         }
      97           18 :         if ((key_ex_cap == 0) && (psk_cap != 0)) {
      98            1 :             if (handshake_in_the_clear_cap == 1) {
      99            1 :                 return false;
     100              :             }
     101              :         }
     102              : 
     103              :         /* Checks that originate from certificate or public key capabilities. */
     104           17 :         if ((cert_cap == 1) || (pub_key_id_cap == 1)) {
     105              :             /* Certificate capabilities and public key capabilities cannot both be set. */
     106           12 :             if ((cert_cap == 1) && (pub_key_id_cap == 1)) {
     107            1 :                 return false;
     108              :             }
     109              :             /* If certificates or public keys are enabled then at least one of these capabilities
     110              :              * must be enabled to use the key. */
     111           11 :             if ((chal_cap == 0) && (key_ex_cap == 0) && ((meas_cap == 0) || (meas_cap == 1))) {
     112            1 :                 if (version >= SPDM_MESSAGE_VERSION_13) {
     113            0 :                     if ((ep_info_cap == 0) || (ep_info_cap == 1)) {
     114            0 :                         return false;
     115              :                     }
     116              :                 } else {
     117            1 :                     return false;
     118              :                 }
     119              :             }
     120              :         } else {
     121              :             /* If certificates or public keys are not enabled then these capabilities
     122              :              * cannot be enabled. */
     123            5 :             if ((chal_cap == 1) || (key_ex_cap == 1) || (meas_cap == 2) || (mut_auth_cap == 1)) {
     124            1 :                 return false;
     125              :             }
     126            4 :             if (version >= SPDM_MESSAGE_VERSION_13) {
     127            1 :                 if (ep_info_cap == 2) {
     128            1 :                     return false;
     129              :                 }
     130              :             }
     131              :         }
     132              : 
     133              :         /* Checks that originate from mutual authentication capabilities. */
     134           13 :         if (mut_auth_cap == 1) {
     135              :             /* Mutual authentication with asymmetric keys can only occur through the basic mutual
     136              :              * authentication flow (CHAL_CAP == 1) or the session-based mutual authentication flow
     137              :              * (KEY_EX_CAP == 1). */
     138            4 :             if ((key_ex_cap == 0) && (chal_cap == 0)) {
     139            0 :                 return false;
     140              :             }
     141              :         }
     142              :     }
     143              : 
     144              :     /* Checks specific to 1.1. */
     145           13 :     if (version == SPDM_MESSAGE_VERSION_11) {
     146            3 :         if ((mut_auth_cap == 1) && (encap_cap == 0)) {
     147            1 :             return false;
     148              :         }
     149              :     }
     150              : 
     151              :     /* Checks common to 1.2 and higher. */
     152           12 :     if (version >= SPDM_MESSAGE_VERSION_12) {
     153           10 :         if ((cert_cap == 0) && ((alias_cert_cap == 1) || (set_cert_cap == 1))) {
     154            1 :             return false;
     155              :         }
     156            9 :         if ((csr_cap == 1) && (set_cert_cap == 0)) {
     157            1 :             return false;
     158              :         }
     159            8 :         if ((cert_install_reset_cap == 1) && (csr_cap == 0) && (set_cert_cap == 0)) {
     160            1 :             return false;
     161              :         }
     162              :     }
     163              : 
     164              :     /* Checks specific to 1.3 and higher. */
     165            9 :     if (version >= SPDM_MESSAGE_VERSION_13) {
     166              :         /* Illegal to return reserved values. */
     167            1 :         if ((ep_info_cap == 3) || (multi_key_cap == 3)) {
     168            0 :             return false;
     169              :         }
     170            1 :         if ((multi_key_cap != 0) && ((get_key_pair_info_cap == 0) || (cert_cap == 0))) {
     171            0 :             return false;
     172              :         }
     173            1 :         if (pub_key_id_cap == 1) {
     174            0 :             if ((multi_key_cap != 0) || (get_key_pair_info_cap == 1) ||
     175              :                 (set_key_pair_info_cap == 1)) {
     176            0 :                 return false;
     177              :             }
     178              :         }
     179              :     }
     180              : 
     181              :     /* Checks that are deferred to when a message is sent.
     182              :      *
     183              :      * If the Responder supports key exchange then MAC_CAP must be set. In addition, if the
     184              :      * negotiated SPDM version is greater than 1.1 then the negotiated opaque data format must be
     185              :      * OpaqueDataFmt1.
     186              :      */
     187              : 
     188            9 :     return true;
     189              : }
     190              : 
     191              : /**
     192              :  * This function sends GET_CAPABILITIES and receives CAPABILITIES.
     193              :  *
     194              :  * @param  spdm_context A pointer to the SPDM context.
     195              :  *
     196              :  * @retval LIBSPDM_STATUS_SUCCESS
     197              :  *         GET_CAPABILITIES was sent and CAPABILITIES was received.
     198              :  * @retval LIBSPDM_STATUS_INVALID_STATE_LOCAL
     199              :  *         Cannot send GET_CAPABILITIES due to Requester's state. Send GET_VERSION first.
     200              :  * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE
     201              :  *         The size of the CAPABILITIES response is invalid.
     202              :  * @retval LIBSPDM_STATUS_INVALID_MSG_FIELD
     203              :  *         The CAPABILITIES response contains one or more invalid fields.
     204              :  * @retval LIBSPDM_STATUS_ERROR_PEER
     205              :  *         The Responder returned an unexpected error.
     206              :  * @retval LIBSPDM_STATUS_BUSY_PEER
     207              :  *         The Responder continually returned Busy error messages.
     208              :  * @retval LIBSPDM_STATUS_RESYNCH_PEER
     209              :  *         The Responder returned a RequestResynch error message.
     210              :  * @retval LIBSPDM_STATUS_BUFFER_FULL
     211              :  *         The buffer used to store transcripts is exhausted.
     212              :  **/
     213           68 : static libspdm_return_t libspdm_try_get_capabilities(libspdm_context_t *spdm_context)
     214              : {
     215              :     libspdm_return_t status;
     216              :     spdm_get_capabilities_request_t *spdm_request;
     217              :     size_t spdm_request_size;
     218              :     spdm_capabilities_response_t *spdm_response;
     219              :     size_t spdm_response_size;
     220              :     uint8_t *message;
     221              :     size_t message_size;
     222              :     size_t transport_header_size;
     223              : 
     224              :     /* -=[Verify State Phase]=- */
     225           68 :     if (spdm_context->connection_info.connection_state != LIBSPDM_CONNECTION_STATE_AFTER_VERSION) {
     226            1 :         return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
     227              :     }
     228           67 :     libspdm_reset_message_buffer_via_request_code(spdm_context, NULL, SPDM_GET_CAPABILITIES);
     229              : 
     230              :     /* -=[Construct Request Phase]=- */
     231           67 :     transport_header_size = spdm_context->local_context.capability.transport_header_size;
     232           67 :     status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
     233           67 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     234            1 :         return status;
     235              :     }
     236           66 :     LIBSPDM_ASSERT (message_size >= transport_header_size +
     237              :                     spdm_context->local_context.capability.transport_tail_size);
     238           66 :     spdm_request = (void *)(message + transport_header_size);
     239           66 :     spdm_request_size = message_size - transport_header_size -
     240           66 :                         spdm_context->local_context.capability.transport_tail_size;
     241              : 
     242           66 :     LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_request->header));
     243           66 :     libspdm_zero_mem(spdm_request, spdm_request_size);
     244           66 :     spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
     245           66 :     if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
     246           11 :         LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_get_capabilities_request_t));
     247           11 :         spdm_request_size = sizeof(spdm_get_capabilities_request_t);
     248           55 :     } else if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
     249           35 :         LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_get_capabilities_request_t) -
     250              :                         sizeof(spdm_request->data_transfer_size) -
     251              :                         sizeof(spdm_request->max_spdm_msg_size));
     252           35 :         spdm_request_size = sizeof(spdm_get_capabilities_request_t) -
     253              :                             sizeof(spdm_request->data_transfer_size) -
     254              :                             sizeof(spdm_request->max_spdm_msg_size);
     255              :     } else {
     256           20 :         spdm_request_size = sizeof(spdm_request->header);
     257              :     }
     258           66 :     spdm_request->header.request_response_code = SPDM_GET_CAPABILITIES;
     259           66 :     spdm_request->header.param1 = 0;
     260           66 :     spdm_request->header.param2 = 0;
     261           66 :     if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
     262           46 :         spdm_request->ct_exponent = spdm_context->local_context.capability.ct_exponent;
     263           46 :         spdm_request->flags =
     264           46 :             libspdm_mask_capability_flags(spdm_context, true,
     265              :                                           spdm_context->local_context.capability.flags);
     266              :     }
     267           66 :     if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
     268           11 :         spdm_request->data_transfer_size =
     269           11 :             spdm_context->local_context.capability.data_transfer_size;
     270           11 :         spdm_request->max_spdm_msg_size =
     271           11 :             spdm_context->local_context.capability.max_spdm_msg_size;
     272              :     }
     273              : 
     274              :     /* -=[Send Request Phase]=- */
     275           66 :     status = libspdm_send_spdm_request(spdm_context, NULL, spdm_request_size, spdm_request);
     276           66 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     277            1 :         libspdm_release_sender_buffer (spdm_context);
     278            1 :         return status;
     279              :     }
     280           65 :     libspdm_release_sender_buffer (spdm_context);
     281           65 :     spdm_request = (void *)spdm_context->last_spdm_request;
     282              : 
     283              :     /* -=[Receive Response Phase]=- */
     284           65 :     status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
     285           65 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     286            1 :         return status;
     287              :     }
     288           64 :     LIBSPDM_ASSERT (message_size >= transport_header_size);
     289           64 :     spdm_response = (void *)(message);
     290           64 :     spdm_response_size = message_size;
     291              : 
     292           64 :     status = libspdm_receive_spdm_response(spdm_context, NULL, &spdm_response_size,
     293              :                                            (void **)&spdm_response);
     294           64 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     295            3 :         goto receive_done;
     296              :     }
     297              : 
     298              :     /* -=[Validate Response Phase]=- */
     299           61 :     if (spdm_response_size < sizeof(spdm_message_header_t)) {
     300            0 :         status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     301            0 :         goto receive_done;
     302              :     }
     303           61 :     if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
     304            1 :         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     305            1 :         goto receive_done;
     306              :     }
     307           60 :     if (spdm_response->header.request_response_code == SPDM_ERROR) {
     308           23 :         status = libspdm_handle_simple_error_response(
     309           23 :             spdm_context, spdm_response->header.param1);
     310           23 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     311           23 :             goto receive_done;
     312              :         }
     313           37 :     } else if (spdm_response->header.request_response_code != SPDM_CAPABILITIES) {
     314            1 :         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     315            1 :         goto receive_done;
     316              :     }
     317           36 :     if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
     318           11 :         if (spdm_response_size < sizeof(spdm_capabilities_response_t)) {
     319            0 :             status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     320            0 :             goto receive_done;
     321              :         }
     322              :     } else {
     323           25 :         if (spdm_response_size < sizeof(spdm_capabilities_response_t) -
     324              :             sizeof(spdm_response->data_transfer_size) - sizeof(spdm_response->max_spdm_msg_size)) {
     325            1 :             status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     326            1 :             goto receive_done;
     327              :         }
     328              :     }
     329           35 :     if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
     330           11 :         spdm_response_size = sizeof(spdm_capabilities_response_t);
     331              :     } else {
     332           24 :         spdm_response_size = sizeof(spdm_capabilities_response_t) -
     333              :                              sizeof(spdm_response->data_transfer_size) -
     334              :                              sizeof(spdm_response->max_spdm_msg_size);
     335              :     }
     336              : 
     337           35 :     if (!validate_responder_capability(spdm_response->flags, spdm_response->header.spdm_version)) {
     338           21 :         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     339           21 :         goto receive_done;
     340              :     }
     341           14 :     if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
     342            7 :         if ((spdm_response->data_transfer_size < SPDM_MIN_DATA_TRANSFER_SIZE_VERSION_12) ||
     343            6 :             (spdm_response->data_transfer_size > spdm_response->max_spdm_msg_size)) {
     344            2 :             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     345            2 :             goto receive_done;
     346              :         }
     347              : 
     348            5 :         if (((spdm_response->flags & SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP) == 0) &&
     349            2 :             (spdm_response->data_transfer_size != spdm_response->max_spdm_msg_size)) {
     350            1 :             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     351            1 :             goto receive_done;
     352              :         }
     353              :     }
     354              : 
     355           11 :     if (spdm_response->ct_exponent > LIBSPDM_MAX_CT_EXPONENT) {
     356            1 :         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     357            1 :         goto receive_done;
     358              :     }
     359              : 
     360              :     /* -=[Process Response Phase]=- */
     361           10 :     status = libspdm_append_message_a(spdm_context, spdm_request, spdm_request_size);
     362           10 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     363            1 :         goto receive_done;
     364              :     }
     365              : 
     366            9 :     status = libspdm_append_message_a(spdm_context, spdm_response, spdm_response_size);
     367            9 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     368            0 :         goto receive_done;
     369              :     }
     370              : 
     371            9 :     spdm_context->connection_info.capability.ct_exponent = spdm_response->ct_exponent;
     372            9 :     spdm_context->connection_info.capability.flags =
     373            9 :         libspdm_mask_capability_flags(spdm_context, false, spdm_response->flags);
     374              : 
     375            9 :     if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
     376            2 :         spdm_context->connection_info.capability.data_transfer_size =
     377            2 :             spdm_response->data_transfer_size;
     378            2 :         spdm_context->connection_info.capability.max_spdm_msg_size =
     379            2 :             spdm_response->max_spdm_msg_size;
     380              :     } else {
     381            7 :         spdm_context->connection_info.capability.data_transfer_size = 0;
     382            7 :         spdm_context->connection_info.capability.max_spdm_msg_size = 0;
     383              :     }
     384              : 
     385              :     /* -=[Update State Phase]=- */
     386            9 :     spdm_context->connection_info.connection_state = LIBSPDM_CONNECTION_STATE_AFTER_CAPABILITIES;
     387            9 :     status = LIBSPDM_STATUS_SUCCESS;
     388              : 
     389              :     /* -=[Log Message Phase]=- */
     390              :     #if LIBSPDM_ENABLE_MSG_LOG
     391            9 :     libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
     392              :     #endif /* LIBSPDM_ENABLE_MSG_LOG */
     393              : 
     394           64 : receive_done:
     395           64 :     libspdm_release_receiver_buffer (spdm_context);
     396           64 :     return status;
     397              : }
     398              : 
     399           67 : libspdm_return_t libspdm_get_capabilities(libspdm_context_t *spdm_context)
     400              : {
     401              :     size_t retry;
     402              :     uint64_t retry_delay_time;
     403              :     libspdm_return_t status;
     404              : 
     405           67 :     spdm_context->crypto_request = false;
     406           67 :     retry = spdm_context->retry_times;
     407           67 :     retry_delay_time = spdm_context->retry_delay_time;
     408              :     do {
     409           68 :         status = libspdm_try_get_capabilities(spdm_context);
     410           68 :         if (status != LIBSPDM_STATUS_BUSY_PEER) {
     411           66 :             return status;
     412              :         }
     413              : 
     414            2 :         libspdm_sleep(retry_delay_time);
     415            2 :     } while (retry-- != 0);
     416              : 
     417            1 :     return status;
     418              : }
        

Generated by: LCOV version 2.0-1