1 /*
2 * SPDX-License-Identifier: BSD-3-Clause
3 * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
4 */
5
6 #include <arch_features.h>
7 #include <assert.h>
8 #include <attestation.h>
9 #include <attestation_priv.h>
10 #include <cpuid.h>
11 #include <entropy.h>
12 #include <errno.h>
13 #include <fpu_helpers.h>
14 #include <mbedtls/entropy.h>
15 #include <mbedtls/hmac_drbg.h>
16 #include <platform_api.h>
17 #include <stdbool.h>
18 #include <utils_def.h>
19
20 /*
21 * Allocate a PRNG object per PE in order to avoid the necessity of locking if
22 * concurrent attestation token requests are executed.
23 */
24 static mbedtls_hmac_drbg_context cpu_drbg_ctx[MAX_CPUS];
25 static bool prng_init_done;
26
get_random_seed(unsigned char * output,size_t len)27 static int get_random_seed(unsigned char *output, size_t len)
28 {
29 bool rc;
30 uint64_t *random_output;
31 uint64_t *random_end;
32
33 assert(!prng_init_done);
34
35 /* Enforce `len` is a multiple of 8 and `output` is 8-byte aligned. */
36 assert((len & 0x7UL) == 0UL && ((uintptr_t)output & 0x7UL) == 0UL);
37
38 random_output = (uint64_t *)output;
39 random_end = (uint64_t *)(output + len);
40
41 for (; random_output < random_end; ++random_output) {
42 rc = arch_collect_entropy(random_output);
43 if (!rc) {
44 return -EINVAL;
45 }
46 }
47 return 0;
48 }
49
50 /*
51 * This function is used by Mbed TLS as a source of entropy. This means it is
52 * called during RMM operation, to add entropy to the signing process.
53 * See declaration in mbedtls/entropy_poll.h.
54 * For details see `MBEDTLS_ENTROPY_HARDWARE_ALT` in mbedtls/config.h
55 */
mbedtls_hardware_poll(void * data,unsigned char * output,size_t len,size_t * olen)56 int mbedtls_hardware_poll(void *data, unsigned char *output,
57 size_t len, size_t *olen)
58 {
59 int ret;
60 unsigned int cpu_id = my_cpuid();
61 void *rng_ctx;
62
63 assert(prng_init_done);
64
65 (void)data;
66
67 /* Not in RMM init, PRNGs are already initialized, use them. */
68 rng_ctx = &cpu_drbg_ctx[cpu_id];
69 ret = mbedtls_hmac_drbg_random(rng_ctx, output, len);
70 if (ret != 0) {
71 return ret;
72 }
73 *olen = len;
74
75 return 0;
76 }
77
attest_get_cpu_rng_context(struct attest_rng_context * rng_ctx)78 void attest_get_cpu_rng_context(struct attest_rng_context *rng_ctx)
79 {
80 unsigned int cpu_id = my_cpuid();
81
82 assert(prng_init_done);
83
84 rng_ctx->f_rng = mbedtls_hmac_drbg_random;
85 rng_ctx->p_rng = &cpu_drbg_ctx[cpu_id];
86 }
87
attest_rnd_prng_init(void)88 int attest_rnd_prng_init(void)
89 {
90 const mbedtls_md_info_t *md_info;
91 mbedtls_hmac_drbg_context drbg_ctx;
92 uint8_t seed[128] __aligned(8) ; /* mbedtls_hardware_poll request this size */
93 unsigned int i;
94 int rc;
95 int retval = 0;
96
97 assert(!prng_init_done);
98 assert(IS_FPU_ALLOWED());
99
100 if (!is_feat_rng_present()) {
101 return -EINVAL;
102 }
103
104 /*
105 * Setup a temporary PRNG which seeded by real TRNG and use this
106 * instance to set up the per CPU PRNG objects. The temporary PRNG
107 * relies on the RNDR instruction to get its seed. RNDR instruction has
108 * an implementation defined TRNG backend. The timing of the TRNG could
109 * be nondeterministic therefore access to it is kept on the minimum.
110 */
111 rc = get_random_seed(seed, sizeof(seed));
112 if (rc != 0) {
113 return -EINVAL;
114 }
115
116 md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
117 mbedtls_hmac_drbg_init(&drbg_ctx);
118 rc = mbedtls_hmac_drbg_seed_buf(&drbg_ctx,
119 md_info,
120 seed, sizeof(seed));
121 if (rc != 0) {
122 retval = -EINVAL;
123 goto free_temp_prng;
124 }
125
126 /*
127 * Set up the per CPU PRNG objects which going to be used during
128 * Elliptic Curve signing to blind the private key.
129 */
130 for (i = 0U; i < MAX_CPUS; ++i) {
131 rc = mbedtls_hmac_drbg_random(&drbg_ctx, seed, sizeof(seed));
132 if (rc != 0) {
133 retval = -EINVAL;
134 goto free_temp_prng;
135 }
136
137 mbedtls_hmac_drbg_init(&cpu_drbg_ctx[i]);
138 rc = mbedtls_hmac_drbg_seed_buf(&cpu_drbg_ctx[i], md_info,
139 seed, sizeof(seed));
140 if (rc != 0) {
141 retval = -EINVAL;
142 goto free_temp_prng;
143 }
144 }
145
146 prng_init_done = true;
147
148 free_temp_prng:
149 /* Free the memory allocated by the temporary PRNG */
150 mbedtls_hmac_drbg_free(&drbg_ctx);
151
152 return retval;
153 }
154