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