blob: 4fde391c75df37e072749fc91266c47a7905c671 [file] [log] [blame]
Soby Mathewb4c6df42022-11-09 11:13:29 +00001/*
2 * SPDX-License-Identifier: BSD-3-Clause
3 * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
4 */
5
6#include <attestation.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +00007#include <debug.h>
8#include <granule.h>
9#include <measurement.h>
10#include <realm.h>
AlexeiFedorov5b186ad2023-04-26 14:43:18 +010011#include <rsi-handler.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000012#include <smc-rsi.h>
13#include <smc.h>
14#include <string.h>
15#include <utils_def.h>
16
17#define MAX_EXTENDED_SIZE (64U)
18
19/*
20 * Return the Realm Personalization Value.
21 *
22 * Arguments:
23 * rd - The Realm descriptor.
Mate Toth-Pal071aa562023-07-04 09:09:26 +020024 * claim_ptr - The start address of the Realm Personalization Value claim
25 * claim_len - The length of the Realm Personalization Value claim
Soby Mathewb4c6df42022-11-09 11:13:29 +000026 */
Mate Toth-Pal071aa562023-07-04 09:09:26 +020027static void get_rpv(struct rd *rd, void **claim_ptr, size_t *claim_len)
Soby Mathewb4c6df42022-11-09 11:13:29 +000028{
Mate Toth-Pal071aa562023-07-04 09:09:26 +020029 *claim_ptr = (uint8_t *)&(rd->rpv[0]);
30 *claim_len = RPV_SIZE;
Soby Mathewb4c6df42022-11-09 11:13:29 +000031}
32
33/*
34 * Save the input parameters in the context for later iterations to check for
35 * consistency.
36 */
37static void save_input_parameters(struct rec *rec)
38{
39 rec->token_sign_ctx.token_ipa = rec->regs[1];
40 (void)memcpy(rec->token_sign_ctx.challenge, &rec->regs[2],
41 ATTEST_CHALLENGE_SIZE);
42}
43
44/*
45 * Verify that in all the iterations the input parameters are the same
46 * as in the initial call.
47 */
48static bool verify_input_parameters_consistency(struct rec *rec)
49{
50 return rec->token_sign_ctx.token_ipa == rec->regs[1];
51}
52
53/*
54 * Function to continue with the sign operation.
55 * It returns void as the result will be updated in the
56 * struct attest_result passed as argument.
57 */
58static void attest_token_continue_sign_state(struct rec *rec,
59 struct attest_result *res)
60{
61 /*
62 * Sign and finish creating the token.
63 */
64 enum attest_token_err_t ret =
65 attest_realm_token_sign(&(rec->token_sign_ctx.ctx),
Mate Toth-Pal071aa562023-07-04 09:09:26 +020066 &(rec->rmm_realm_token_len));
Soby Mathewb4c6df42022-11-09 11:13:29 +000067
68 if ((ret == ATTEST_TOKEN_ERR_COSE_SIGN_IN_PROGRESS) ||
69 (ret == ATTEST_TOKEN_ERR_SUCCESS)) {
70 /*
71 * Return to RSI handler function after each iteration
72 * to check is there anything else to do (pending IRQ)
73 * or next signing iteration can be executed.
74 */
75 res->incomplete = true;
76 res->smc_res.x[0] = RSI_INCOMPLETE;
77
78 /* If this was the last signing cycle */
79 if (ret == ATTEST_TOKEN_ERR_SUCCESS) {
80 rec->token_sign_ctx.state =
81 ATTEST_SIGN_TOKEN_WRITE_IN_PROGRESS;
82 }
83 } else {
84 /* Accessible only in case of failure during token signing */
85 ERROR("FATAL_ERROR: Realm token creation failed\n");
86 panic();
87 }
88}
89
90/*
91 * Function to continue with the token write operation.
92 * It returns void as the result will be updated in the
93 * struct attest_result passed as argument.
94 */
95static void attest_token_continue_write_state(struct rec *rec,
96 struct attest_result *res)
97{
Soby Mathewb4c6df42022-11-09 11:13:29 +000098 struct granule *gr;
99 uint8_t *realm_att_token;
100 unsigned long realm_att_token_ipa = rec->regs[1];
101 enum s2_walk_status walk_status;
102 struct s2_walk_result walk_res = { 0UL };
Mate Toth-Pal071aa562023-07-04 09:09:26 +0200103 size_t attest_token_len;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000104
105 /*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000106 * Translate realm granule IPA to PA. If returns with
107 * WALK_SUCCESS then the last level page table (llt),
108 * which holds the realm_att_token_buf mapping, is locked.
109 */
AlexeiFedorovd2e1bbd2023-04-18 15:18:39 +0100110 walk_status = realm_ipa_to_pa(rec, realm_att_token_ipa, &walk_res);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000111
112 /* Walk parameter validity was checked by RSI_ATTESTATION_TOKEN_INIT */
113 assert(walk_status != WALK_INVALID_PARAMS);
114
115 if (walk_status == WALK_FAIL) {
AlexeiFedorovd2e1bbd2023-04-18 15:18:39 +0100116 if (walk_res.ripas_val == RIPAS_EMPTY) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000117 res->smc_res.x[0] = RSI_ERROR_INPUT;
118 } else {
119 /*
120 * Translation failed, IPA is not mapped. Return to NS host to
121 * fix the issue.
122 */
123 res->walk_result.abort = true;
124 res->walk_result.rtt_level = walk_res.rtt_level;
125 res->smc_res.x[0] = RSI_INCOMPLETE;
126 }
127 return;
128 }
129
130 /* Map realm data granule to RMM address space */
131 gr = find_granule(walk_res.pa);
132 realm_att_token = granule_map(gr, SLOT_RSI_CALL);
133
Mate Toth-Pal071aa562023-07-04 09:09:26 +0200134 attest_token_len = attest_cca_token_create(realm_att_token,
135 ATTEST_TOKEN_BUFFER_SIZE,
136 (void *)rec->rmm_realm_token_buf,
137 rec->rmm_realm_token_len);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000138
139 /* Unmap realm granule */
140 buffer_unmap(realm_att_token);
141
142 /* Unlock last level page table (walk_res.g_llt) */
143 granule_unlock(walk_res.llt);
144
145 /* Write output parameters */
146 if (attest_token_len == 0) {
147 res->smc_res.x[0] = RSI_ERROR_INPUT;
148 } else {
149 res->smc_res.x[0] = RSI_SUCCESS;
150 res->smc_res.x[1] = attest_token_len;
151 }
152
153 /* The signing has either succeeded or failed. Reset the state. */
154 rec->token_sign_ctx.state = ATTEST_SIGN_NOT_STARTED;
155}
156
157unsigned long handle_rsi_attest_token_init(struct rec *rec)
158{
159 struct rd *rd = NULL;
160 unsigned long ret;
161 unsigned long realm_buf_ipa = rec->regs[1];
Mate Toth-Pal071aa562023-07-04 09:09:26 +0200162 void *rpv_ptr;
163 size_t rpv_len;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000164 int att_ret;
165
166 assert(rec != NULL);
167
168 /*
169 * Calling RSI_ATTESTATION_TOKEN_INIT any time aborts any ongoing
170 * operation.
171 * TODO: This can be moved to attestation lib
172 */
173 if (rec->token_sign_ctx.state != ATTEST_SIGN_NOT_STARTED) {
174 int restart;
175
176 rec->token_sign_ctx.state = ATTEST_SIGN_NOT_STARTED;
177 restart = attestation_heap_reinit_pe(rec->aux_data.attest_heap_buf,
AlexeiFedoroveaec0c42023-02-01 18:13:32 +0000178 REC_HEAP_SIZE);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000179 if (restart != 0) {
180 /* There is no provision for this failure so panic */
181 panic();
182 }
183 }
184
185 if (!GRANULE_ALIGNED(realm_buf_ipa)) {
186 return RSI_ERROR_INPUT;
187 }
188
189 /*
190 * rd lock is acquired so that measurement cannot be updated
191 * simultaneously by another rec
192 */
193 granule_lock(rec->realm_info.g_rd, GRANULE_STATE_RD);
194 rd = granule_map(rec->realm_info.g_rd, SLOT_RD);
195 if (!addr_in_par(rd, realm_buf_ipa)) {
196 ret = RSI_ERROR_INPUT;
197 goto out_unmap_rd;
198 }
199
200 /*
201 * Save the input parameters in the context for later iterations
202 * to check.
203 */
204 save_input_parameters(rec);
205
Mate Toth-Pal071aa562023-07-04 09:09:26 +0200206 get_rpv(rd, &rpv_ptr, &rpv_len);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000207 att_ret = attest_realm_token_create(rd->algorithm, rd->measurement,
208 MEASUREMENT_SLOT_NR,
Mate Toth-Pal071aa562023-07-04 09:09:26 +0200209 rpv_ptr,
210 rpv_len,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000211 &rec->token_sign_ctx,
Mate Toth-Pal071aa562023-07-04 09:09:26 +0200212 rec->rmm_realm_token_buf,
213 sizeof(rec->rmm_realm_token_buf));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000214 if (att_ret != 0) {
215 ERROR("FATAL_ERROR: Realm token creation failed,\n");
216 panic();
217 }
218
219 rec->token_sign_ctx.state = ATTEST_SIGN_IN_PROGRESS;
220 ret = RSI_SUCCESS;
221
222out_unmap_rd:
223 buffer_unmap(rd);
224 granule_unlock(rec->realm_info.g_rd);
225 return ret;
226}
227
Soby Mathewb4c6df42022-11-09 11:13:29 +0000228void handle_rsi_attest_token_continue(struct rec *rec,
229 struct attest_result *res)
230{
231 assert(rec != NULL);
232 assert(res != NULL);
233
234 /* Initialize attest_result */
235 res->incomplete = false;
236 res->walk_result.abort = false;
237
238 if (!verify_input_parameters_consistency(rec)) {
239 res->smc_res.x[0] = RSI_ERROR_INPUT;
240 return;
241 }
242
243 switch (rec->token_sign_ctx.state) {
244 case ATTEST_SIGN_NOT_STARTED:
245 /*
246 * Before this call the initial attestation token call
247 * (SMC_RSI_ATTEST_TOKEN_INIT) must have been executed
248 * successfully.
249 */
250 res->smc_res.x[0] = RSI_ERROR_STATE;
251 break;
252 case ATTEST_SIGN_IN_PROGRESS:
253 attest_token_continue_sign_state(rec, res);
254 break;
255 case ATTEST_SIGN_TOKEN_WRITE_IN_PROGRESS:
256 attest_token_continue_write_state(rec, res);
257 break;
258 default:
259 /* Any other state is considered an error. */
260 assert(false);
261 }
262}
263
264unsigned long handle_rsi_extend_measurement(struct rec *rec)
265{
266 struct granule *g_rd;
267 struct rd *rd;
268 unsigned long index;
269 unsigned long rd_addr;
270 size_t size;
271 unsigned long ret;
272 void *extend_measurement;
273 unsigned char *current_measurement;
274 int __unused meas_ret;
275
276 /*
277 * rd lock is acquired so that measurement cannot be updated
278 * simultaneously by another rec
279 */
280 rd_addr = granule_addr(rec->realm_info.g_rd);
281 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
282
283 assert(g_rd != NULL);
284
285 rd = granule_map(rec->realm_info.g_rd, SLOT_RD);
286
287 /*
288 * X1: index
289 * X2: size
290 * X3-X10: measurement value
291 */
292 index = rec->regs[1];
293
294 if ((index == RIM_MEASUREMENT_SLOT) ||
295 (index >= MEASUREMENT_SLOT_NR)) {
296 ret = RSI_ERROR_INPUT;
297 goto out_unmap_rd;
298 }
299
300 size = rec->regs[2];
301
302 if (size > MAX_EXTENDED_SIZE) {
303 ret = RSI_ERROR_INPUT;
304 goto out_unmap_rd;
305 }
306
307 extend_measurement = &rec->regs[3];
308 current_measurement = rd->measurement[index];
309
310 measurement_extend(rd->algorithm,
311 current_measurement,
312 extend_measurement,
313 size,
314 current_measurement);
315
316 ret = RSI_SUCCESS;
317
318out_unmap_rd:
319 buffer_unmap(rd);
320 granule_unlock(g_rd);
321 return ret;
322}
323
324unsigned long handle_rsi_read_measurement(struct rec *rec)
325{
326 struct rd *rd;
327 unsigned long idx;
328 size_t measurement_size;
329
330 assert(rec != NULL);
331
332 /* X1: Index */
333 idx = rec->regs[1];
334
335 if (idx >= MEASUREMENT_SLOT_NR) {
336 return RSI_ERROR_INPUT;
337 }
338
339 /*
340 * rd lock is acquired so that measurement cannot be updated
341 * simultaneously by another rec
342 */
343 granule_lock(rec->realm_info.g_rd, GRANULE_STATE_RD);
344 rd = granule_map(rec->realm_info.g_rd, SLOT_RD);
345
346 measurement_size = measurement_get_size(rd->algorithm);
347
348 (void)memcpy(&rec->regs[1], rd->measurement[idx], measurement_size);
349
350 /* Zero-initialize the unused area */
351 if (measurement_size < MAX_MEASUREMENT_SIZE) {
352 (void)memset((char *)(&rec->regs[1]) + measurement_size,
353 0, MAX_MEASUREMENT_SIZE - measurement_size);
354 }
355
356 buffer_unmap(rd);
357 granule_unlock(rec->realm_info.g_rd);
358
359 return RSI_SUCCESS;
360}