LCOV - code coverage report
Current view: top level - os_stub/spdm_device_secret_lib_sample - set_cert.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 83.5 % 91 76
Test Date: 2026-07-05 09:06:49 Functions: 100.0 % 4 4

            Line data    Source code
       1              : /**
       2              :  *  Copyright Notice:
       3              :  *  Copyright 2024 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 <stdarg.h>
       8              : #include <stddef.h>
       9              : #include <setjmp.h>
      10              : #include <stdint.h>
      11              : #include <stdlib.h>
      12              : #include <stdio.h>
      13              : #include <assert.h>
      14              : #include <string.h>
      15              : 
      16              : #include <base.h>
      17              : #if defined(_WIN32) || (defined(__clang__) && (defined (LIBSPDM_CPU_AARCH64) || \
      18              :     defined(LIBSPDM_CPU_ARM)))
      19              : #else
      20              :     #include <fcntl.h>
      21              :     #include <unistd.h>
      22              :     #include <sys/stat.h>
      23              : #endif
      24              : #include "library/memlib.h"
      25              : #include "internal/libspdm_device_secret_lib.h"
      26              : #include "internal/libspdm_common_lib.h"
      27              : 
      28              : bool g_in_trusted_environment = false;
      29              : bool g_set_cert_is_busy = false;
      30              : 
      31              : #if LIBSPDM_ENABLE_CAPABILITY_SET_CERT_CAP
      32           12 : bool libspdm_is_in_trusted_environment(void *spdm_context)
      33              : {
      34           12 :     return g_in_trusted_environment;
      35              : }
      36              : 
      37           14 : static bool libspdm_write_certificate_to_nvm(
      38              :     void *spdm_context,
      39              :     uint8_t slot_id, const void * cert_chain,
      40              :     size_t cert_chain_size,
      41              :     uint32_t base_hash_algo, uint32_t base_asym_algo, uint32_t pqc_asym_algo,
      42              :     bool *need_reset, bool *is_busy)
      43              : {
      44           14 :     if (g_set_cert_is_busy) {
      45            1 :         *is_busy = true;
      46              : 
      47            1 :         return false;
      48              :     } else {
      49              :     #if defined(_WIN32) || (defined(__clang__) && (defined (LIBSPDM_CPU_AARCH64) || \
      50              :         defined(LIBSPDM_CPU_ARM)))
      51              :         FILE *fp_out;
      52              :     #else
      53              :         int64_t fp_out;
      54              :     #endif
      55              : 
      56           13 :         char file_name[] = "slot_id_0_cert_chain.der";
      57              :         /*change the file name, for example: slot_id_1_cert_chain.der*/
      58           13 :         file_name[8] = (char)(slot_id+'0');
      59              : 
      60              :         /*check the input parameter*/
      61           13 :         if ((cert_chain == NULL) ^ (cert_chain_size == 0) ) {
      62            0 :             return false;
      63              :         }
      64              : 
      65              :     #if defined(_WIN32) || (defined(__clang__) && (defined (LIBSPDM_CPU_AARCH64) || \
      66              :         defined(LIBSPDM_CPU_ARM)))
      67              :         if ((fp_out = fopen(file_name, "w+b")) == NULL) {
      68              :             printf("Unable to open file %s\n", file_name);
      69              :             return false;
      70              :         }
      71              : 
      72              :         if (cert_chain != NULL) {
      73              :             if ((fwrite(cert_chain, 1, cert_chain_size, fp_out)) != cert_chain_size) {
      74              :                 printf("Write output file error %s\n", file_name);
      75              :                 fclose(fp_out);
      76              :                 return false;
      77              :             }
      78              :         }
      79              : 
      80              :         fclose(fp_out);
      81              :     #else
      82           13 :         if (cert_chain != NULL) {
      83           12 :             if ((fp_out = open(file_name, O_WRONLY | O_CREAT, S_IRWXU)) == -1) {
      84            0 :                 printf("Unable to open file %s\n", file_name);
      85            0 :                 return false;
      86              :             }
      87              : 
      88           12 :             if ((write(fp_out, cert_chain, cert_chain_size)) != cert_chain_size) {
      89            0 :                 printf("Write output file error %s\n", file_name);
      90            0 :                 close(fp_out);
      91            0 :                 return false;
      92              :             }
      93              :         } else {
      94            1 :             if ((fp_out = open(file_name, O_WRONLY | O_TRUNC)) == -1) {
      95            0 :                 printf("Unable to open file %s\n", file_name);
      96            0 :                 return false;
      97              :             }
      98              :         }
      99              : 
     100           13 :         close(fp_out);
     101              :     #endif
     102              : 
     103           13 :         return true;
     104              :     }
     105              : }
     106              : 
     107            1 : uint32_t libspdm_get_cert_chain_slot_storage_size(
     108              :     void *spdm_context, uint8_t slot_id)
     109              : {
     110            1 :     return SPDM_MAX_CERTIFICATE_CHAIN_SIZE_14;
     111              : }
     112              : 
     113           15 : bool libspdm_update_local_cert_chain(
     114              :     void *spdm_context,
     115              :     uint8_t slot_id,
     116              :     uint32_t base_hash_algo,
     117              :     uint32_t base_asym_algo,
     118              :     uint32_t pqc_asym_algo,
     119              :     size_t hash_size,
     120              :     const void *old_cert_chain,
     121              :     size_t old_cert_chain_size,
     122              :     const void *cert_chain,
     123              :     size_t *cert_chain_size,
     124              :     uint8_t cert_model,
     125              :     bool *need_reset,
     126              :     bool *is_busy)
     127              : {
     128              :     libspdm_data_parameter_t parameter;
     129              :     libspdm_return_t status;
     130              :     size_t header_size;
     131              :     uint8_t *new_buffer;
     132              :     bool result;
     133              :     const uint8_t *new_chain_bytes;
     134              : 
     135           15 :     if (slot_id >= SPDM_MAX_SLOT_COUNT) {
     136            1 :         return false;
     137              :     }
     138              : 
     139           14 :     if (cert_chain != NULL) {
     140           13 :         result = libspdm_write_certificate_to_nvm(
     141              :             spdm_context,
     142              :             slot_id,
     143           13 :             (const uint8_t *)cert_chain + sizeof(spdm_cert_chain_t) + hash_size,
     144           13 :             *cert_chain_size - (sizeof(spdm_cert_chain_t) + hash_size),
     145              :             base_hash_algo,
     146              :             base_asym_algo,
     147              :             pqc_asym_algo,
     148              :             need_reset,
     149              :             is_busy);
     150              :     } else {
     151            1 :         result = libspdm_write_certificate_to_nvm(
     152              :             spdm_context,
     153              :             slot_id,
     154              :             NULL,
     155              :             0,
     156              :             base_hash_algo,
     157              :             base_asym_algo,
     158              :             pqc_asym_algo,
     159              :             need_reset,
     160              :             is_busy);
     161              :     }
     162              : 
     163           14 :     if (!result) {
     164            1 :         return result;
     165              :     }
     166              : 
     167           13 :     if (cert_chain == NULL || cert_chain_size == NULL || *cert_chain_size == 0) {
     168            1 :         new_buffer = NULL;
     169            1 :         goto set_cert;
     170              :     }
     171              : 
     172           12 :     header_size = sizeof(spdm_cert_chain_t) + hash_size;
     173           12 :     if (*cert_chain_size < header_size) {
     174            1 :         return false;
     175              :     }
     176              : 
     177           11 :     new_chain_bytes = (const uint8_t *)cert_chain;
     178              : 
     179           11 :     if (cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_DEVICE_CERT ||
     180              :         cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT) {
     181              :         /* Device/generic certificate model: replace the entire local chain.*/
     182              : 
     183            8 :         new_buffer = (uint8_t *)malloc(*cert_chain_size);
     184            8 :         if (new_buffer == NULL) {
     185            0 :             return false;
     186              :         }
     187              : 
     188            8 :         libspdm_copy_mem(new_buffer, *cert_chain_size,
     189              :                          new_chain_bytes, *cert_chain_size);
     190            3 :     } else if (cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_ALIAS_CERT) {
     191              :         /* Alias Cert Model, the new `cert_chain` shall contain a partial
     192              :          * certificate chain from the root CA to the Device Certificate CA.
     193              :          *
     194              :          * We need to update the old root CA to the Device Certificate CA
     195              :          * and leave the other certs as they are. Then update the hash and
     196              :          * the size.
     197              :          */
     198            2 :         const uint8_t *new_certs = new_chain_bytes + header_size;
     199            2 :         size_t new_certs_size = *cert_chain_size - header_size;
     200            2 :         const uint8_t *old_certs = (const uint8_t *)old_cert_chain + header_size;
     201            2 :         size_t old_certs_size = old_cert_chain_size - header_size;
     202            2 :         size_t old_offset = 0;
     203            2 :         int32_t cert_index = 0;
     204            2 :         size_t mutable_cert_offset = 0;
     205              :         spdm_cert_chain_t *new_cert_chain;
     206              :         const uint8_t *root_cert;
     207              :         size_t root_cert_len;
     208              : 
     209              :         /* First, find the offset of the Device Certificate CA in the old
     210              :          * certs. This should contain the Hardware identity OID.
     211              :          */
     212            6 :         while (old_offset < old_certs_size) {
     213            6 :             const uint8_t *cert = NULL;
     214            6 :             size_t cert_size = 0;
     215              : 
     216            6 :             if (!libspdm_x509_get_cert_from_cert_chain(
     217              :                     old_certs, old_certs_size, cert_index,
     218              :                     &cert, &cert_size)) {
     219            0 :                 return false;
     220              :             }
     221              : 
     222            6 :             mutable_cert_offset += cert_size;
     223              : 
     224            6 :             if (libspdm_contains_hardware_id_oid(cert, cert_size)) {
     225              :                 /* We found the Device Certificate CA */
     226            2 :                 break;
     227              :             }
     228              : 
     229            4 :             cert_index++;
     230              :         }
     231              : 
     232              :         /* Now Allocate enough memory for the new cert chain and the old
     233              :          * mutable certs
     234              :          */
     235            2 :         size_t new_cert_chain_size = (old_certs_size - mutable_cert_offset) + *cert_chain_size;
     236            2 :         new_buffer = (uint8_t *)malloc(new_cert_chain_size);
     237            2 :         if (new_buffer == NULL) {
     238            0 :             return false;
     239              :         }
     240              : 
     241              : 
     242              :         /* Copy the new immutable certificates */
     243            2 :         libspdm_copy_mem(new_buffer + header_size, new_cert_chain_size - header_size,
     244              :                          new_certs, new_certs_size);
     245              : 
     246              :         /* Copy the old mutable certificates */
     247            2 :         libspdm_copy_mem(new_buffer + header_size + new_certs_size, new_cert_chain_size - header_size - new_certs_size,
     248            2 :                          old_certs + mutable_cert_offset, old_certs_size - mutable_cert_offset);
     249              : 
     250              :         /* Update the size */
     251            2 :         *cert_chain_size = new_cert_chain_size;
     252              : 
     253            2 :         new_cert_chain = (spdm_cert_chain_t*)new_buffer;
     254            2 :         new_cert_chain->length = (uint32_t)new_cert_chain_size;
     255              : 
     256              :         /* Get Root Certificate*/
     257            2 :         status = libspdm_x509_get_cert_from_cert_chain(new_buffer + header_size, new_cert_chain_size - header_size, 0,
     258              :                                                        &root_cert,
     259              :                                                        &root_cert_len);
     260            2 :         if (!status) {
     261            0 :             free(new_buffer);
     262            0 :             return false;
     263              :         }
     264              : 
     265              :         /* Update the certificate hash */
     266            2 :         libspdm_hash_all(
     267              :             base_hash_algo,
     268              :             root_cert,
     269              :             root_cert_len,
     270              :             new_buffer + 4);
     271              :     } else {
     272            1 :         return false;
     273              :     }
     274              : 
     275           11 : set_cert:
     276              : 
     277           11 :     libspdm_zero_mem(&parameter, sizeof(parameter));
     278           11 :     parameter.location = LIBSPDM_DATA_LOCATION_LOCAL;
     279           11 :     parameter.additional_data[0] = slot_id;
     280           11 :     if (cert_chain_size == NULL) {
     281            1 :         status = libspdm_set_data(spdm_context, LIBSPDM_DATA_LOCAL_PUBLIC_CERT_CHAIN,
     282              :                                   &parameter, new_buffer, 0);
     283              :     } else {
     284           10 :         status = libspdm_set_data(spdm_context, LIBSPDM_DATA_LOCAL_PUBLIC_CERT_CHAIN,
     285              :                                   &parameter, new_buffer, *cert_chain_size);
     286              :     }
     287           11 :     if (status != LIBSPDM_STATUS_SUCCESS) {
     288            0 :         free(new_buffer);
     289            0 :         return false;
     290              :     }
     291              : 
     292              :     /* `old_cert_chain` can be freed at this point. We can't
     293              :      * free() the const version supplied to this function and
     294              :      * stored in libspdm, so implementations need to keep track
     295              :      * of the buffer manually, probably by storing it in
     296              :      * `app_context_data_ptr`.
     297              :      */
     298              : 
     299           11 :     return true;
     300              : }
     301              : #endif /* LIBSPDM_ENABLE_CAPABILITY_SET_CERT_CAP */
        

Generated by: LCOV version 2.0-1