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

Generated by: LCOV version 2.0-1