1 /*
2 * SPDX-License-Identifier: BSD-3-Clause
3 * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
4 */
5
6 #include <assert.h>
7 #include <attestation.h>
8 #include <attestation_priv.h>
9 #include <debug.h>
10 #include <errno.h>
11 #include <fpu_helpers.h>
12 #include <mbedtls/sha256.h>
13 #include <measurement.h>
14 #include <psa/crypto.h>
15 #include <rmm_el3_ifc.h>
16 #include <sizes.h>
17
18 #define ECC_P384_PUBLIC_KEY_SIZE (97U)
19 #define SHA256_DIGEST_SIZE (32U)
20
21 /*
22 * The size of X and Y coordinate in 2 parameter style EC public key. Format is
23 * as defined in [COSE (RFC 8152)] (https://tools.ietf.org/html/rfc8152) and
24 * [SEC 1: Elliptic Curve Cryptography](http://www.secg.org/sec1-v2.pdf).
25 *
26 * This size is well-known and documented in public standards.
27 */
28 #define ECC_P384_COORD_SIZE (48U) /* 384 bits -> 48 bytes */
29 #define BIT_SIZE_OF_P384 (384U)
30
31 /* ECC Curve type define for querying attestation key from monitor */
32 #define ATTEST_KEY_CURVE_ECC_SECP384R1 0
33
34 /*
35 * The platform token which will be needed during attestation.
36 */
37 static unsigned char rmm_platform_token_buf[SZ_4K];
38 static struct q_useful_buf rmm_platform_token;
39
40 /*
41 * The public key is kept loaded as it is both not required to be secret (and
42 * hence can be kept in attestation memory) and immutable.
43 */
44 static uint8_t realm_attest_public_key[ECC_P384_PUBLIC_KEY_SIZE];
45 static size_t realm_attest_public_key_len;
46
47 /*
48 * The hash of the realm attestation public key is included in the Platform
49 * attestation token as the challenge claim.
50 */
51 static uint8_t realm_attest_public_key_hash[SHA256_DIGEST_SIZE];
52 static size_t realm_attest_public_key_hash_len;
53
54 /*
55 * The keypair for the sign operation
56 */
57 static mbedtls_ecp_keypair realm_attest_keypair = {0};
58
59 /* Specify the hash algorithm to use for computing the hash of the
60 * realm public key.
61 */
62 static enum hash_algo public_key_hash_algo_id = HASH_ALGO_SHA256;
63
64 /*
65 * TODO: review panic usage and try to gracefully exit on error. Also
66 * improve documentation of usage of MbedTLS APIs
67 */
attest_init_realm_attestation_key(void)68 int attest_init_realm_attestation_key(void)
69 {
70 int ret;
71 struct q_useful_buf realm_attest_private_key;
72 uintptr_t buf;
73 size_t attest_key_size = 0UL;
74
75 struct attest_rng_context rng_ctx;
76
77 assert(IS_FPU_ALLOWED());
78
79 attest_get_cpu_rng_context(&rng_ctx);
80
81 /*
82 * The realm attestation key is requested from the root world in the
83 * boot phase only once. Then the same key is used in the entire power
84 * cycle to sign the realm attestation tokens.
85 */
86 if (realm_attest_keypair.MBEDTLS_PRIVATE(d).MBEDTLS_PRIVATE(p) != NULL) {
87 ERROR("Realm attestation key already loaded.\n");
88 return -EINVAL;
89 }
90
91 /*
92 * Get the realm attestation key. The key is retrieved in raw format.
93 */
94 buf = rmm_el3_ifc_get_shared_buf_locked();
95
96 if (rmm_el3_ifc_get_realm_attest_key(buf,
97 rmm_el3_ifc_get_shared_buf_size(),
98 &attest_key_size,
99 ATTEST_KEY_CURVE_ECC_SECP384R1) != 0) {
100 rmm_el3_ifc_release_shared_buf();
101 return -EINVAL;
102 }
103
104 realm_attest_private_key.len = attest_key_size;
105 realm_attest_private_key.ptr = (void *)buf;
106
107 /*
108 * Setup ECC key.
109 * The memory for the keypair is allocated from MbedTLS Heap.
110 */
111 mbedtls_ecp_keypair_init(&realm_attest_keypair);
112 ret = mbedtls_ecp_group_load(&realm_attest_keypair.MBEDTLS_PRIVATE(grp),
113 MBEDTLS_ECP_DP_SECP384R1);
114 if (ret != 0) {
115 ERROR("mbedtls_ecp_group_load has failed\n");
116 rmm_el3_ifc_release_shared_buf();
117 return -EINVAL;
118 }
119
120 ret = mbedtls_mpi_read_binary(&realm_attest_keypair.MBEDTLS_PRIVATE(d),
121 realm_attest_private_key.ptr,
122 realm_attest_private_key.len);
123 if (ret != 0) {
124 ERROR("mbedtls_mpi_read_binary has failed\n");
125 rmm_el3_ifc_release_shared_buf();
126 return -EINVAL;
127 }
128
129 ret = mbedtls_ecp_check_privkey(&realm_attest_keypair.MBEDTLS_PRIVATE(grp),
130 &realm_attest_keypair.MBEDTLS_PRIVATE(d));
131 if (ret != 0) {
132 ERROR("mbedtls_ecp_check_privkey has failed: %d\n", ret);
133 rmm_el3_ifc_release_shared_buf();
134 return -EINVAL;
135 }
136
137 ret = mbedtls_ecp_mul(&realm_attest_keypair.MBEDTLS_PRIVATE(grp),
138 &realm_attest_keypair.MBEDTLS_PRIVATE(Q),
139 &realm_attest_keypair.MBEDTLS_PRIVATE(d),
140 &realm_attest_keypair.MBEDTLS_PRIVATE(grp).G,
141 rng_ctx.f_rng,
142 rng_ctx.p_rng);
143 if (ret != 0) {
144 ERROR("mbedtls_ecp_mul priv has failed: %d\n", ret);
145 rmm_el3_ifc_release_shared_buf();
146 return -EINVAL;
147 }
148
149 ret = mbedtls_ecp_point_write_binary(&realm_attest_keypair.MBEDTLS_PRIVATE(grp),
150 &realm_attest_keypair.MBEDTLS_PRIVATE(Q),
151 MBEDTLS_ECP_PF_UNCOMPRESSED,
152 &realm_attest_public_key_len,
153 realm_attest_public_key,
154 sizeof(realm_attest_public_key));
155 if (ret != 0) {
156 ERROR("mbedtls_ecp_point_write_binary pub has failed\n");
157 rmm_el3_ifc_release_shared_buf();
158 return -EINVAL;
159 }
160
161 /* Compute the hash of the realm attestation public key */
162 ret = mbedtls_sha256(realm_attest_public_key,
163 realm_attest_public_key_len,
164 realm_attest_public_key_hash,
165 false);
166 if (ret != 0) {
167 ERROR("mbedtls_sha256 has failed\n");
168 rmm_el3_ifc_release_shared_buf();
169 return -EINVAL;
170 }
171
172 realm_attest_public_key_hash_len = sizeof(realm_attest_public_key_hash);
173
174 /* Clear the private key from the buffer */
175 (void)memset(realm_attest_private_key.ptr, 0,
176 realm_attest_private_key.len);
177
178 rmm_el3_ifc_release_shared_buf();
179
180 return 0;
181 }
182
attest_get_realm_signing_key(const void ** keypair)183 int attest_get_realm_signing_key(const void **keypair)
184 {
185 if (realm_attest_keypair.MBEDTLS_PRIVATE(d).MBEDTLS_PRIVATE(p) == NULL) {
186 ERROR("Realm attestation key not initialized\n");
187 return -EINVAL;
188 }
189
190 *keypair = &realm_attest_keypair;
191 return 0;
192 }
193
attest_get_realm_public_key_hash(struct q_useful_buf_c * public_key_hash)194 int attest_get_realm_public_key_hash(struct q_useful_buf_c *public_key_hash)
195 {
196 if (realm_attest_keypair.MBEDTLS_PRIVATE(d).MBEDTLS_PRIVATE(p) == NULL) {
197 ERROR("Realm attestation key not initialized\n");
198 return -EINVAL;
199 }
200
201 public_key_hash->ptr = realm_attest_public_key_hash;
202 public_key_hash->len = realm_attest_public_key_hash_len;
203 return 0;
204 }
205
attest_get_realm_public_key(struct q_useful_buf_c * public_key)206 int attest_get_realm_public_key(struct q_useful_buf_c *public_key)
207 {
208 if (realm_attest_keypair.MBEDTLS_PRIVATE(d).MBEDTLS_PRIVATE(p) == NULL) {
209 ERROR("Realm attestation key not initialized\n");
210 return -EINVAL;
211 }
212
213 public_key->ptr = realm_attest_public_key;
214 public_key->len = realm_attest_public_key_len;
215 return 0;
216 }
217
attest_setup_platform_token(void)218 int attest_setup_platform_token(void)
219 {
220 int ret;
221 uintptr_t shared_buf;
222 size_t platform_token_len = 0;
223 struct q_useful_buf_c rmm_pub_key_hash;
224
225 /*
226 * Copy the RAK public hash value to the token buffer. This is
227 * used as the challenge input for the token generation
228 * thus creating a binding between the two.
229 */
230 ret = attest_get_realm_public_key_hash(&rmm_pub_key_hash);
231 if (ret != 0) {
232 ERROR("Realm attestation key not initialized\n");
233 return ret;
234 }
235
236 shared_buf = rmm_el3_ifc_get_shared_buf_locked();
237
238 (void)memcpy((void *)shared_buf, rmm_pub_key_hash.ptr,
239 rmm_pub_key_hash.len);
240
241 ret = rmm_el3_ifc_get_platform_token(shared_buf,
242 rmm_el3_ifc_get_shared_buf_size(),
243 &platform_token_len,
244 SHA256_DIGEST_SIZE);
245
246 if (ret != 0) {
247 rmm_el3_ifc_release_shared_buf();
248 return -EINVAL;
249 }
250
251 (void)memcpy(rmm_platform_token_buf,
252 (void *)shared_buf,
253 platform_token_len);
254
255 rmm_el3_ifc_release_shared_buf();
256
257 rmm_platform_token.ptr = rmm_platform_token_buf;
258 rmm_platform_token.len = platform_token_len;
259
260 return 0;
261 }
262
attest_get_platform_token(struct q_useful_buf_c ** buf)263 int attest_get_platform_token(struct q_useful_buf_c **buf)
264 {
265 assert(buf != NULL);
266
267 if (rmm_platform_token.ptr == NULL) {
268 return -EINVAL;
269 }
270
271 *buf = (struct q_useful_buf_c *)&rmm_platform_token;
272 return 0;
273 }
274
attest_get_realm_public_key_hash_algo_id(void)275 enum hash_algo attest_get_realm_public_key_hash_algo_id(void)
276 {
277 return public_key_hash_algo_id;
278 }
279