TF-RMM Release v0.1.0

This is the first external release of TF-RMM and provides a reference
implementation of Realm Management Monitor (RMM) as specified by the
RMM Beta0 specification[1].

The `docs/readme.rst` has more details about the project and
`docs/getting_started/getting-started.rst` has details on how to get
started with TF-RMM.

[1] https://developer.arm.com/documentation/den0137/1-0bet0/?lang=en

Signed-off-by: Soby Mathew <soby.mathew@arm.com>
Change-Id: I205ef14c015e4a37ae9ae1a64e4cd22eb8da746e
diff --git a/lib/attestation/src/attestation_defs_priv.h b/lib/attestation/src/attestation_defs_priv.h
new file mode 100644
index 0000000..0295bd9
--- /dev/null
+++ b/lib/attestation/src/attestation_defs_priv.h
@@ -0,0 +1,26 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+/*
+ * TODO: Include a reference the RMM spec once the attestation
+ * token spec is included on the former.
+ */
+
+#ifndef ATTESTATION_DEFS_PRIV_H
+#define ATTESTATION_DEFS_PRIV_H
+
+#define CCA_REALM_CHALLENGE			(10)
+#define CCA_REALM_PERSONALIZATION_VALUE		(44235)
+#define CCA_REALM_HASH_ALGM_ID			(44236)
+#define CCA_REALM_PUB_KEY			(44237)
+#define CCA_REALM_INITIAL_MEASUREMENT		(44238)
+#define CCA_REALM_EXTENSIBLE_MEASUREMENTS	(44239)
+#define CCA_REALM_PUB_KEY_HASH_ALGO_ID		(44240)
+
+#define TAG_CCA_TOKEN				(399)
+#define CCA_PLAT_TOKEN				(44234)
+#define CCA_REALM_DELEGATED_TOKEN		(44241)
+
+#endif /* ATTESTATION_DEFS_PRIV_H */
diff --git a/lib/attestation/src/attestation_key.c b/lib/attestation/src/attestation_key.c
new file mode 100644
index 0000000..0ad9dd5
--- /dev/null
+++ b/lib/attestation/src/attestation_key.c
@@ -0,0 +1,278 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+#include <assert.h>
+#include <attestation.h>
+#include <attestation_priv.h>
+#include <debug.h>
+#include <errno.h>
+#include <fpu_helpers.h>
+#include <mbedtls/sha256.h>
+#include <measurement.h>
+#include <psa/crypto.h>
+#include <rmm_el3_ifc.h>
+#include <sizes.h>
+
+#define ECC_P384_PUBLIC_KEY_SIZE	(97U)
+#define SHA256_DIGEST_SIZE		(32U)
+
+/*
+ * The size of X and Y coordinate in 2 parameter style EC public key. Format is
+ * as defined in [COSE (RFC 8152)] (https://tools.ietf.org/html/rfc8152) and
+ * [SEC 1: Elliptic Curve Cryptography](http://www.secg.org/sec1-v2.pdf).
+ *
+ * This size is well-known and documented in public standards.
+ */
+#define ECC_P384_COORD_SIZE		(48U) /* 384 bits -> 48 bytes */
+#define BIT_SIZE_OF_P384		(384U)
+
+/* ECC Curve type define for querying attestation key from monitor */
+#define ATTEST_KEY_CURVE_ECC_SECP384R1	0
+
+/*
+ * The platform token which will be needed during attestation.
+ */
+static unsigned char rmm_platform_token_buf[SZ_4K];
+static struct q_useful_buf rmm_platform_token;
+
+/*
+ * The public key is kept loaded as it is both not required to be secret (and
+ * hence can be kept in attestation memory) and immutable.
+ */
+static uint8_t realm_attest_public_key[ECC_P384_PUBLIC_KEY_SIZE];
+static size_t realm_attest_public_key_len;
+
+/*
+ * The hash of the realm attestation public key is included in the Platform
+ * attestation token as the challenge claim.
+ */
+static uint8_t realm_attest_public_key_hash[SHA256_DIGEST_SIZE];
+static size_t realm_attest_public_key_hash_len;
+
+/*
+ * The keypair for the sign operation
+ */
+static mbedtls_ecp_keypair realm_attest_keypair = {0};
+
+/* Specify the hash algorithm to use for computing the hash of the
+ * realm public key.
+ */
+static enum hash_algo public_key_hash_algo_id = HASH_ALGO_SHA256;
+
+/*
+ * TODO: review panic usage and try to gracefully exit on error. Also
+ * improve documentation of usage of MbedTLS APIs
+ */
+int attest_init_realm_attestation_key(void)
+{
+	int ret;
+	struct q_useful_buf realm_attest_private_key;
+	uintptr_t buf;
+	size_t attest_key_size = 0UL;
+
+	struct attest_rng_context rng_ctx;
+
+	assert(IS_FPU_ALLOWED());
+
+	attest_get_cpu_rng_context(&rng_ctx);
+
+	/*
+	 * The realm attestation key is requested from the root world in the
+	 * boot phase only once. Then the same key is used in the entire power
+	 * cycle to sign the realm attestation tokens.
+	 */
+	if (realm_attest_keypair.MBEDTLS_PRIVATE(d).MBEDTLS_PRIVATE(p) != NULL) {
+		ERROR("Realm attestation key already loaded.\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Get the realm attestation key. The key is retrieved in raw format.
+	 */
+	buf = rmm_el3_ifc_get_shared_buf_locked();
+
+	if (rmm_el3_ifc_get_realm_attest_key(buf,
+				rmm_el3_ifc_get_shared_buf_size(),
+				&attest_key_size,
+				ATTEST_KEY_CURVE_ECC_SECP384R1) != 0) {
+		rmm_el3_ifc_release_shared_buf();
+		return -EINVAL;
+	}
+
+	realm_attest_private_key.len = attest_key_size;
+	realm_attest_private_key.ptr = (void *)buf;
+
+	/*
+	 * Setup ECC key.
+	 * The memory for the keypair is allocated from MbedTLS Heap.
+	 */
+	mbedtls_ecp_keypair_init(&realm_attest_keypair);
+	ret = mbedtls_ecp_group_load(&realm_attest_keypair.MBEDTLS_PRIVATE(grp),
+				     MBEDTLS_ECP_DP_SECP384R1);
+	if (ret != 0) {
+		ERROR("mbedtls_ecp_group_load has failed\n");
+		rmm_el3_ifc_release_shared_buf();
+		return -EINVAL;
+	}
+
+	ret = mbedtls_mpi_read_binary(&realm_attest_keypair.MBEDTLS_PRIVATE(d),
+				      realm_attest_private_key.ptr,
+				      realm_attest_private_key.len);
+	if (ret != 0) {
+		ERROR("mbedtls_mpi_read_binary has failed\n");
+		rmm_el3_ifc_release_shared_buf();
+		return -EINVAL;
+	}
+
+	ret = mbedtls_ecp_check_privkey(&realm_attest_keypair.MBEDTLS_PRIVATE(grp),
+					&realm_attest_keypair.MBEDTLS_PRIVATE(d));
+	if (ret != 0) {
+		ERROR("mbedtls_ecp_check_privkey has failed: %d\n", ret);
+		rmm_el3_ifc_release_shared_buf();
+		return -EINVAL;
+	}
+
+	ret = mbedtls_ecp_mul(&realm_attest_keypair.MBEDTLS_PRIVATE(grp),
+			      &realm_attest_keypair.MBEDTLS_PRIVATE(Q),
+			      &realm_attest_keypair.MBEDTLS_PRIVATE(d),
+			      &realm_attest_keypair.MBEDTLS_PRIVATE(grp).G,
+			      rng_ctx.f_rng,
+			      rng_ctx.p_rng);
+	if (ret != 0) {
+		ERROR("mbedtls_ecp_mul priv has failed: %d\n", ret);
+		rmm_el3_ifc_release_shared_buf();
+		return -EINVAL;
+	}
+
+	ret = mbedtls_ecp_point_write_binary(&realm_attest_keypair.MBEDTLS_PRIVATE(grp),
+					     &realm_attest_keypair.MBEDTLS_PRIVATE(Q),
+					     MBEDTLS_ECP_PF_UNCOMPRESSED,
+					     &realm_attest_public_key_len,
+					     realm_attest_public_key,
+					     sizeof(realm_attest_public_key));
+	if (ret != 0) {
+		ERROR("mbedtls_ecp_point_write_binary pub has failed\n");
+		rmm_el3_ifc_release_shared_buf();
+		return -EINVAL;
+	}
+
+	/* Compute the hash of the realm attestation public key */
+	ret = mbedtls_sha256(realm_attest_public_key,
+			     realm_attest_public_key_len,
+			     realm_attest_public_key_hash,
+			     false);
+	if (ret != 0) {
+		ERROR("mbedtls_sha256 has failed\n");
+		rmm_el3_ifc_release_shared_buf();
+		return -EINVAL;
+	}
+
+	realm_attest_public_key_hash_len = sizeof(realm_attest_public_key_hash);
+
+	/* Clear the private key from the buffer */
+	(void)memset(realm_attest_private_key.ptr, 0,
+			realm_attest_private_key.len);
+
+	rmm_el3_ifc_release_shared_buf();
+
+	return 0;
+}
+
+int attest_get_realm_signing_key(const void **keypair)
+{
+	if (realm_attest_keypair.MBEDTLS_PRIVATE(d).MBEDTLS_PRIVATE(p) == NULL) {
+		ERROR("Realm attestation key not initialized\n");
+		return -EINVAL;
+	}
+
+	*keypair = &realm_attest_keypair;
+	return 0;
+}
+
+int attest_get_realm_public_key_hash(struct q_useful_buf_c *public_key_hash)
+{
+	if (realm_attest_keypair.MBEDTLS_PRIVATE(d).MBEDTLS_PRIVATE(p) == NULL) {
+		ERROR("Realm attestation key not initialized\n");
+		return -EINVAL;
+	}
+
+	public_key_hash->ptr = realm_attest_public_key_hash;
+	public_key_hash->len = realm_attest_public_key_hash_len;
+	return 0;
+}
+
+int attest_get_realm_public_key(struct q_useful_buf_c *public_key)
+{
+	if (realm_attest_keypair.MBEDTLS_PRIVATE(d).MBEDTLS_PRIVATE(p) == NULL) {
+		ERROR("Realm attestation key not initialized\n");
+		return -EINVAL;
+	}
+
+	public_key->ptr = realm_attest_public_key;
+	public_key->len = realm_attest_public_key_len;
+	return 0;
+}
+
+int attest_setup_platform_token(void)
+{
+	int ret;
+	uintptr_t shared_buf;
+	size_t platform_token_len = 0;
+	struct q_useful_buf_c rmm_pub_key_hash;
+
+	/*
+	 * Copy the RAK public hash value to the token buffer. This is
+	 * used as the challenge input for the token generation
+	 * thus creating a binding between the two.
+	 */
+	ret = attest_get_realm_public_key_hash(&rmm_pub_key_hash);
+	if (ret != 0) {
+		ERROR("Realm attestation key not initialized\n");
+		return ret;
+	}
+
+	shared_buf = rmm_el3_ifc_get_shared_buf_locked();
+
+	(void)memcpy((void *)shared_buf, rmm_pub_key_hash.ptr,
+					 rmm_pub_key_hash.len);
+
+	ret = rmm_el3_ifc_get_platform_token(shared_buf,
+					     rmm_el3_ifc_get_shared_buf_size(),
+					     &platform_token_len,
+					     SHA256_DIGEST_SIZE);
+
+	if (ret != 0) {
+		rmm_el3_ifc_release_shared_buf();
+		return -EINVAL;
+	}
+
+	(void)memcpy(rmm_platform_token_buf,
+		     (void *)shared_buf,
+		     platform_token_len);
+
+	rmm_el3_ifc_release_shared_buf();
+
+	rmm_platform_token.ptr = rmm_platform_token_buf;
+	rmm_platform_token.len = platform_token_len;
+
+	return 0;
+}
+
+int attest_get_platform_token(struct q_useful_buf_c **buf)
+{
+	assert(buf != NULL);
+
+	if (rmm_platform_token.ptr == NULL) {
+		return -EINVAL;
+	}
+
+	*buf = (struct q_useful_buf_c *)&rmm_platform_token;
+	return 0;
+}
+
+enum hash_algo attest_get_realm_public_key_hash_algo_id(void)
+{
+	return public_key_hash_algo_id;
+}
diff --git a/lib/attestation/src/attestation_priv.h b/lib/attestation/src/attestation_priv.h
new file mode 100644
index 0000000..852381b
--- /dev/null
+++ b/lib/attestation/src/attestation_priv.h
@@ -0,0 +1,99 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+#ifndef ATTESTATION_PRIV_H
+#define ATTESTATION_PRIV_H
+
+/*
+ * A structure holding the context for generating a pseudo-random number derived
+ * from a real random seed.
+ */
+struct attest_rng_context {
+	int (*f_rng)(void *p_rng, unsigned char *output, size_t out_len);
+	void *p_rng;
+};
+
+/*
+ * Copy the rng_ctx for the current CPU to rng_ctx
+ *
+ * Arguments:
+ * rng_ctx - Pointer to the target context structure
+ */
+void attest_get_cpu_rng_context(struct attest_rng_context *rng_ctx);
+
+/*
+ * Get a pointer to the keypair for signing realm attestation token.
+ *
+ * Arguments:
+ * keypair - Pointer to the keypair for signing token.
+
+ * Returns 0 on success, negative error code on error.
+ */
+int attest_get_realm_signing_key(const void **keypair);
+
+/*
+ * Query the attestation private key from monitor and generate the public
+ * key by using MbedCryto lib. The key is cached internally for future
+ * use. The function returns early if the key has been initialized.
+ *
+ * FPU context must be saved and FPU access should be enabled by caller.
+ *
+ * Returns 0 on success, negative error code on error.
+ */
+int attest_init_realm_attestation_key(void);
+
+/*
+ * Get the hash of the realm attestation public key. The public key hash is the
+ * challenge value in the platform attestation token.
+ *
+ * Arguments:
+ * public_key_hash - Get the buffer address and size which holds
+ *                   the hash of the realm attestation public key.
+ *
+ * Returns 0 on success, negative error code on error.
+ *
+ */
+int attest_get_realm_public_key_hash(struct q_useful_buf_c *public_key_hash);
+
+/*
+ * Get the realm attestation public key hash. The public key hash is the
+ * challenge value in the platform attestation token.
+ *
+ * Arguments:
+ * public_key - Get the buffer address and size which holds the realm
+ *              attestation public key.
+ *
+ * Returns 0 on success, negative error code on error.
+ */
+int attest_get_realm_public_key(struct q_useful_buf_c *public_key);
+
+/*
+ * Get the platform token from monitor. This function needs to be called
+ * after the Realm attestation key has been initialized.
+ *
+ * Returns 0 on success, negative error code on error.
+ */
+int attest_setup_platform_token(void);
+
+/*
+ * Get the hash algorithm to use for computing the hash of the realm public key.
+ */
+enum hash_algo attest_get_realm_public_key_hash_algo_id(void);
+
+/*
+ * Initialise PRNGs for all the CPUs
+ *
+ * FPU context must be saved and FPU access should be enabled by caller.
+ *
+ * Returns 0 on success, negative error code otherwise.
+ *
+ * This function creates a separate PRNG object for all the CPUs. The PRNGs are
+ * used by Mbed TLS when it needs random data. The PRNGs are seeded with values
+ * generated by a temporary PRNG, which is in turn is seeded with a real random
+ * value.
+ */
+int attest_rnd_prng_init(void);
+
+#endif /* ATTESTATION_PRIV_H */
diff --git a/lib/attestation/src/attestation_rnd.c b/lib/attestation/src/attestation_rnd.c
new file mode 100644
index 0000000..bd2a9a5
--- /dev/null
+++ b/lib/attestation/src/attestation_rnd.c
@@ -0,0 +1,153 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+#include <arch_features.h>
+#include <assert.h>
+#include <attestation.h>
+#include <attestation_priv.h>
+#include <cpuid.h>
+#include <entropy.h>
+#include <errno.h>
+#include <fpu_helpers.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/hmac_drbg.h>
+#include <platform_api.h>
+#include <stdbool.h>
+#include <utils_def.h>
+
+/*
+ * Allocate a PRNG object per PE in order to avoid the necessity of locking if
+ * concurrent attestation token requests are executed.
+ */
+static mbedtls_hmac_drbg_context cpu_drbg_ctx[MAX_CPUS];
+static bool prng_init_done;
+
+static int get_random_seed(unsigned char *output, size_t len)
+{
+	bool rc;
+	uint64_t *random_output;
+	uint64_t *random_end;
+
+	assert(!prng_init_done);
+
+	/* Enforce `len` is a multiple of 8 and `output` is 8-byte aligned. */
+	assert((len & 0x7UL) == 0UL && ((uintptr_t)output & 0x7UL) == 0UL);
+
+	random_output = (uint64_t *)output;
+	random_end = (uint64_t *)(output + len);
+
+	for (; random_output < random_end; ++random_output) {
+		rc = arch_collect_entropy(random_output);
+		if (!rc) {
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+/*
+ * This function is used by Mbed TLS as a source of entropy. This means it is
+ * called during RMM operation, to add entropy to the signing process.
+ * See declaration in mbedtls/entropy_poll.h.
+ * For details see `MBEDTLS_ENTROPY_HARDWARE_ALT` in mbedtls/config.h
+ */
+int mbedtls_hardware_poll(void  *data, unsigned char *output,
+			  size_t len,  size_t        *olen)
+{
+	int ret;
+	unsigned int cpu_id = my_cpuid();
+	void *rng_ctx;
+
+	assert(prng_init_done);
+
+	(void)data;
+
+	/* Not in RMM init, PRNGs are already initialized, use them. */
+	rng_ctx = &cpu_drbg_ctx[cpu_id];
+	ret = mbedtls_hmac_drbg_random(rng_ctx, output, len);
+	if (ret != 0) {
+		return ret;
+	}
+	*olen = len;
+
+	return 0;
+}
+
+void attest_get_cpu_rng_context(struct attest_rng_context *rng_ctx)
+{
+	unsigned int cpu_id = my_cpuid();
+
+	assert(prng_init_done);
+
+	rng_ctx->f_rng = mbedtls_hmac_drbg_random;
+	rng_ctx->p_rng = &cpu_drbg_ctx[cpu_id];
+}
+
+int attest_rnd_prng_init(void)
+{
+	const mbedtls_md_info_t *md_info;
+	mbedtls_hmac_drbg_context drbg_ctx;
+	uint8_t seed[128] __aligned(8) ; /* mbedtls_hardware_poll request this size */
+	unsigned int i;
+	int rc;
+	int retval = 0;
+
+	assert(!prng_init_done);
+	assert(IS_FPU_ALLOWED());
+
+	if (!is_feat_rng_present()) {
+		return -EINVAL;
+	}
+
+	/*
+	 * Setup a temporary PRNG which seeded by real TRNG and use this
+	 * instance to set up the per CPU PRNG objects. The temporary PRNG
+	 * relies on the RNDR instruction to get its seed. RNDR instruction has
+	 * an implementation defined TRNG backend. The timing of the TRNG could
+	 * be nondeterministic therefore access to it is kept on the minimum.
+	 */
+	rc = get_random_seed(seed, sizeof(seed));
+	if (rc != 0) {
+		return -EINVAL;
+	}
+
+	md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
+	mbedtls_hmac_drbg_init(&drbg_ctx);
+	rc = mbedtls_hmac_drbg_seed_buf(&drbg_ctx,
+				    md_info,
+				    seed, sizeof(seed));
+	if (rc != 0) {
+		retval = -EINVAL;
+		goto free_temp_prng;
+	}
+
+	/*
+	 * Set up the per CPU PRNG objects which going to be used during
+	 * Elliptic Curve signing to blind the private key.
+	 */
+	for (i = 0U; i < MAX_CPUS; ++i) {
+		rc = mbedtls_hmac_drbg_random(&drbg_ctx, seed, sizeof(seed));
+		if (rc != 0) {
+			retval = -EINVAL;
+			goto free_temp_prng;
+		}
+
+		mbedtls_hmac_drbg_init(&cpu_drbg_ctx[i]);
+		rc = mbedtls_hmac_drbg_seed_buf(&cpu_drbg_ctx[i], md_info,
+						seed, sizeof(seed));
+		if (rc != 0) {
+			retval = -EINVAL;
+			goto free_temp_prng;
+		}
+	}
+
+	prng_init_done = true;
+
+free_temp_prng:
+	/* Free the memory allocated by the temporary PRNG */
+	mbedtls_hmac_drbg_free(&drbg_ctx);
+
+	return retval;
+}
diff --git a/lib/attestation/src/attestation_token.c b/lib/attestation/src/attestation_token.c
new file mode 100644
index 0000000..ba6ad56
--- /dev/null
+++ b/lib/attestation/src/attestation_token.c
@@ -0,0 +1,329 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright Laurence Lundblade.
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+/*
+ * This file is derived from:
+ *    trusted-firmware-m/secure_fw/partitions/initial_attestation/attest_token_encode.c
+ */
+
+#include <assert.h>
+#include <attestation.h>
+#include <attestation_defs_priv.h>
+#include <attestation_priv.h>
+#include <attestation_token.h>
+#include <debug.h>
+#include <fpu_helpers.h>
+#include <measurement.h>
+#include <qcbor/qcbor.h>
+#include <t_cose/q_useful_buf.h>
+#include <t_cose/t_cose_common.h>
+#include <t_cose/t_cose_sign1_sign.h>
+#include <utils_def.h>
+
+/*
+ * According to IANA hash algorithm registry:
+ *   - https://www.iana.org/assignments/hash-function-text-names/hash-function-text-names.xml
+ */
+static void attest_get_hash_algo_text(enum hash_algo  algo_id,
+				      struct q_useful_buf_c *algo_text)
+{
+	const char *sha256 = "sha-256";
+	const char *sha512 = "sha-512";
+
+	switch (algo_id) {
+	case HASH_ALGO_SHA256:
+		*algo_text = UsefulBuf_FromSZ(sha256);
+		break;
+	case HASH_ALGO_SHA512:
+		*algo_text = UsefulBuf_FromSZ(sha512);
+		break;
+	default:
+		assert(false);
+	}
+}
+
+/*
+ * Outline of token creation. Much of this occurs inside
+ * t_cose_sign1_encode_parameters() and t_cose_sign1_encode_signature().
+ *
+ * - Create encoder context
+ * - Open the CBOR array that hold the COSE_Sign1
+ * - Write COSE Headers
+ *   - Protected Header
+ *      - Algorithm ID
+ *   - Unprotected Headers
+ *     - Key ID
+ * - Open payload bstr
+ *   - Write payload data, maybe lots of it
+ *   - Get bstr that is the encoded payload
+ * - Compute signature
+ *   - Create a separate encoder context for Sig_structure
+ *     - Encode CBOR context identifier
+ *     - Encode protected headers
+ *     - Encode two empty bstr
+ *     - Add one more empty bstr that is a "fake payload"
+ *     - Close off Sig_structure
+ *   - Hash all but "fake payload" of Sig_structure
+ *   - Get payload bstr ptr and length
+ *   - Continue hash of the real encoded payload
+ *   - Run ECDSA
+ * - Write signature into the CBOR output
+ * - Close CBOR array holding the COSE_Sign1
+ */
+static enum attest_token_err_t
+attest_token_encode_start(struct attest_token_encode_ctx *me,
+			  uint32_t opt_flags,
+			  int32_t key_select,
+			  int32_t cose_alg_id,
+			  const struct q_useful_buf *out_buf)
+{
+	enum t_cose_err_t cose_res;
+	uint32_t t_cose_options = 0;
+	struct t_cose_key attest_key;
+	const void *signing_key;
+	struct q_useful_buf_c attest_key_id = NULL_Q_USEFUL_BUF_C;
+
+	assert(me != NULL);
+	assert(out_buf != NULL);
+
+	/* Remember some of the configuration values */
+	me->opt_flags  = opt_flags;
+	me->key_select = key_select;
+
+	t_cose_sign1_sign_init(&(me->signer_ctx),
+			       t_cose_options,
+			       cose_alg_id);
+
+	cose_res = t_cose_sign1_set_restart_context(&(me->signer_ctx),
+						    &(me->signer_restart_ctx));
+	if (cose_res != T_COSE_SUCCESS) {
+		return ATTEST_TOKEN_ERR_COSE_ERROR;
+	}
+
+	t_cose_sign1_set_crypto_context(&(me->signer_ctx),
+					&(me->crypto_ctx));
+
+
+	/*
+	 * Get the reference to `mbedtls_ecp_keypair` and set it to t_cose.
+	 */
+	attest_get_realm_signing_key(&signing_key);
+	attest_key.crypto_lib = T_COSE_CRYPTO_LIB_MBEDTLS;
+	attest_key.k.key_ptr = (void *)signing_key;
+	t_cose_sign1_set_signing_key(&(me->signer_ctx),
+				     attest_key,
+				     attest_key_id);
+
+	/* Spin up the CBOR encoder */
+	QCBOREncode_Init(&(me->cbor_enc_ctx), *out_buf);
+
+	/*
+	 * This will cause the cose headers to be encoded and written into
+	 * out_buf using me->cbor_enc_ctx
+	 */
+	cose_res = t_cose_sign1_encode_parameters(&(me->signer_ctx),
+						  &(me->cbor_enc_ctx));
+
+	if (cose_res != T_COSE_SUCCESS) {
+		return ATTEST_TOKEN_ERR_COSE_ERROR;
+	}
+
+	QCBOREncode_OpenMap(&(me->cbor_enc_ctx));
+	return ATTEST_TOKEN_ERR_SUCCESS;
+}
+
+enum attest_token_err_t
+attest_realm_token_sign(struct attest_token_encode_ctx *me,
+			struct q_useful_buf_c *completed_token)
+{
+	/* The completed and signed encoded cose_sign1 */
+	struct q_useful_buf_c completed_token_ub;
+	enum attest_token_err_t attest_res = ATTEST_TOKEN_ERR_SUCCESS;
+	QCBORError qcbor_res;
+	enum t_cose_err_t cose_res;
+
+	assert(me != NULL);
+	assert(completed_token != NULL);
+
+	/* Finish up the COSE_Sign1. This is where the signing happens */
+	FPU_ALLOW(
+		cose_res = t_cose_sign1_encode_signature(&(me->signer_ctx),
+							 &(me->cbor_enc_ctx)));
+
+	if (cose_res == T_COSE_ERR_SIG_IN_PROGRESS) {
+		/* Token signing has not yet finished */
+		return ATTEST_TOKEN_ERR_COSE_SIGN_IN_PROGRESS;
+	}
+
+	if (cose_res != T_COSE_SUCCESS) {
+		/* Main errors are invoking the hash or signature */
+		return ATTEST_TOKEN_ERR_COSE_ERROR;
+	}
+
+	/*
+	 * Finally close off the CBOR formatting and get the pointer and length
+	 * of the resulting COSE_Sign1
+	 */
+	qcbor_res = QCBOREncode_Finish(&(me->cbor_enc_ctx),
+				       &completed_token_ub);
+
+	switch (qcbor_res) {
+	case QCBOR_ERR_BUFFER_TOO_SMALL:
+		attest_res = ATTEST_TOKEN_ERR_TOO_SMALL;
+		break;
+	case QCBOR_SUCCESS:
+		*completed_token = completed_token_ub;
+		break;
+	default:
+		/* likely from array not closed, too many closes ... */
+		attest_res = ATTEST_TOKEN_ERR_CBOR_FORMATTING;
+	}
+
+	return attest_res;
+}
+
+size_t attest_cca_token_create(struct q_useful_buf         *attest_token_buf,
+			       const struct q_useful_buf_c *realm_token)
+{
+	struct q_useful_buf_c   completed_token;
+	QCBOREncodeContext      cbor_enc_ctx;
+	QCBORError              qcbor_res;
+	struct q_useful_buf_c  *rmm_platform_token;
+
+	__unused int            ret;
+
+	/* Get the platform token */
+	ret = attest_get_platform_token(&rmm_platform_token);
+	assert(ret == 0);
+
+	QCBOREncode_Init(&cbor_enc_ctx, *attest_token_buf);
+
+	QCBOREncode_AddTag(&cbor_enc_ctx, TAG_CCA_TOKEN);
+
+	QCBOREncode_OpenMap(&cbor_enc_ctx);
+
+	QCBOREncode_AddBytesToMapN(&cbor_enc_ctx,
+				   CCA_PLAT_TOKEN,
+				   *rmm_platform_token);
+
+	QCBOREncode_AddBytesToMapN(&cbor_enc_ctx,
+				   CCA_REALM_DELEGATED_TOKEN,
+				   *realm_token);
+	QCBOREncode_CloseMap(&cbor_enc_ctx);
+
+	qcbor_res = QCBOREncode_Finish(&cbor_enc_ctx, &completed_token);
+
+	if (qcbor_res == QCBOR_ERR_BUFFER_TOO_SMALL) {
+		ERROR("CCA output token buffer too small\n");
+		return 0;
+	} else if (qcbor_res != QCBOR_SUCCESS) {
+		/* likely from array not closed, too many closes, ... */
+		assert(false);
+	} else {
+		return completed_token.len;
+	}
+	return 0;
+}
+
+/*
+ * Assemble the Realm Attestation Token in the buffer provided in
+ * realm_token_buf, except the signature.
+ *
+ * As per section A7.2.3.1 of RMM specfication, Realm Attestation token is
+ * composed of:
+ *	- Realm Challenge
+ *	- Realm Personalization Value
+ *	- Realm Hash Algorithm Id
+ *	- Realm Public Key
+ *	- Realm Public Key Hash Algorithm Id
+ *	- Realm Initial Measurement
+ *	- Realm Extensible Measurements
+ */
+int attest_realm_token_create(enum hash_algo algorithm,
+			     unsigned char measurements[][MAX_MEASUREMENT_SIZE],
+			     unsigned int num_measurements,
+			     struct q_useful_buf_c *rpv,
+			     struct token_sign_ctx *ctx,
+			     struct q_useful_buf *realm_token_buf)
+{
+	struct q_useful_buf_c buf;
+	size_t measurement_size;
+	enum attest_token_err_t token_ret;
+	int ret;
+
+	/* Can only be called in the init state */
+	assert(ctx->state == ATTEST_SIGN_NOT_STARTED);
+
+	assert(num_measurements == MEASUREMENT_SLOT_NR);
+
+	/*
+	 * Get started creating the token. This sets up the CBOR and COSE
+	 * contexts which causes the COSE headers to be constructed.
+	 */
+	token_ret = attest_token_encode_start(&(ctx->ctx),
+					      0,     /* option_flags */
+					      0,     /* key_select */
+					      T_COSE_ALGORITHM_ES384,
+					      realm_token_buf);
+	if (token_ret != ATTEST_TOKEN_ERR_SUCCESS) {
+		return token_ret;
+	}
+
+	/* Add challenge value, which is the only input from the caller. */
+	buf.ptr = ctx->challenge;
+	buf.len = ATTEST_CHALLENGE_SIZE;
+	QCBOREncode_AddBytesToMapN(&(ctx->ctx.cbor_enc_ctx),
+				   CCA_REALM_CHALLENGE,
+				   buf);
+
+	QCBOREncode_AddBytesToMapN(&(ctx->ctx.cbor_enc_ctx),
+				   CCA_REALM_PERSONALIZATION_VALUE,
+				   *rpv);
+
+	ret = attest_get_realm_public_key(&buf);
+	if (ret != 0) {
+		return ret;
+	}
+
+	QCBOREncode_AddBytesToMapN(&(ctx->ctx.cbor_enc_ctx),
+				   CCA_REALM_PUB_KEY,
+				   buf);
+
+	attest_get_hash_algo_text(algorithm, &buf);
+	QCBOREncode_AddTextToMapN(&(ctx->ctx.cbor_enc_ctx),
+				  CCA_REALM_HASH_ALGM_ID,
+				  buf);
+
+	attest_get_hash_algo_text(attest_get_realm_public_key_hash_algo_id(),
+				  &buf);
+	QCBOREncode_AddTextToMapN(&(ctx->ctx.cbor_enc_ctx),
+				  CCA_REALM_PUB_KEY_HASH_ALGO_ID,
+				  buf);
+
+	measurement_size = measurement_get_size(algorithm);
+	assert(measurement_size <= MAX_MEASUREMENT_SIZE);
+
+	/* RIM: 0, REM: 1..4 */
+	buf.ptr = &measurements[RIM_MEASUREMENT_SLOT];
+	buf.len = measurement_size;
+	QCBOREncode_AddBytesToMapN(&(ctx->ctx.cbor_enc_ctx),
+				   CCA_REALM_INITIAL_MEASUREMENT,
+				   buf);
+
+	QCBOREncode_OpenArrayInMapN(&(ctx->ctx.cbor_enc_ctx),
+				    CCA_REALM_EXTENSIBLE_MEASUREMENTS);
+
+	for (unsigned int i = 1U; i < num_measurements; ++i) {
+		buf.ptr = &measurements[i];
+		buf.len = measurement_size;
+		QCBOREncode_AddBytes(&(ctx->ctx.cbor_enc_ctx), buf);
+	}
+
+	QCBOREncode_CloseArray(&(ctx->ctx.cbor_enc_ctx));
+	QCBOREncode_CloseMap(&(ctx->ctx.cbor_enc_ctx));
+
+	return ATTEST_TOKEN_ERR_SUCCESS;
+}
diff --git a/lib/attestation/src/attestation_utils.c b/lib/attestation/src/attestation_utils.c
new file mode 100644
index 0000000..31a5189
--- /dev/null
+++ b/lib/attestation/src/attestation_utils.c
@@ -0,0 +1,142 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+#include <assert.h>
+#include <attestation.h>
+#include <attestation_priv.h>
+#include <debug.h>
+#include <errno.h>
+#include <fpu_helpers.h>
+#include <mbedtls/ecp.h>
+#include <mbedtls/memory_buffer_alloc.h>
+#include <memory_alloc.h>
+#include <sizes.h>
+
+/*
+ * Memory buffer for the allocator during key initialization.
+ *
+ * Used to compute the public key and setup a PRNG object per CPU. PRNGs are
+ * needed for key blinding during EC signing.
+ *
+ * Memory requirements:
+ * +------------------------+-------+ ------------------------+
+ * |                        |  MAX  |  Persisting allocation  |
+ * +------------------------+-------+-------------------------+
+ * | Public key computation |  2.4K |         0.4K            |
+ * +------------------------+-------+-------------------------+
+ * |      PRNG setup        |  6.1K |          3.7K           |
+ * +------------------------+-------+-------------------------+
+ *
+ * Measured with:
+ *	src/lib/memory_buffer_alloc.c: mbedtls_memory_buffer_alloc_status()
+ */
+#define INIT_HEAP_PAGES		3
+
+static unsigned char mem_buf[INIT_HEAP_PAGES * SZ_4K]
+					__aligned(sizeof(unsigned long));
+
+static bool attest_initialized;
+
+struct buffer_alloc_ctx init_ctx;
+
+int attestation_init(void)
+{
+	int ret;
+
+	/*
+	 * Associate the allocated heap for mbedtls with the current CPU.
+	 */
+	buffer_alloc_ctx_assign(&init_ctx);
+
+	fpu_save_my_state();
+
+	FPU_ALLOW(mbedtls_memory_buffer_alloc_init(mem_buf, sizeof(mem_buf)));
+
+	/*
+	 * Set the number of max operations per ECC signing iteration
+	 * Check for effective minimum values for
+	 *  - ext/mbedtls/include/mbedtls/ecp.h:493
+	 *
+	 * This adjusts the length of a single signing loop.
+	 */
+	FPU_ALLOW(mbedtls_ecp_set_max_ops(ECP_MAX_OPS));
+
+	FPU_ALLOW(ret = attest_rnd_prng_init());
+	if (ret != 0) {
+		return ret;
+	}
+
+	/* Retrieve the platform key from root world */
+	FPU_ALLOW(ret = attest_init_realm_attestation_key());
+	if (ret != 0) {
+		return ret;
+	}
+
+	fpu_restore_my_state();
+
+	/* Retrieve the platform token from root world */
+	ret = attest_setup_platform_token();
+	if (ret != 0) {
+		return ret;
+	}
+
+	buffer_alloc_ctx_unassign();
+
+	attest_initialized = true;
+
+	return 0;
+}
+
+int attestation_heap_ctx_init(unsigned char *buf, size_t buf_size)
+{
+	assert(buf != NULL);
+
+	if (attest_initialized == false) {
+		return -EINVAL;
+	}
+
+	/* Initialise the mbedTLS heap */
+	fpu_save_my_state();
+	FPU_ALLOW(mbedtls_memory_buffer_alloc_init(buf, buf_size));
+	fpu_restore_my_state();
+
+	return 0;
+}
+
+int attestation_heap_ctx_assign_pe(struct buffer_alloc_ctx *ctx)
+{
+	assert(ctx != NULL);
+
+	if (attest_initialized == false) {
+		return -EINVAL;
+	}
+
+	/*
+	 * Associate the buffer_alloc_ctx to this CPU
+	 */
+	buffer_alloc_ctx_assign(ctx);
+	return 0;
+}
+
+int attestation_heap_ctx_unassign_pe(struct buffer_alloc_ctx *ctx)
+{
+	assert(ctx != NULL);
+
+	if (attest_initialized == false) {
+		return -EINVAL;
+	}
+
+	buffer_alloc_ctx_unassign();
+	return 0;
+}
+
+inline int attestation_heap_reinit_pe(unsigned char *buf, size_t buf_size)
+{
+	fpu_save_my_state();
+	FPU_ALLOW(mbedtls_memory_buffer_alloc_init(buf, buf_size));
+	fpu_restore_my_state();
+
+	return 0;
+}