LCOV - code coverage report
Current view: top level - library/spdm_responder_lib - libspdm_rsp_encap_get_certificate.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 55.6 % 160 89
Test Date: 2025-09-14 08:11:04 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_responder_lib.h"
       8              : 
       9              : #if (LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP) && (LIBSPDM_SEND_GET_CERTIFICATE_SUPPORT)
      10              : 
      11            2 : libspdm_return_t libspdm_get_encap_request_get_certificate(libspdm_context_t *spdm_context,
      12              :                                                            size_t *encap_request_size,
      13              :                                                            void *encap_request)
      14              : {
      15              :     spdm_get_certificate_large_request_t *spdm_request;
      16              :     libspdm_return_t status;
      17              :     uint32_t req_msg_length;
      18              :     uint32_t req_msg_offset;
      19              :     bool use_large_cert_chain;
      20              :     uint32_t req_msg_header_size;
      21              : 
      22            2 :     spdm_context->encap_context.last_encap_request_size = 0;
      23              : 
      24            2 :     if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_11) {
      25            0 :         return LIBSPDM_STATUS_UNSUPPORTED_CAP;
      26              :     }
      27              : 
      28            2 :     if (!libspdm_is_capabilities_flag_supported(
      29              :             spdm_context, false,
      30              :             SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CERT_CAP, 0)) {
      31            0 :         return LIBSPDM_STATUS_UNSUPPORTED_CAP;
      32              :     }
      33              : 
      34            2 :     if ((libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_14) &&
      35            0 :         libspdm_is_capabilities_flag_supported(
      36              :             spdm_context, false,
      37              :             SPDM_GET_CAPABILITIES_REQUEST_FLAGS_LARGE_RESP_CAP, 0)) {
      38            0 :         use_large_cert_chain = true;
      39            0 :         spdm_context->encap_context.use_large_cert_chain = true;
      40              :     } else {
      41            2 :         use_large_cert_chain = false;
      42            2 :         spdm_context->encap_context.use_large_cert_chain = false;
      43              :     }
      44              : 
      45            2 :     if (use_large_cert_chain) {
      46            0 :         req_msg_header_size = sizeof(spdm_get_certificate_large_request_t);
      47              :     } else {
      48            2 :         req_msg_header_size = sizeof(spdm_get_certificate_request_t);
      49              :     }
      50              : 
      51            2 :     LIBSPDM_ASSERT(*encap_request_size >= req_msg_header_size);
      52            2 :     *encap_request_size = req_msg_header_size;
      53              : 
      54            2 :     spdm_request = encap_request;
      55              : 
      56            2 :     spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
      57            2 :     spdm_request->header.request_response_code = SPDM_GET_CERTIFICATE;
      58            2 :     spdm_request->header.param1 = spdm_context->encap_context.req_slot_id;
      59            2 :     spdm_request->header.param2 = 0;
      60            2 :     req_msg_offset = (uint32_t)spdm_context->mut_auth_cert_chain_buffer_size;
      61            2 :     req_msg_length = LIBSPDM_MAX_CERT_CHAIN_BLOCK_LEN;
      62            2 :     if (use_large_cert_chain) {
      63            0 :         spdm_request->header.param1 |= SPDM_GET_CERTIFICATE_REQUEST_LARGE_CERT_CHAIN;
      64            0 :         spdm_request->offset = 0;
      65            0 :         spdm_request->length = 0;
      66            0 :         spdm_request->large_offset = req_msg_offset;
      67            0 :         spdm_request->large_length = req_msg_length;
      68              :     } else {
      69            2 :         spdm_request->offset = (uint16_t)req_msg_offset;
      70            2 :         spdm_request->length = (uint16_t)req_msg_length;
      71              :     }
      72            2 :     LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "request (offset 0x%x, size 0x%x):\n",
      73              :                    req_msg_offset, req_msg_length));
      74              : 
      75            2 :     libspdm_reset_message_buffer_via_request_code(spdm_context, NULL,
      76            2 :                                                   spdm_request->header.request_response_code);
      77              : 
      78              :     /* Cache data*/
      79            2 :     status = libspdm_append_message_mut_b(spdm_context, spdm_request, *encap_request_size);
      80            2 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
      81            0 :         return LIBSPDM_STATUS_BUFFER_FULL;
      82              :     }
      83              : 
      84            2 :     libspdm_copy_mem(&spdm_context->encap_context.last_encap_request_header,
      85              :                      sizeof(spdm_context->encap_context.last_encap_request_header),
      86            2 :                      &spdm_request->header, sizeof(spdm_message_header_t));
      87            2 :     spdm_context->encap_context.last_encap_request_size = *encap_request_size;
      88              : 
      89            2 :     return LIBSPDM_STATUS_SUCCESS;
      90              : }
      91              : 
      92           12 : libspdm_return_t libspdm_process_encap_response_certificate(
      93              :     libspdm_context_t *spdm_context, size_t encap_response_size,
      94              :     const void *encap_response, bool *need_continue)
      95              : {
      96              :     const spdm_certificate_large_response_t *spdm_response;
      97              :     size_t spdm_response_size;
      98              :     bool result;
      99              :     libspdm_return_t status;
     100              :     uint32_t request_offset;
     101              :     uint8_t slot_id;
     102              :     uint8_t *cert_chain_buffer;
     103              :     size_t cert_chain_buffer_size;
     104              :     size_t cert_chain_buffer_max_size;
     105              :     uint8_t cert_model;
     106              :     uint32_t rsp_msg_portion_length;
     107              :     uint32_t rsp_msg_remainder_length;
     108              :     bool use_large_cert_chain;
     109              :     uint32_t rsp_msg_header_size;
     110              :     uint32_t max_cert_chain_size;
     111              : 
     112           12 :     spdm_response = encap_response;
     113           12 :     spdm_response_size = encap_response_size;
     114              : 
     115           12 :     cert_chain_buffer = (uint8_t *)spdm_context->mut_auth_cert_chain_buffer;
     116           12 :     cert_chain_buffer_size = spdm_context->mut_auth_cert_chain_buffer_size;
     117           12 :     cert_chain_buffer_max_size = spdm_context->mut_auth_cert_chain_buffer_max_size;
     118              : 
     119           12 :     if (spdm_response_size < sizeof(spdm_message_header_t)) {
     120            0 :         return LIBSPDM_STATUS_INVALID_MSG_SIZE;
     121              :     }
     122           12 :     if (spdm_response->header.spdm_version != libspdm_get_connection_version (spdm_context)) {
     123            0 :         return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     124              :     }
     125           12 :     if (spdm_response->header.request_response_code == SPDM_ERROR) {
     126            2 :         status = libspdm_handle_encap_error_response_main(
     127            2 :             spdm_context, spdm_response->header.param1);
     128            2 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     129            2 :             return status;
     130              :         }
     131           10 :     } else if (spdm_response->header.request_response_code != SPDM_CERTIFICATE) {
     132            0 :         return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     133              :     }
     134           10 :     use_large_cert_chain = spdm_context->encap_context.use_large_cert_chain;
     135           10 :     if (use_large_cert_chain) {
     136            0 :         if ((spdm_response->header.param1 & SPDM_CERTIFICATE_RESPONSE_LARGE_CERT_CHAIN) == 0) {
     137            0 :             return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     138              :         }
     139              :     } else {
     140           10 :         if ((spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_14) &&
     141            0 :             ((spdm_response->header.param1 & SPDM_CERTIFICATE_RESPONSE_LARGE_CERT_CHAIN) != 0)) {
     142            0 :             return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     143              :         }
     144              :     }
     145              : 
     146           10 :     if (use_large_cert_chain) {
     147            0 :         max_cert_chain_size = SPDM_MAX_CERTIFICATE_CHAIN_SIZE_14;
     148            0 :         rsp_msg_header_size = sizeof(spdm_certificate_large_response_t);
     149              :     } else {
     150           10 :         max_cert_chain_size = SPDM_MAX_CERTIFICATE_CHAIN_SIZE;
     151           10 :         rsp_msg_header_size = sizeof(spdm_certificate_response_t);
     152              :     }
     153              : 
     154           10 :     if (encap_response_size < rsp_msg_header_size) {
     155            0 :         return LIBSPDM_STATUS_INVALID_MSG_SIZE;
     156              :     }
     157           10 :     if (use_large_cert_chain) {
     158            0 :         rsp_msg_portion_length = spdm_response->large_portion_length;
     159            0 :         rsp_msg_remainder_length = spdm_response->large_remainder_length;
     160              :     } else {
     161           10 :         rsp_msg_portion_length = spdm_response->portion_length;
     162           10 :         rsp_msg_remainder_length = spdm_response->remainder_length;
     163              :     }
     164              : 
     165           10 :     if ((rsp_msg_portion_length > LIBSPDM_MAX_CERT_CHAIN_BLOCK_LEN) ||
     166              :         (rsp_msg_portion_length == 0)) {
     167            2 :         return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     168              :     }
     169              : 
     170            8 :     request_offset = (uint32_t)cert_chain_buffer_size;
     171              : 
     172            8 :     if (rsp_msg_portion_length > max_cert_chain_size - request_offset) {
     173            0 :         return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     174              :     }
     175            8 :     if (rsp_msg_remainder_length > max_cert_chain_size - request_offset - rsp_msg_portion_length) {
     176            0 :         return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     177              :     }
     178            8 :     if (request_offset == 0) {
     179            8 :         spdm_context->encap_context.cert_chain_total_len = rsp_msg_portion_length +
     180              :                                                            rsp_msg_remainder_length;
     181            0 :     } else if (spdm_context->encap_context.cert_chain_total_len !=
     182            0 :                request_offset + rsp_msg_portion_length + rsp_msg_remainder_length) {
     183            0 :         return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     184              :     }
     185            8 :     slot_id = spdm_context->encap_context.req_slot_id;
     186            8 :     if ((spdm_response->header.param1 & SPDM_CERTIFICATE_RESPONSE_SLOT_ID_MASK) != slot_id) {
     187            0 :         return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     188              :     }
     189            8 :     if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
     190            6 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "cert_info - 0x%02x\n",
     191              :                        spdm_response->header.param2));
     192            6 :         cert_model = spdm_response->header.param2 &
     193              :                      SPDM_CERTIFICATE_RESPONSE_ATTRIBUTES_CERTIFICATE_INFO_MASK;
     194            6 :         if (spdm_context->connection_info.multi_key_conn_req) {
     195            5 :             if (cert_model > SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT) {
     196            0 :                 return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     197              :             }
     198            5 :             if ((slot_id == 0) &&
     199              :                 (cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT)) {
     200            1 :                 return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     201              :             }
     202            4 :             if ((cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) &&
     203            1 :                 (spdm_response->portion_length != 0)) {
     204            1 :                 return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     205              :             }
     206              :         } else {
     207            1 :             if (cert_model != SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) {
     208            0 :                 return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     209              :             }
     210              :         }
     211            4 :         if (spdm_context->connection_info.peer_cert_info[slot_id] ==
     212              :             SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) {
     213            4 :             spdm_context->connection_info.peer_cert_info[slot_id] = cert_model;
     214            0 :         } else if (spdm_context->connection_info.peer_cert_info[slot_id] != cert_model) {
     215            0 :             return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     216              :         }
     217              :     }
     218              : 
     219            6 :     if (spdm_response_size < rsp_msg_header_size + rsp_msg_portion_length) {
     220            0 :         return LIBSPDM_STATUS_INVALID_MSG_SIZE;
     221              :     }
     222            6 :     spdm_response_size = rsp_msg_header_size + rsp_msg_portion_length;
     223              : 
     224              :     /* Cache data*/
     225              : 
     226            6 :     status = libspdm_append_message_mut_b(spdm_context, spdm_response, spdm_response_size);
     227            6 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     228            0 :         return LIBSPDM_STATUS_BUFFER_FULL;
     229              :     }
     230              : 
     231            6 :     LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Certificate (offset 0x%x, size 0x%x):\n",
     232              :                    request_offset, rsp_msg_portion_length));
     233            6 :     LIBSPDM_INTERNAL_DUMP_HEX((const uint8_t *)spdm_response + rsp_msg_header_size,
     234              :                               rsp_msg_portion_length);
     235              : 
     236            6 :     if (cert_chain_buffer_size + rsp_msg_portion_length > cert_chain_buffer_max_size) {
     237            0 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "cert_chain_buffer full\n"));
     238            0 :         return LIBSPDM_STATUS_BUFFER_FULL;
     239              :     }
     240              : 
     241            6 :     libspdm_copy_mem(cert_chain_buffer + cert_chain_buffer_size,
     242              :                      cert_chain_buffer_max_size - cert_chain_buffer_size,
     243              :                      (const uint8_t *)spdm_response + rsp_msg_header_size,
     244              :                      rsp_msg_portion_length);
     245              : 
     246            6 :     cert_chain_buffer_size += rsp_msg_portion_length;
     247            6 :     spdm_context->mut_auth_cert_chain_buffer_size = cert_chain_buffer_size;
     248              : 
     249            6 :     if (rsp_msg_remainder_length != 0) {
     250            6 :         *need_continue = true;
     251              : 
     252            6 :         return LIBSPDM_STATUS_SUCCESS;
     253              :     }
     254              : 
     255            0 :     *need_continue = false;
     256              : 
     257            0 :     if (spdm_context->local_context.verify_peer_spdm_cert_chain != NULL) {
     258            0 :         result = spdm_context->local_context.verify_peer_spdm_cert_chain (
     259            0 :             spdm_context, spdm_context->encap_context.req_slot_id,
     260              :             cert_chain_buffer_size, cert_chain_buffer, NULL, NULL);
     261            0 :         if (!result) {
     262            0 :             return LIBSPDM_STATUS_VERIF_FAIL;
     263              :         }
     264              :     } else {
     265            0 :         result = libspdm_verify_peer_cert_chain_buffer_integrity(
     266              :             spdm_context, cert_chain_buffer, cert_chain_buffer_size);
     267            0 :         if (!result) {
     268            0 :             return LIBSPDM_STATUS_VERIF_FAIL;
     269              :         }
     270              : 
     271              :         /*verify peer cert chain authority*/
     272            0 :         result = libspdm_verify_peer_cert_chain_buffer_authority(
     273              :             spdm_context, cert_chain_buffer, cert_chain_buffer_size, NULL, NULL);
     274            0 :         if (!result) {
     275            0 :             status = LIBSPDM_STATUS_VERIF_NO_AUTHORITY;
     276              :         }
     277              :     }
     278              : 
     279            0 :     spdm_context->connection_info.peer_used_cert_chain_slot_id =
     280            0 :         spdm_context->encap_context.req_slot_id;
     281            0 :     slot_id = spdm_context->encap_context.req_slot_id;
     282            0 :     LIBSPDM_ASSERT(slot_id < SPDM_MAX_SLOT_COUNT);
     283              : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
     284              :     spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_size =
     285              :         cert_chain_buffer_size;
     286              : 
     287              :     libspdm_copy_mem(spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer,
     288              :                      sizeof(spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer),
     289              :                      cert_chain_buffer, cert_chain_buffer_size);
     290              : #else
     291            0 :     result = libspdm_hash_all(
     292              :         spdm_context->connection_info.algorithm.base_hash_algo,
     293              :         cert_chain_buffer, cert_chain_buffer_size,
     294            0 :         spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_hash);
     295            0 :     if (!result) {
     296            0 :         return LIBSPDM_STATUS_CRYPTO_ERROR;
     297              :     }
     298            0 :     spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_hash_size =
     299            0 :         libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
     300              : 
     301            0 :     if (spdm_context->connection_info.algorithm.req_pqc_asym_alg != 0) {
     302            0 :         result = libspdm_get_pqc_leaf_cert_public_key_from_cert_chain(
     303              :             spdm_context->connection_info.algorithm.base_hash_algo,
     304              :             spdm_context->connection_info.algorithm.req_pqc_asym_alg,
     305              :             cert_chain_buffer, cert_chain_buffer_size,
     306            0 :             &spdm_context->connection_info.peer_used_cert_chain[slot_id].leaf_cert_public_key);
     307              :     } else {
     308            0 :         result = libspdm_get_leaf_cert_public_key_from_cert_chain(
     309              :             spdm_context->connection_info.algorithm.base_hash_algo,
     310            0 :             spdm_context->connection_info.algorithm.req_base_asym_alg,
     311              :             cert_chain_buffer, cert_chain_buffer_size,
     312            0 :             &spdm_context->connection_info.peer_used_cert_chain[slot_id].leaf_cert_public_key);
     313              :     }
     314            0 :     if (!result) {
     315            0 :         return LIBSPDM_STATUS_INVALID_CERT;
     316              :     }
     317              : #endif
     318            0 :     if (status != LIBSPDM_STATUS_VERIF_NO_AUTHORITY) {
     319            0 :         return LIBSPDM_STATUS_SUCCESS;
     320              :     } else {
     321            0 :         return LIBSPDM_STATUS_VERIF_NO_AUTHORITY;
     322              :     }
     323              : }
     324              : 
     325              : #endif /* (LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP) && (...) */
        

Generated by: LCOV version 2.0-1