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(&parameter, 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,
+				       &parameter, &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(&parameter, 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,
+				  &parameter, &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(&param, 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,
+					  &param, &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 @@
 				  &parameter, &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);