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_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;
+}