LCOV - code coverage report
Current view: top level - library/spdm_responder_lib - libspdm_rsp_capabilities.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 87.9 % 140 123
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_responder_lib.h"
       8              : 
       9              : /**
      10              :  * This function checks the compatibility of the received SPDM version,
      11              :  * if received version is valid, subsequent spdm communication will follow this version.
      12              :  *
      13              :  * @param  spdm_context  A pointer to the SPDM context.
      14              :  * @param  version       The SPDM message version.
      15              :  *
      16              :  *
      17              :  * @retval true   The received SPDM version is valid.
      18              :  * @retval false  The received SPDM version is invalid.
      19              :  **/
      20           19 : static bool libspdm_check_request_version_compatibility(libspdm_context_t *spdm_context,
      21              :                                                         uint8_t version)
      22              : {
      23              :     uint8_t local_ver;
      24              :     size_t index;
      25              : 
      26           41 :     for (index = 0; index < spdm_context->local_context.version.spdm_version_count; index++) {
      27           41 :         local_ver = libspdm_get_version_from_version_number(
      28           41 :             spdm_context->local_context.version.spdm_version[index]);
      29           41 :         if (local_ver == version) {
      30           19 :             spdm_context->connection_info.version = version << SPDM_VERSION_NUMBER_SHIFT_BIT;
      31           19 :             return true;
      32              :         }
      33              :     }
      34            0 :     return false;
      35              : }
      36              : 
      37              : /**
      38              :  * This function checks the compatibility of the received GET_CAPABILITES flag.
      39              :  * Some flags are mutually inclusive/exclusive.
      40              :  *
      41              :  * @param  capabilities_flag  The received CAPABILITIES Flag.
      42              :  * @param  version            The SPDM message version.
      43              :  *
      44              :  *
      45              :  * @retval true   The received Capabilities flag is valid.
      46              :  * @retval false  The received Capabilities flag is invalid.
      47              :  **/
      48           19 : static bool libspdm_check_request_flag_compatibility(uint32_t capabilities_flag, uint8_t version)
      49              : {
      50           19 :     const uint8_t cert_cap = (uint8_t)(capabilities_flag >> 1) & 0x01;
      51           19 :     const uint8_t chal_cap = (uint8_t)(capabilities_flag >> 2) & 0x01;
      52           19 :     const uint8_t encrypt_cap = (uint8_t)(capabilities_flag >> 6) & 0x01;
      53           19 :     const uint8_t mac_cap = (uint8_t)(capabilities_flag >> 7) & 0x01;
      54           19 :     const uint8_t mut_auth_cap = (uint8_t)(capabilities_flag >> 8) & 0x01;
      55           19 :     const uint8_t key_ex_cap = (uint8_t)(capabilities_flag >> 9) & 0x01;
      56           19 :     const uint8_t psk_cap = (uint8_t)(capabilities_flag >> 10) & 0x03;
      57           19 :     const uint8_t encap_cap = (uint8_t)(capabilities_flag >> 12) & 0x01;
      58           19 :     const uint8_t hbeat_cap = (uint8_t)(capabilities_flag >> 13) & 0x01;
      59           19 :     const uint8_t key_upd_cap = (uint8_t)(capabilities_flag >> 14) & 0x01;
      60           19 :     const uint8_t handshake_in_the_clear_cap = (uint8_t)(capabilities_flag >> 15) & 0x01;
      61           19 :     const uint8_t pub_key_id_cap = (uint8_t)(capabilities_flag >> 16) & 0x01;
      62           19 :     const uint8_t ep_info_cap = (uint8_t)(capabilities_flag >> 22) & 0x03;
      63           19 :     const uint8_t event_cap = (uint8_t)(capabilities_flag >> 25) & 0x01;
      64           19 :     const uint8_t multi_key_cap = (uint8_t)(capabilities_flag >> 26) & 0x03;
      65              : 
      66              :     /* Checks common to 1.1 and higher */
      67           19 :     if (version >= SPDM_MESSAGE_VERSION_11) {
      68              :         /* Illegal to return reserved values. */
      69           17 :         if ((psk_cap == 2) || (psk_cap == 3)) {
      70            0 :             return false;
      71              :         }
      72              : 
      73              :         /* Checks that originate from key exchange capabilities. */
      74           17 :         if ((key_ex_cap == 1) || (psk_cap != 0)) {
      75           11 :             if ((mac_cap == 0) && (encrypt_cap == 0)) {
      76            2 :                 return false;
      77              :             }
      78              :         } else {
      79            6 :             if ((mac_cap == 1) || (encrypt_cap == 1) || (handshake_in_the_clear_cap == 1) ||
      80            4 :                 (hbeat_cap == 1) || (key_upd_cap == 1)) {
      81            2 :                 return false;
      82              :             }
      83            4 :             if (version >= SPDM_MESSAGE_VERSION_13) {
      84            1 :                 if (event_cap == 1) {
      85            0 :                     return false;
      86              :                 }
      87              :             }
      88              :         }
      89           13 :         if ((key_ex_cap == 0) && (psk_cap == 1)) {
      90            1 :             if (handshake_in_the_clear_cap == 1) {
      91            1 :                 return false;
      92              :             }
      93              :         }
      94              : 
      95              :         /* Checks that originate from certificate or public key capabilities. */
      96           12 :         if ((cert_cap == 1) || (pub_key_id_cap == 1)) {
      97              :             /* Certificate capabilities and public key capabilities cannot both be set. */
      98            9 :             if ((cert_cap == 1) && (pub_key_id_cap == 1)) {
      99            2 :                 return false;
     100              :             }
     101              :             /* If certificates or public keys are enabled then at least one of these capabilities
     102              :              * must be enabled to use the key. */
     103            7 :             if ((chal_cap == 0) && (key_ex_cap == 0)) {
     104            1 :                 if (version >= SPDM_MESSAGE_VERSION_13) {
     105            1 :                     if ((ep_info_cap == 0) || (ep_info_cap == 1)) {
     106            0 :                         return false;
     107              :                     }
     108              :                 } else {
     109            0 :                     return false;
     110              :                 }
     111              :             }
     112              :         } else {
     113              :             /* If certificates or public keys are not enabled then these capabilities
     114              :              * cannot be enabled. */
     115            3 :             if ((chal_cap == 1) || (mut_auth_cap == 1)) {
     116            0 :                 return false;
     117              :             }
     118            3 :             if (version >= SPDM_MESSAGE_VERSION_13) {
     119            0 :                 if (ep_info_cap == 2) {
     120            0 :                     return false;
     121              :                 }
     122              :             }
     123              :         }
     124              : 
     125              :         /* Checks that originate from mutual authentication capabilities. */
     126           10 :         if (mut_auth_cap == 1) {
     127              :             /* Mutual authentication with asymmetric keys can only occur through the basic mutual
     128              :              * authentication flow (CHAL_CAP == 1) or the session-based mutual authentication flow
     129              :              * (KEY_EX_CAP == 1). */
     130            6 :             if ((key_ex_cap == 0) && (chal_cap == 0)) {
     131            0 :                 return false;
     132              :             }
     133              :         }
     134              :     }
     135              : 
     136              :     /* Checks specific to 1.1. */
     137           12 :     if (version == SPDM_MESSAGE_VERSION_11) {
     138            6 :         if ((mut_auth_cap == 1) && (encap_cap == 0)) {
     139            1 :             return false;
     140              :         }
     141              :     }
     142              : 
     143              :     /* Checks specific to 1.3 and higher. */
     144           11 :     if (version >= SPDM_MESSAGE_VERSION_13) {
     145              :         /* Illegal to return reserved values. */
     146            1 :         if ((ep_info_cap == 3) || (multi_key_cap == 3)) {
     147            0 :             return false;
     148              :         }
     149            1 :         if ((multi_key_cap != 0) && ((pub_key_id_cap == 1) || (cert_cap == 0))) {
     150            0 :             return false;
     151              :         }
     152              :     }
     153              : 
     154              :     /* Checks that are deferred to when a message is received.
     155              :      *
     156              :      * If the Requester supports key exchange then MAC_CAP must be set. In addition, if the
     157              :      * negotiated SPDM version is greater than 1.1 then the negotiated opaque data format must be
     158              :      * OpaqueDataFmt1.
     159              :      */
     160              : 
     161           11 :     return true;
     162              : }
     163              : 
     164           22 : libspdm_return_t libspdm_get_response_capabilities(libspdm_context_t *spdm_context,
     165              :                                                    size_t request_size,
     166              :                                                    const void *request,
     167              :                                                    size_t *response_size,
     168              :                                                    void *response)
     169              : {
     170              :     const spdm_get_capabilities_request_t *spdm_request;
     171              :     spdm_capabilities_response_t *spdm_response;
     172              :     libspdm_return_t status;
     173              : 
     174           22 :     spdm_request = request;
     175              : 
     176              :     /* -=[Check Parameters Phase]=- */
     177           22 :     LIBSPDM_ASSERT(spdm_request->header.request_response_code == SPDM_GET_CAPABILITIES);
     178              : 
     179              :     /* -=[Verify State Phase]=- */
     180           22 :     if (spdm_context->response_state != LIBSPDM_RESPONSE_STATE_NORMAL) {
     181            2 :         return libspdm_responder_handle_response_state(
     182            2 :             spdm_context, spdm_request->header.request_response_code,  response_size, response);
     183              :     }
     184           20 :     if (spdm_context->connection_info.connection_state != LIBSPDM_CONNECTION_STATE_AFTER_VERSION) {
     185            1 :         return libspdm_generate_error_response(spdm_context,
     186              :                                                SPDM_ERROR_CODE_UNEXPECTED_REQUEST,
     187              :                                                0, response_size, response);
     188              :     }
     189              : 
     190              :     /* -=[Validate Request Phase]=- */
     191           19 :     if (!libspdm_check_request_version_compatibility(
     192           19 :             spdm_context, spdm_request->header.spdm_version)) {
     193            0 :         return libspdm_generate_error_response(spdm_context,
     194              :                                                SPDM_ERROR_CODE_VERSION_MISMATCH, 0,
     195              :                                                response_size, response);
     196              :     }
     197           19 :     if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
     198            4 :         if (request_size < sizeof(spdm_get_capabilities_request_t)) {
     199            0 :             return libspdm_generate_error_response(
     200              :                 spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
     201              :         } else {
     202            4 :             request_size = sizeof(spdm_get_capabilities_request_t);
     203              :         }
     204           15 :     } else if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
     205           13 :         if (request_size < sizeof(spdm_get_capabilities_request_t) -
     206              :             sizeof(spdm_request->data_transfer_size) - sizeof(spdm_request->max_spdm_msg_size)) {
     207            0 :             return libspdm_generate_error_response(
     208              :                 spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
     209              :         } else {
     210           13 :             request_size = sizeof(spdm_get_capabilities_request_t) -
     211              :                            sizeof(spdm_request->data_transfer_size) -
     212              :                            sizeof(spdm_request->max_spdm_msg_size);
     213              :         }
     214              :     } else {
     215            2 :         if (request_size < sizeof(spdm_message_header_t)) {
     216            0 :             return libspdm_generate_error_response(
     217              :                 spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
     218              :         } else {
     219            2 :             request_size = sizeof(spdm_message_header_t);
     220              :         }
     221              :     }
     222           19 :     if (!libspdm_check_request_flag_compatibility(
     223           19 :             spdm_request->flags, spdm_request->header.spdm_version)) {
     224            8 :         return libspdm_generate_error_response(spdm_context,
     225              :                                                SPDM_ERROR_CODE_INVALID_REQUEST, 0,
     226              :                                                response_size, response);
     227              :     }
     228           11 :     if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
     229            4 :         if ((spdm_request->data_transfer_size < SPDM_MIN_DATA_TRANSFER_SIZE_VERSION_12) ||
     230            4 :             (spdm_request->data_transfer_size > spdm_request->max_spdm_msg_size)) {
     231            1 :             return libspdm_generate_error_response(spdm_context,
     232              :                                                    SPDM_ERROR_CODE_INVALID_REQUEST, 0,
     233              :                                                    response_size, response);
     234              :         }
     235            3 :         if (((spdm_request->flags & SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP) == 0) &&
     236            2 :             (spdm_request->data_transfer_size != spdm_request->max_spdm_msg_size)) {
     237            1 :             return libspdm_generate_error_response(spdm_context,
     238              :                                                    SPDM_ERROR_CODE_INVALID_REQUEST, 0,
     239              :                                                    response_size, response);
     240              :         }
     241              :     }
     242            9 :     if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
     243            7 :         if (spdm_request->ct_exponent > LIBSPDM_MAX_CT_EXPONENT) {
     244            1 :             return libspdm_generate_error_response(spdm_context,
     245              :                                                    SPDM_ERROR_CODE_INVALID_REQUEST, 0,
     246              :                                                    response_size, response);
     247              :         }
     248              :     }
     249              : 
     250            8 :     libspdm_reset_message_buffer_via_request_code(spdm_context, NULL,
     251            8 :                                                   spdm_request->header.request_response_code);
     252              : 
     253              :     /* -=[Construct Response Phase]=- */
     254            8 :     LIBSPDM_ASSERT(*response_size >= sizeof(spdm_capabilities_response_t));
     255            8 :     *response_size = sizeof(spdm_capabilities_response_t);
     256            8 :     libspdm_zero_mem(response, *response_size);
     257            8 :     spdm_response = response;
     258              : 
     259            8 :     spdm_response->header.spdm_version = spdm_request->header.spdm_version;
     260            8 :     spdm_response->header.request_response_code = SPDM_CAPABILITIES;
     261            8 :     spdm_response->header.param1 = 0;
     262            8 :     spdm_response->header.param2 = 0;
     263            8 :     spdm_response->ct_exponent = spdm_context->local_context.capability.ct_exponent;
     264            8 :     spdm_response->flags =
     265            8 :         libspdm_mask_capability_flags(spdm_context, false,
     266              :                                       spdm_context->local_context.capability.flags);
     267            8 :     if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
     268            2 :         spdm_response->data_transfer_size =
     269            2 :             spdm_context->local_context.capability.data_transfer_size;
     270            2 :         spdm_response->max_spdm_msg_size =
     271            2 :             spdm_context->local_context.capability.max_spdm_msg_size;
     272              :     }
     273              : 
     274            8 :     if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
     275            2 :         *response_size = sizeof(spdm_capabilities_response_t);
     276              :     } else {
     277            6 :         *response_size = sizeof(spdm_capabilities_response_t) -
     278              :                          sizeof(spdm_response->data_transfer_size) -
     279              :                          sizeof(spdm_response->max_spdm_msg_size);
     280              :     }
     281              : 
     282              :     /* -=[Process Request Phase]=- */
     283            8 :     status = libspdm_append_message_a(spdm_context, spdm_request, request_size);
     284            8 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     285            0 :         return libspdm_generate_error_response(spdm_context,
     286              :                                                SPDM_ERROR_CODE_UNSPECIFIED, 0,
     287              :                                                response_size, response);
     288              :     }
     289            8 :     status = libspdm_append_message_a(spdm_context, spdm_response, *response_size);
     290              : 
     291            8 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     292            0 :         return libspdm_generate_error_response(spdm_context,
     293              :                                                SPDM_ERROR_CODE_UNSPECIFIED, 0,
     294              :                                                response_size, response);
     295              :     }
     296              : 
     297            8 :     if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
     298            6 :         spdm_context->connection_info.capability.ct_exponent = spdm_request->ct_exponent;
     299              :     } else {
     300            2 :         spdm_context->connection_info.capability.ct_exponent = 0;
     301              :     }
     302              : 
     303            8 :     spdm_context->connection_info.capability.flags =
     304            8 :         libspdm_mask_capability_flags(spdm_context, true, spdm_request->flags);
     305              : 
     306            8 :     if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
     307            2 :         spdm_context->connection_info.capability.data_transfer_size =
     308            2 :             spdm_request->data_transfer_size;
     309            2 :         spdm_context->connection_info.capability.max_spdm_msg_size =
     310            2 :             spdm_request->max_spdm_msg_size;
     311              :     } else {
     312            6 :         spdm_context->connection_info.capability.data_transfer_size = 0;
     313            6 :         spdm_context->connection_info.capability.max_spdm_msg_size = 0;
     314              :     }
     315              : 
     316              :     /* -=[Update State Phase]=- */
     317            8 :     libspdm_set_connection_state(spdm_context, LIBSPDM_CONNECTION_STATE_AFTER_CAPABILITIES);
     318              : 
     319            8 :     return LIBSPDM_STATUS_SUCCESS;
     320              : }
        

Generated by: LCOV version 2.0-1