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.1 % 168 96
Test Date: 2025-12-21 08:10:27 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              :     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(
     137            2 :             spdm_context, spdm_response->header.param1);
     138            2 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     139            2 :             return status;
     140              :         }
     141           10 :     } else if (spdm_response->header.request_response_code != SPDM_CERTIFICATE) {
     142            0 :         return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     143              :     }
     144           10 :     use_large_cert_chain = spdm_context->encap_context.use_large_cert_chain;
     145           10 :     if (use_large_cert_chain) {
     146            0 :         if ((spdm_response->header.param1 & SPDM_CERTIFICATE_RESPONSE_LARGE_CERT_CHAIN) == 0) {
     147            0 :             return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     148              :         }
     149              :     } else {
     150           10 :         if ((spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_14) &&
     151            0 :             ((spdm_response->header.param1 & SPDM_CERTIFICATE_RESPONSE_LARGE_CERT_CHAIN) != 0)) {
     152            0 :             return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     153              :         }
     154              :     }
     155              : 
     156           10 :     if (use_large_cert_chain) {
     157            0 :         max_cert_chain_size = SPDM_MAX_CERTIFICATE_CHAIN_SIZE_14;
     158            0 :         rsp_msg_header_size = sizeof(spdm_certificate_large_response_t);
     159              :     } else {
     160           10 :         max_cert_chain_size = SPDM_MAX_CERTIFICATE_CHAIN_SIZE;
     161           10 :         rsp_msg_header_size = sizeof(spdm_certificate_response_t);
     162              :     }
     163              : 
     164              :     /* certificate response is encapsulate in deliver encapsulated response msg */
     165           10 :     req_msg_length = spdm_context->local_context.capability.max_spdm_msg_size -
     166           10 :                      sizeof(spdm_deliver_encapsulated_response_request_t) -
     167              :                      rsp_msg_header_size;
     168              : 
     169           10 :     if (!use_large_cert_chain) {
     170           10 :         req_msg_length = LIBSPDM_MIN(req_msg_length, SPDM_MAX_CERTIFICATE_CHAIN_SIZE);
     171              :     }
     172              : 
     173           10 :     if (encap_response_size < rsp_msg_header_size) {
     174            0 :         return LIBSPDM_STATUS_INVALID_MSG_SIZE;
     175              :     }
     176           10 :     if (use_large_cert_chain) {
     177            0 :         rsp_msg_portion_length = spdm_response->large_portion_length;
     178            0 :         rsp_msg_remainder_length = spdm_response->large_remainder_length;
     179              :     } else {
     180           10 :         rsp_msg_portion_length = spdm_response->portion_length;
     181           10 :         rsp_msg_remainder_length = spdm_response->remainder_length;
     182              :     }
     183              : 
     184           10 :     if ((rsp_msg_portion_length > req_msg_length) ||
     185              :         (rsp_msg_portion_length == 0)) {
     186            2 :         return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     187              :     }
     188              : 
     189            8 :     request_offset = (uint32_t)cert_chain_buffer_size;
     190              : 
     191            8 :     if (rsp_msg_portion_length > max_cert_chain_size - request_offset) {
     192            0 :         return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     193              :     }
     194            8 :     if (rsp_msg_remainder_length > max_cert_chain_size - request_offset - rsp_msg_portion_length) {
     195            0 :         return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     196              :     }
     197            8 :     if (request_offset == 0) {
     198            8 :         spdm_context->encap_context.cert_chain_total_len = rsp_msg_portion_length +
     199              :                                                            rsp_msg_remainder_length;
     200            0 :     } else if (spdm_context->encap_context.cert_chain_total_len !=
     201            0 :                request_offset + rsp_msg_portion_length + rsp_msg_remainder_length) {
     202            0 :         return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     203              :     }
     204            8 :     slot_id = spdm_context->encap_context.req_slot_id;
     205            8 :     if ((spdm_response->header.param1 & SPDM_CERTIFICATE_RESPONSE_SLOT_ID_MASK) != slot_id) {
     206            0 :         return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     207              :     }
     208            8 :     if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
     209            6 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "cert_info - 0x%02x\n",
     210              :                        spdm_response->header.param2));
     211            6 :         cert_model = spdm_response->header.param2 &
     212              :                      SPDM_CERTIFICATE_RESPONSE_ATTRIBUTES_CERTIFICATE_INFO_MASK;
     213            6 :         if (spdm_context->connection_info.multi_key_conn_req) {
     214            5 :             if (cert_model > SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT) {
     215            0 :                 return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     216              :             }
     217            5 :             if ((slot_id == 0) &&
     218              :                 (cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT)) {
     219            1 :                 return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     220              :             }
     221            4 :             if ((cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) &&
     222            1 :                 (spdm_response->portion_length != 0)) {
     223            1 :                 return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     224              :             }
     225              :         } else {
     226            1 :             if (cert_model != SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) {
     227            0 :                 return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     228              :             }
     229              :         }
     230            4 :         if (spdm_context->connection_info.peer_cert_info[slot_id] ==
     231              :             SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) {
     232            4 :             spdm_context->connection_info.peer_cert_info[slot_id] = cert_model;
     233            0 :         } else if (spdm_context->connection_info.peer_cert_info[slot_id] != cert_model) {
     234            0 :             return LIBSPDM_STATUS_INVALID_MSG_FIELD;
     235              :         }
     236              :     }
     237              : 
     238            6 :     if (spdm_response_size < rsp_msg_header_size + rsp_msg_portion_length) {
     239            0 :         return LIBSPDM_STATUS_INVALID_MSG_SIZE;
     240              :     }
     241            6 :     spdm_response_size = rsp_msg_header_size + rsp_msg_portion_length;
     242              : 
     243              :     /* Cache data*/
     244              : 
     245            6 :     status = libspdm_append_message_mut_b(spdm_context, spdm_response, spdm_response_size);
     246            6 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     247            0 :         return LIBSPDM_STATUS_BUFFER_FULL;
     248              :     }
     249              : 
     250            6 :     LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Certificate (offset 0x%x, size 0x%x):\n",
     251              :                    request_offset, rsp_msg_portion_length));
     252            6 :     LIBSPDM_INTERNAL_DUMP_HEX((const uint8_t *)spdm_response + rsp_msg_header_size,
     253              :                               rsp_msg_portion_length);
     254              : 
     255            6 :     if (cert_chain_buffer_size + rsp_msg_portion_length > cert_chain_buffer_max_size) {
     256            0 :         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "cert_chain_buffer full\n"));
     257            0 :         return LIBSPDM_STATUS_BUFFER_FULL;
     258              :     }
     259              : 
     260            6 :     libspdm_copy_mem(cert_chain_buffer + cert_chain_buffer_size,
     261              :                      cert_chain_buffer_max_size - cert_chain_buffer_size,
     262              :                      (const uint8_t *)spdm_response + rsp_msg_header_size,
     263              :                      rsp_msg_portion_length);
     264              : 
     265            6 :     cert_chain_buffer_size += rsp_msg_portion_length;
     266            6 :     spdm_context->mut_auth_cert_chain_buffer_size = cert_chain_buffer_size;
     267              : 
     268            6 :     if (rsp_msg_remainder_length != 0) {
     269            6 :         *need_continue = true;
     270              : 
     271            6 :         return LIBSPDM_STATUS_SUCCESS;
     272              :     }
     273              : 
     274            0 :     *need_continue = false;
     275              : 
     276            0 :     if (spdm_context->local_context.verify_peer_spdm_cert_chain != NULL) {
     277            0 :         result = spdm_context->local_context.verify_peer_spdm_cert_chain (
     278            0 :             spdm_context, spdm_context->encap_context.req_slot_id,
     279              :             cert_chain_buffer_size, cert_chain_buffer, NULL, NULL);
     280            0 :         if (!result) {
     281            0 :             return LIBSPDM_STATUS_VERIF_FAIL;
     282              :         }
     283              :     } else {
     284            0 :         result = libspdm_verify_peer_cert_chain_buffer_integrity(
     285              :             spdm_context, cert_chain_buffer, cert_chain_buffer_size);
     286            0 :         if (!result) {
     287            0 :             return LIBSPDM_STATUS_VERIF_FAIL;
     288              :         }
     289              : 
     290              :         /*verify peer cert chain authority*/
     291            0 :         result = libspdm_verify_peer_cert_chain_buffer_authority(
     292              :             spdm_context, cert_chain_buffer, cert_chain_buffer_size, NULL, NULL);
     293            0 :         if (!result) {
     294            0 :             status = LIBSPDM_STATUS_VERIF_NO_AUTHORITY;
     295              :         }
     296              :     }
     297              : 
     298            0 :     spdm_context->connection_info.peer_used_cert_chain_slot_id =
     299            0 :         spdm_context->encap_context.req_slot_id;
     300            0 :     slot_id = spdm_context->encap_context.req_slot_id;
     301            0 :     LIBSPDM_ASSERT(slot_id < SPDM_MAX_SLOT_COUNT);
     302              : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
     303              :     spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_size =
     304              :         cert_chain_buffer_size;
     305              : 
     306              :     libspdm_copy_mem(spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer,
     307              :                      sizeof(spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer),
     308              :                      cert_chain_buffer, cert_chain_buffer_size);
     309              : #else
     310            0 :     result = libspdm_hash_all(
     311              :         spdm_context->connection_info.algorithm.base_hash_algo,
     312              :         cert_chain_buffer, cert_chain_buffer_size,
     313            0 :         spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_hash);
     314            0 :     if (!result) {
     315            0 :         return LIBSPDM_STATUS_CRYPTO_ERROR;
     316              :     }
     317            0 :     spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_hash_size =
     318            0 :         libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
     319              : 
     320            0 :     if (spdm_context->connection_info.algorithm.req_pqc_asym_alg != 0) {
     321            0 :         result = libspdm_get_pqc_leaf_cert_public_key_from_cert_chain(
     322              :             spdm_context->connection_info.algorithm.base_hash_algo,
     323              :             spdm_context->connection_info.algorithm.req_pqc_asym_alg,
     324              :             cert_chain_buffer, cert_chain_buffer_size,
     325            0 :             &spdm_context->connection_info.peer_used_cert_chain[slot_id].leaf_cert_public_key);
     326              :     } else {
     327            0 :         result = libspdm_get_leaf_cert_public_key_from_cert_chain(
     328              :             spdm_context->connection_info.algorithm.base_hash_algo,
     329            0 :             spdm_context->connection_info.algorithm.req_base_asym_alg,
     330              :             cert_chain_buffer, cert_chain_buffer_size,
     331            0 :             &spdm_context->connection_info.peer_used_cert_chain[slot_id].leaf_cert_public_key);
     332              :     }
     333            0 :     if (!result) {
     334            0 :         return LIBSPDM_STATUS_INVALID_CERT;
     335              :     }
     336              : #endif
     337            0 :     if (status != LIBSPDM_STATUS_VERIF_NO_AUTHORITY) {
     338            0 :         return LIBSPDM_STATUS_SUCCESS;
     339              :     } else {
     340            0 :         return LIBSPDM_STATUS_VERIF_NO_AUTHORITY;
     341              :     }
     342              : }
     343              : 
     344              : #endif /* (LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP) && (...) */
        

Generated by: LCOV version 2.0-1