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: 57.6 % 165 95
Test Date: 2026-02-22 08:11:49 Functions: 100.0 % 2 2

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

Generated by: LCOV version 2.0-1