feat(app/device_assignment): add support for libspdm_get_certificate
In dev_assign_cmd_init_connection_main add support to do
libspdm_get_certificate. This retrivies device certificate in parts or
whole based on the size of device certificate and response buffer size.
As the device certificate is retrived, RMM does below steps
- Sets cache fields in DevCommExit for NS host to cache the device
response.
- Computes spdm_cert_chain hash based on the negotiated hash algorithm.
- Computes x509_cert_chain hash based on the PDEV hash algorithm.
- Once the certificate is completed retrived, RMM sets the hash of the
certificate in libspdm connection using custom set_data command
LIBSPDM_DATA_PEER_USED_CERT_CHAIN_HASH.
Set LIBSPDM_MAX_CERT_CHAIN_SIZE to 0 as RMM do not store certificate
chain in libspdm context.
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Signed-off-by: Mate Toth-Pal <mate.toth-pal@arm.com>
Change-Id: I56362c99c654178f4feb474fda031db2d9a74641
diff --git a/app/common/rmm_svc/src/app_services.c b/app/common/rmm_svc/src/app_services.c
index 40c911f..97df885 100644
--- a/app/common/rmm_svc/src/app_services.c
+++ b/app/common/rmm_svc/src/app_services.c
@@ -404,7 +404,6 @@
return 0;
}
-
static app_service_func service_functions[APP_SERVICE_COUNT] = {
[APP_SERVICE_PRINT] = app_service_print,
[APP_SERVICE_RANDOM] = app_service_get_random,
diff --git a/app/device_assignment/el0_app/spdm_requester/CMakeLists.txt b/app/device_assignment/el0_app/spdm_requester/CMakeLists.txt
index f101f2c..6207365 100644
--- a/app/device_assignment/el0_app/spdm_requester/CMakeLists.txt
+++ b/app/device_assignment/el0_app/spdm_requester/CMakeLists.txt
@@ -26,6 +26,7 @@
set(LIBSPDM_PATCH_FILES
"${LIBSPDM_PATCH_DIR}/0001-cryptlib_mbedtls-use-external-Mbed-TLS.patch"
"${LIBSPDM_PATCH_DIR}/0002-fix-libspdm_hmac_new-return-and-LIBSPDM_STATUS_CONST.patch"
+ "${LIBSPDM_PATCH_DIR}/0003-get_certificate-do-not-store-cert_chain-content.patch"
)
Git_Apply_Patches(${LIBSPDM_DIR} "${LIBSPDM_PATCH_FILES}")
diff --git a/app/device_assignment/el0_app/src/dev_assign_cmds.c b/app/device_assignment/el0_app/src/dev_assign_cmds.c
index 8927469..94f4101 100644
--- a/app/device_assignment/el0_app/src/dev_assign_cmds.c
+++ b/app/device_assignment/el0_app/src/dev_assign_cmds.c
@@ -45,9 +45,35 @@
return DEV_ASSIGN_STATUS_SUCCESS;
}
+static void init_connection_cleanup(struct dev_assign_info *info, bool scrub_cert_chain_hash)
+{
+ libspdm_data_parameter_t parameter;
+
+ info->spdm_cert_chain_algo = PSA_ALG_NONE;
+ info->spdm_cert_chain_len = 0U;
+
+ if (scrub_cert_chain_hash) {
+ /* Clean up the CERT_CHAIN_HASH in the context */
+ (void)memset(&info->spdm_cert_chain_digest, 0,
+ info->spdm_cert_chain_digest_length);
+
+ /* Clean up the CERT_CHAIN_HASH in the connection */
+ (void)memset(¶meter, 0, sizeof(parameter));
+ parameter.location = LIBSPDM_DATA_LOCATION_CONNECTION;
+ parameter.additional_data[0] = info->cert_slot_id;
+ (void)libspdm_set_data(info->libspdm_ctx,
+ LIBSPDM_DATA_PEER_USED_CERT_CHAIN_HASH,
+ ¶meter, &info->spdm_cert_chain_digest,
+ info->spdm_cert_chain_digest_length);
+ info->spdm_cert_chain_digest_length = 0;
+ }
+}
+
/* dev_assign_cmd_init_connection_main */
int dev_assign_cmd_init_connection_main(struct dev_assign_info *info)
{
+ size_t cert_chain_size;
+ libspdm_data_parameter_t parameter;
void *spdm_context = info->libspdm_ctx;
libspdm_return_t status;
@@ -73,6 +99,45 @@
return DEV_ASSIGN_STATUS_ERROR;
}
+ /*
+ * Get device certificate. The certificate is not kept in RMM instead
+ * RMM retrieves the certificates in parts and asks the NS Host to
+ * cache the certificate during retrieval. Due to this the buffer
+ * allocated to cache the certificate chain is not known to RMM. So set
+ * cert_chain_size to the max value limited by SPDM spec which is 64kb.
+ */
+ cert_chain_size = SPDM_MAX_CERTIFICATE_CHAIN_SIZE;
+ status = libspdm_get_certificate(spdm_context,
+ NULL, /* session_id */
+ info->cert_slot_id,
+ &cert_chain_size,
+ NULL /* cert_chain */);
+ if (status != LIBSPDM_STATUS_SUCCESS) {
+ init_connection_cleanup(info, false);
+ return DEV_ASSIGN_STATUS_ERROR;
+ }
+
+ /*
+ * Set libspdm data LIBSPDM_DATA_PEER_USED_CERT_CHAIN_HASH.
+ * As part of the certificate retrieval, RMM calculates the
+ * spdm_cert_chain digest based on the SPDM negotiated hash algorithm.
+ * This should be completed at this point and update the same to libspdm
+ * context.
+ */
+ assert(info->spdm_cert_chain_digest_length != 0U);
+ (void)memset(¶meter, 0, sizeof(parameter));
+ parameter.location = LIBSPDM_DATA_LOCATION_CONNECTION;
+ parameter.additional_data[0] = info->cert_slot_id;
+ status = libspdm_set_data(spdm_context,
+ LIBSPDM_DATA_PEER_USED_CERT_CHAIN_HASH,
+ ¶meter, &info->spdm_cert_chain_digest,
+ info->spdm_cert_chain_digest_length);
+
+ if (status != LIBSPDM_STATUS_SUCCESS) {
+ init_connection_cleanup(info, false);
+ return DEV_ASSIGN_STATUS_ERROR;
+ }
+
return (int)LIBSPDM_STATUS_SUCCESS;
}
@@ -88,5 +153,8 @@
*/
dev_assign_unset_pubkey(info);
+ /* Clean up the cma spdm connection state */
+ init_connection_cleanup(info, true);
+
return DEV_ASSIGN_STATUS_SUCCESS;
}
diff --git a/app/device_assignment/el0_app/src/dev_assign_el0_app.c b/app/device_assignment/el0_app/src/dev_assign_el0_app.c
index f862994..fcd8d7a 100644
--- a/app/device_assignment/el0_app/src/dev_assign_el0_app.c
+++ b/app/device_assignment/el0_app/src/dev_assign_el0_app.c
@@ -5,13 +5,30 @@
#include <app_common.h>
#include <debug.h>
+#include <dev_assign_helper.h>
#include <dev_assign_private.h>
#include <el0_app_helpers.h>
+#include <library/spdm_crypt_lib.h>
#include <mbedtls/memory_buffer_alloc.h>
#include <psa/crypto.h>
#include <psa/crypto_struct.h>
+#include <smc-rmi.h>
#include <string.h>
+static void copy_back_exit_args_to_shared(struct dev_assign_info *info)
+{
+ struct dev_comm_exit_shared *shared = (struct dev_comm_exit_shared *)info->shared_buf;
+
+ shared->rmi_dev_comm_exit = info->exit_args;
+ shared->cached_digest.len = info->cached_digest.len;
+
+ if (info->cached_digest.len != 0U) {
+ (void)memcpy(shared->cached_digest.value, info->cached_digest.value,
+ info->cached_digest.len);
+ info->cached_digest.len = 0;
+ }
+}
+
static libspdm_return_t spdm_send_message(void *spdm_context,
size_t request_size,
const void *request,
@@ -63,7 +80,7 @@
info->exit_args.req_len = request_size;
/* Copy back the exit args to shared buf */
- *(struct rmi_dev_comm_exit *)info->shared_buf = info->exit_args;
+ copy_back_exit_args_to_shared(info);
el0_app_yield();
@@ -141,6 +158,143 @@
return LIBSPDM_STATUS_SUCCESS;
}
+/*
+ * Set cache flags in DevCommExit and compute digest of cached data.
+ */
+static int dev_assign_dev_comm_set_cache(struct dev_assign_info *info, const void *cache_buf,
+ size_t cache_offset, size_t cache_len,
+ uint8_t cache_type, uint8_t hash_op_flags)
+{
+ uint8_t *hash_src;
+ const size_t digest_size = DEV_OBJ_DIGEST_MAX;
+ int rc;
+
+ assert(info->cached_digest.len == 0U);
+
+ hash_src = (uint8_t *)((unsigned long)cache_buf + cache_offset);
+ rc = dev_assign_hash_extend(info->psa_hash_algo, &info->psa_hash_op,
+ hash_op_flags, hash_src, cache_len,
+ info->cached_digest.value, digest_size,
+ &info->cached_digest.len);
+ if (rc != 0) {
+ return -1;
+ }
+
+ info->exit_args.flags |= RMI_DEV_COMM_EXIT_FLAGS_CACHE_RSP_BIT;
+ info->exit_args.cache_rsp_offset = cache_offset;
+ info->exit_args.cache_rsp_len = cache_len;
+ if (cache_type == CACHE_TYPE_CERT) {
+ info->exit_args.cache_obj_id = (unsigned char)RMI_DEV_COMM_OBJECT_CERTIFICATE;
+ }
+
+ return 0;
+}
+
+static psa_algorithm_t spdm_to_psa_hash_algo(uint32_t spdm_hash_algo)
+{
+ if (spdm_hash_algo ==
+ (uint32_t)SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_256) {
+ return PSA_ALG_SHA_256;
+ } else if (spdm_hash_algo ==
+ (uint32_t)SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_384) {
+ return PSA_ALG_SHA_384;
+ }
+
+ return PSA_ALG_NONE;
+}
+
+/* Cache spdm certificate response */
+static int cma_spdm_cache_certificate(struct dev_assign_info *info,
+ spdm_certificate_response_t *cert_rsp)
+{
+ size_t cache_offset, cache_len;
+ uint8_t hash_op_flags = 0;
+ uint8_t *hash_src;
+ int rc;
+
+ /* Start of certificate chain */
+ if (info->spdm_cert_chain_len == 0U) {
+ libspdm_return_t status;
+ libspdm_data_parameter_t param;
+ size_t cert_chain_offset;
+ uint32_t spdm_hash_algo = 0U;
+ size_t data_sz;
+ psa_algorithm_t spdm_cert_chain_algo;
+
+ (void)memset(¶m, 0, sizeof(libspdm_data_parameter_t));
+ param.location = LIBSPDM_DATA_LOCATION_CONNECTION;
+ data_sz = sizeof(uint32_t);
+ status = libspdm_get_data(info->libspdm_ctx,
+ LIBSPDM_DATA_BASE_HASH_ALGO,
+ ¶m, &spdm_hash_algo,
+ &data_sz);
+ if (status != LIBSPDM_STATUS_SUCCESS) {
+ return -1;
+ }
+
+ spdm_cert_chain_algo = spdm_to_psa_hash_algo(spdm_hash_algo);
+ if (spdm_cert_chain_algo == PSA_ALG_NONE) {
+ return -1;
+ }
+
+ /* Set SPDM cert_chain hash algo */
+ info->spdm_cert_chain_algo = spdm_cert_chain_algo;
+ hash_op_flags = HASH_OP_FLAG_SETUP;
+ info->spdm_cert_chain_hash_op = psa_hash_operation_init();
+ info->psa_hash_op = psa_hash_operation_init();
+
+ /*
+ * For the start of the certificate chain ignore the hash of
+ * root certificate included in the response buffer.
+ */
+ cert_chain_offset = sizeof(spdm_cert_chain_t) +
+ libspdm_get_hash_size(spdm_hash_algo);
+ cache_offset = sizeof(spdm_certificate_response_t) +
+ cert_chain_offset;
+ if (cert_chain_offset > cert_rsp->portion_length) {
+ return -1;
+ }
+ cache_len = cert_rsp->portion_length - cert_chain_offset;
+ } else {
+ cache_offset = sizeof(spdm_certificate_response_t);
+ cache_len = cert_rsp->portion_length;
+ }
+
+ hash_op_flags |= HASH_OP_FLAG_UPDATE;
+ if (cert_rsp->remainder_length == 0U) {
+ hash_op_flags |= HASH_OP_FLAG_FINISH;
+ }
+
+ /*
+ * Compute the hash for the entire spdm_certificate_response. This hash
+ * will be later used to set it in SPDM connection. It need to be set
+ * instead of letting libspdm calculate it, because the whole
+ * certificate chain is not stored in RMM memory.
+ */
+ hash_src = (uint8_t *)((unsigned long)cert_rsp +
+ sizeof(spdm_certificate_response_t));
+ rc = dev_assign_hash_extend(info->spdm_cert_chain_algo,
+ &info->spdm_cert_chain_hash_op, hash_op_flags,
+ hash_src, cert_rsp->portion_length,
+ info->spdm_cert_chain_digest,
+ sizeof(info->spdm_cert_chain_digest),
+ &info->spdm_cert_chain_digest_length);
+ if (rc != 0) {
+ return -1;
+ }
+
+ /*
+ * As certificate is received (in parts or whole) invoke cache callback
+ * to let NS Host to cache device certificate.
+ */
+ rc = dev_assign_dev_comm_set_cache(info, cert_rsp, cache_offset,
+ cache_len, (uint8_t)CACHE_TYPE_CERT, hash_op_flags);
+
+ info->spdm_cert_chain_len += cert_rsp->portion_length;
+
+ return rc;
+}
+
static libspdm_return_t
spdm_transport_decode_message(void *spdm_context, uint32_t **session_id,
bool *is_app_message, bool is_request_message,
@@ -148,14 +302,53 @@
void *transport_message,
size_t *message_size, void **message)
{
+
+ struct dev_assign_info *info;
+ spdm_message_header_t *spdm_hdr;
+
(void)spdm_context;
(void)is_app_message;
(void)is_request_message;
+ info = spdm_to_dev_assign_info(spdm_context);
*session_id = NULL;
*message_size = transport_message_size;
*message = transport_message;
+ if (transport_message_size < sizeof(spdm_message_header_t)) {
+ return LIBSPDM_STATUS_RECEIVE_FAIL;
+ }
+ spdm_hdr = (spdm_message_header_t *)*message;
+
+ /*
+ * Cache device objects like certificate, interface_report, measurements
+ * once the message is decrypted.
+ */
+ if (spdm_hdr->request_response_code == (uint8_t)SPDM_CERTIFICATE) {
+ int rc;
+ spdm_certificate_response_t *cert_rsp;
+
+ if (transport_message_size < sizeof(spdm_certificate_response_t)) {
+ return LIBSPDM_STATUS_RECEIVE_FAIL;
+ }
+ cert_rsp = (spdm_certificate_response_t *)spdm_hdr;
+
+ /* Make sure portion length is in bounds of the message size. */
+ if (cert_rsp->portion_length >
+ (transport_message_size - sizeof(spdm_certificate_response_t))) {
+ return LIBSPDM_STATUS_RECEIVE_FAIL;
+ }
+
+ rc = cma_spdm_cache_certificate(info, cert_rsp);
+ if (rc != 0) {
+ /* cppcheck-suppress misra-c2012-12.2 */
+ /* cppcheck-suppress misra-c2012-10.1 */
+ /* coverity[misra_c_2012_rule_10_1_violation:SUPPRESS] */
+ /* coverity[misra_c_2012_rule_12_2_violation:SUPPRESS] */
+ return LIBSPDM_STATUS_RECEIVE_FAIL;
+ }
+ }
+
return LIBSPDM_STATUS_SUCCESS;
}
@@ -203,6 +396,30 @@
/* Nothing to do */
}
+static bool cma_spdm_verify_cert_chain(void *spdm_context, uint8_t slot_id,
+ size_t cert_chain_size,
+ const void *cert_chain,
+ const void **trust_anchor,
+ size_t *trust_anchor_size)
+{
+ (void)spdm_context;
+ (void)slot_id;
+ (void)cert_chain_size;
+ (void)cert_chain;
+ (void)trust_anchor;
+ (void)trust_anchor_size;
+ assert(cert_chain == NULL);
+
+ /*
+ * The certificate is not stored by RMM, so this function is
+ * intentionally left empty.
+ *
+ * Certificate verification is the responsibility of the realm the
+ * device is assigned to.
+ */
+ return true;
+}
+
void dev_assign_unset_pubkey(struct dev_assign_info *info)
{
if ((info->key_sig_algo == RMI_SIGNATURE_ALGORITHM_ECDSA_P256) ||
@@ -336,6 +553,7 @@
PRIV_LIBSPDM_SCRATCH_BUF_SIZE);
info->libspdm_ctx = (void *)((uintptr_t)info->mbedtls_heap_buf +
PRIV_LIBSPDM_MBEDTLS_HEAP_SIZE);
+ info->cached_digest.len = 0U;
assert((uintptr_t)spdm_to_dev_assign_info(info->libspdm_ctx) == (uintptr_t)info);
@@ -357,6 +575,7 @@
info->rp_id = params->rp_id;
info->ide_sid = params->ide_sid;
}
+ info->spdm_cert_chain_digest_length = 0;
info->psa_hash_algo = rmi_to_psa_hash_algo(params->rmi_hash_algo);
@@ -495,6 +714,13 @@
¶meter, &data16, sizeof(data16));
assert(status == LIBSPDM_STATUS_SUCCESS);
+ /*
+ * RMM does not maintain full certificate chain. Register function
+ * handler to skip certificate verification.
+ */
+ libspdm_register_verify_spdm_cert_chain_func(spdm_ctx,
+ cma_spdm_verify_cert_chain);
+
/* Assign the shared_buf. This serves as a marker that init is done. */
info->shared_buf = (void *)params;
@@ -535,7 +761,7 @@
}
/* Copy back the exit args to shared buf */
- *(struct rmi_dev_comm_exit *)shared_buf = info->exit_args;
+ copy_back_exit_args_to_shared(info);
return ret;
}
diff --git a/app/device_assignment/el0_app/src/dev_assign_private.h b/app/device_assignment/el0_app/src/dev_assign_private.h
index a485c18..93c0dd0 100644
--- a/app/device_assignment/el0_app/src/dev_assign_private.h
+++ b/app/device_assignment/el0_app/src/dev_assign_private.h
@@ -225,6 +225,8 @@
PRIV_LIBSPDM_MBEDTLS_HEAP_SIZE + \
PRIV_LIBSPDM_CONTEXT_SIZE))
+#define CACHE_TYPE_CERT U(0x1)
+
struct dev_assign_info {
/* RMI device handle */
void *dev_handle;
@@ -259,12 +261,25 @@
/* ID of the SPDM session started by libspdm_start_session */
uint32_t session_id;
+ /* Temporarily store the calculated digest that needs to be cached */
+ struct dev_obj_digest cached_digest;
+
+ /* spdm_cert_chain digest details */
+ psa_hash_operation_t spdm_cert_chain_hash_op;
+ psa_algorithm_t spdm_cert_chain_algo;
+ uint8_t spdm_cert_chain_digest[64];
+ size_t spdm_cert_chain_digest_length;
+ size_t spdm_cert_chain_len;
+
/*
- * The PSA equivalent of the 'rmi_hash_algo'. This value is used by PSA
- * crypto calls to calculate hash of cached device objects.
+ * The PSA equivalent of the 'rmi_hash_algo'. Tnis value is used by PSA
+ * crypto calls to caclulate hash of cached device objects.
*/
psa_algorithm_t psa_hash_algo;
+ /* State of the hash operation for object referred by 'digest'*/
+ psa_hash_operation_t psa_hash_op;
+
void *send_recv_buffer;
void *scratch_buffer;
void *mbedtls_heap_buf;
diff --git a/app/device_assignment/rmm_stub/include/dev.h b/app/device_assignment/rmm_stub/include/dev.h
index e6516e7..b6ea4ff 100644
--- a/app/device_assignment/rmm_stub/include/dev.h
+++ b/app/device_assignment/rmm_stub/include/dev.h
@@ -9,6 +9,7 @@
#include <app_fw_structures.h>
#include <arch.h>
#include <arch_features.h>
+#include <dev_assign_structs.h>
#include <granule.h>
#include <sizes.h>
#include <smc-rmi.h>
@@ -86,6 +87,13 @@
*/
uint8_t rmi_hash_algo;
+ /*
+ * Digest of device certificate. This digest is calculated when RMM
+ * fetches device certificate. The content of the certificate is cached
+ * by NS host.
+ */
+ struct dev_obj_digest cert_digest;
+
/* Device communiction state */
unsigned int dev_comm_state;
diff --git a/app/device_assignment/rmm_stub/include/dev_assign_app.h b/app/device_assignment/rmm_stub/include/dev_assign_app.h
index 9714288..1e0c818 100644
--- a/app/device_assignment/rmm_stub/include/dev_assign_app.h
+++ b/app/device_assignment/rmm_stub/include/dev_assign_app.h
@@ -34,6 +34,8 @@
* app_data - Pointer to app_data_cfg. This is opaque to caller
* comm_enter_args - Entry arguments to app
* comm_exit_args - Exit arguments from app
+ * comm_digest_ptr - Pointer to the location where the calculated digest is to
+ * be copied. Should be NULL if no digest is expected.
* dev_cmd - Valid device communicate cmds.
*
* Note that when this function indicates that the app is yeilded
@@ -46,6 +48,7 @@
int dev_assign_dev_communicate(struct app_data_cfg *app_data,
struct rmi_dev_comm_enter *comm_enter_args,
struct rmi_dev_comm_exit *comm_exit_args,
+ struct dev_obj_digest *comm_digest_ptr,
int dev_cmd);
/*
diff --git a/app/device_assignment/rmm_stub/include/dev_assign_structs.h b/app/device_assignment/rmm_stub/include/dev_assign_structs.h
index e2c623e..33578a9 100644
--- a/app/device_assignment/rmm_stub/include/dev_assign_structs.h
+++ b/app/device_assignment/rmm_stub/include/dev_assign_structs.h
@@ -15,6 +15,8 @@
#define DEV_ASSIGN_STATUS_ERROR (-1)
#define DEV_ASSIGN_STATUS_COMM_BLOCKED (1)
+#define DEV_OBJ_DIGEST_MAX U(64)
+
/*
* App function for initialization. This needs to be invoked for every
* new instance of the app. App uses heap available via tpidrro_el0.
@@ -28,6 +30,16 @@
*/
#define DEVICE_ASSIGN_APP_FUNC_ID_INIT 1
+/*
+ * RMM maintains digest of device object if its cached by NS host. This device
+ * object could be device certificate or device measurement or device interface
+ * report
+ */
+struct dev_obj_digest {
+ uint8_t value[DEV_OBJ_DIGEST_MAX];
+ size_t len;
+};
+
struct dev_assign_params {
/* RMI device handle */
void *dev_handle;
@@ -50,6 +62,16 @@
};
/*
+ * The structure that dev_assign_dev_communicate can use to get data from app
+ * shared memory on return
+ */
+struct dev_comm_exit_shared {
+ struct rmi_dev_comm_exit rmi_dev_comm_exit;
+
+ struct dev_obj_digest cached_digest;
+};
+
+/*
* App functions for device communication. App uses heap available via tpidrro_el0.
* The function execution can yield and return back to RMM. In this case
* the return would be via APP_YIELD_CALL svc. Callers need to check
diff --git a/app/device_assignment/rmm_stub/src/dev_assign_app_stub.c b/app/device_assignment/rmm_stub/src/dev_assign_app_stub.c
index 4c021a2..80d9bac 100644
--- a/app/device_assignment/rmm_stub/src/dev_assign_app_stub.c
+++ b/app/device_assignment/rmm_stub/src/dev_assign_app_stub.c
@@ -50,11 +50,12 @@
int dev_assign_dev_communicate(struct app_data_cfg *app_data,
struct rmi_dev_comm_enter *comm_enter_args,
struct rmi_dev_comm_exit *comm_exit_args,
+ struct dev_obj_digest *comm_digest_ptr,
int dev_cmd)
{
int rc;
struct rmi_dev_comm_enter *shared;
- struct rmi_dev_comm_exit *shared_ret;
+ struct dev_comm_exit_shared *shared_ret;
assert((dev_cmd == DEVICE_ASSIGN_APP_FUNC_ID_RESUME) ||
(dev_cmd == DEVICE_ASSIGN_APP_FUNC_ID_CONNECT_INIT) ||
@@ -76,7 +77,19 @@
}
shared_ret = app_data->el2_shared_page;
- *comm_exit_args = *shared_ret;
+
+ *comm_exit_args = shared_ret->rmi_dev_comm_exit;
+
+ if (shared_ret->cached_digest.len != 0U) {
+ if (comm_digest_ptr == NULL) {
+ app_unmap_shared_page(app_data);
+ return DEV_ASSIGN_STATUS_ERROR;
+ }
+ (void)memcpy(comm_digest_ptr->value, shared_ret->cached_digest.value,
+ shared_ret->cached_digest.len);
+ comm_digest_ptr->len = shared_ret->cached_digest.len;
+ }
+
app_unmap_shared_page(app_data);
return rc;
diff --git a/configs/libspdm/0003-get_certificate-do-not-store-cert_chain-content.patch b/configs/libspdm/0003-get_certificate-do-not-store-cert_chain-content.patch
new file mode 100644
index 0000000..20955df
--- /dev/null
+++ b/configs/libspdm/0003-get_certificate-do-not-store-cert_chain-content.patch
@@ -0,0 +1,94 @@
+From f17d1146a0da174ebdd9299e4ca7057a38df19c0 Mon Sep 17 00:00:00 2001
+From: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+Date: Wed, 10 Jul 2024 11:17:08 +0100
+Subject: [PATCH 3/5] get_certificate: do not store cert_chain content
+
+Add support for NULL cert_chain argument to libspdm_try_get_certificate.
+
+Add LIBSPDM_DATA_PEER_USED_CERT_CHAIN_HASH to libspdm_set_data to
+set the spdm_cert_chain hash value.
+
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+---
+ include/library/spdm_common_lib.h | 1 +
+ .../spdm_common_lib/libspdm_com_context_data.c | 15 +++++++++++++++
+ .../libspdm_req_get_certificate.c | 7 ++++++-
+ 3 files changed, 22 insertions(+), 1 deletion(-)
+
+diff --git a/include/library/spdm_common_lib.h b/include/library/spdm_common_lib.h
+index 992cef24..a1fa8cc3 100644
+--- a/include/library/spdm_common_lib.h
++++ b/include/library/spdm_common_lib.h
+@@ -158,6 +158,7 @@ typedef enum {
+ LIBSPDM_DATA_MULTI_KEY_CONN_RSP,
+
+ LIBSPDM_DATA_TOTAL_KEY_PAIRS,
++ LIBSPDM_DATA_PEER_USED_CERT_CHAIN_HASH,
+
+ /* MAX */
+ LIBSPDM_DATA_MAX
+diff --git a/library/spdm_common_lib/libspdm_com_context_data.c b/library/spdm_common_lib/libspdm_com_context_data.c
+index 7476abfb..2307d192 100644
+--- a/library/spdm_common_lib/libspdm_com_context_data.c
++++ b/library/spdm_common_lib/libspdm_com_context_data.c
+@@ -611,6 +611,21 @@ libspdm_return_t libspdm_set_data(void *spdm_context, libspdm_data_type_t data_t
+ #endif /* LIBSPDM_CERT_PARSE_SUPPORT */
+ #endif /* LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT */
+ break;
++ case LIBSPDM_DATA_PEER_USED_CERT_CHAIN_HASH:
++ if (parameter->location != LIBSPDM_DATA_LOCATION_CONNECTION) {
++ return LIBSPDM_STATUS_INVALID_PARAMETER;
++ }
++ slot_id = parameter->additional_data[0];
++ if (slot_id >= SPDM_MAX_SLOT_COUNT) {
++ return LIBSPDM_STATUS_INVALID_PARAMETER;
++ }
++ context->connection_info.peer_used_cert_chain_slot_id = slot_id;
++ context->connection_info.peer_used_cert_chain[slot_id].buffer_hash_size =
++ data_size;
++ libspdm_copy_mem(context->connection_info.peer_used_cert_chain[slot_id].buffer_hash,
++ sizeof(context->connection_info.peer_used_cert_chain[slot_id].buffer_hash),
++ data, data_size);
++ break;
+ case LIBSPDM_DATA_PEER_PUBLIC_KEY:
+ if (parameter->location != LIBSPDM_DATA_LOCATION_LOCAL) {
+ return LIBSPDM_STATUS_INVALID_PARAMETER;
+diff --git a/library/spdm_requester_lib/libspdm_req_get_certificate.c b/library/spdm_requester_lib/libspdm_req_get_certificate.c
+index 07d9b8ad..3e8554a0 100644
+--- a/library/spdm_requester_lib/libspdm_req_get_certificate.c
++++ b/library/spdm_requester_lib/libspdm_req_get_certificate.c
+@@ -92,7 +92,6 @@ static libspdm_return_t libspdm_try_get_certificate(libspdm_context_t *spdm_cont
+ LIBSPDM_ASSERT(slot_id < SPDM_MAX_SLOT_COUNT);
+ LIBSPDM_ASSERT(cert_chain_size != NULL);
+ LIBSPDM_ASSERT(*cert_chain_size > 0);
+- LIBSPDM_ASSERT(cert_chain != NULL);
+
+ /* -=[Verify State Phase]=- */
+ if (!libspdm_is_capabilities_flag_supported(
+@@ -329,10 +328,12 @@ static libspdm_return_t libspdm_try_get_certificate(libspdm_context_t *spdm_cont
+ spdm_request->offset, spdm_response->portion_length));
+ LIBSPDM_INTERNAL_DUMP_HEX(spdm_response->cert_chain, spdm_response->portion_length);
+
++ if (cert_chain != NULL) {
+ libspdm_copy_mem((uint8_t *)cert_chain + cert_chain_size_internal,
+ cert_chain_capacity - cert_chain_size_internal,
+ spdm_response->cert_chain,
+ spdm_response->portion_length);
++ }
+
+ cert_chain_size_internal += spdm_response->portion_length;
+
+@@ -378,6 +379,10 @@ static libspdm_return_t libspdm_try_get_certificate(libspdm_context_t *spdm_cont
+ }
+ }
+
++ if (cert_chain == NULL) {
++ goto done;
++ }
++
+ spdm_context->connection_info.peer_used_cert_chain_slot_id = slot_id;
+ #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
+ spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_size =
+--
+2.34.1
+
diff --git a/runtime/rmi/pdev.c b/runtime/rmi/pdev.c
index a52bc20..00b001c 100644
--- a/runtime/rmi/pdev.c
+++ b/runtime/rmi/pdev.c
@@ -423,20 +423,27 @@
struct rmi_dev_comm_exit *exit_args)
{
int rc;
+ struct dev_obj_digest *comm_digest_ptr;
+
+ if (pd->rmi_state == RMI_PDEV_STATE_NEW) {
+ comm_digest_ptr = &pd->cert_digest;
+ } else {
+ comm_digest_ptr = NULL;
+ }
if (pd->dev_comm_state == DEV_COMM_ACTIVE) {
return dev_assign_dev_communicate(&pd->da_app_data, enter_args,
- exit_args, DEVICE_ASSIGN_APP_FUNC_ID_RESUME);
+ exit_args, comm_digest_ptr, DEVICE_ASSIGN_APP_FUNC_ID_RESUME);
}
switch (pd->rmi_state) {
case RMI_PDEV_STATE_NEW:
rc = dev_assign_dev_communicate(&pd->da_app_data, enter_args,
- exit_args, DEVICE_ASSIGN_APP_FUNC_ID_CONNECT_INIT);
+ exit_args, comm_digest_ptr, DEVICE_ASSIGN_APP_FUNC_ID_CONNECT_INIT);
break;
case RMI_PDEV_STATE_STOPPING:
rc = dev_assign_dev_communicate(&pd->da_app_data, enter_args,
- exit_args, DEVICE_ASSIGN_APP_FUNC_ID_STOP_CONNECTION);
+ exit_args, comm_digest_ptr, DEVICE_ASSIGN_APP_FUNC_ID_STOP_CONNECTION);
break;
default:
assert(false);