1 /*
2 * SPDX-License-Identifier: BSD-3-Clause
3 * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
4 */
5
6 #include <attestation.h>
7 #include <attestation_token.h>
8 #include <debug.h>
9 #include <granule.h>
10 #include <measurement.h>
11 #include <realm.h>
12 #include <realm_attest.h>
13 #include <smc-rsi.h>
14 #include <smc.h>
15 #include <string.h>
16 #include <utils_def.h>
17
18 #define MAX_EXTENDED_SIZE (64U)
19
20 /*
21 * Return the Realm Personalization Value.
22 *
23 * Arguments:
24 * rd - The Realm descriptor.
25 * claim - The structure to return the Realm Personalization Value claim
26 */
get_rpv(struct rd * rd,struct q_useful_buf_c * claim)27 static void get_rpv(struct rd *rd, struct q_useful_buf_c *claim)
28 {
29 claim->ptr = (uint8_t *)&(rd->rpv[0]);
30 claim->len = RPV_SIZE;
31 }
32
33 /*
34 * Save the input parameters in the context for later iterations to check for
35 * consistency.
36 */
save_input_parameters(struct rec * rec)37 static 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 */
verify_input_parameters_consistency(struct rec * rec)48 static 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 */
attest_token_continue_sign_state(struct rec * rec,struct attest_result * res)58 static 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),
66 &(rec->rmm_realm_token));
67
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 */
attest_token_continue_write_state(struct rec * rec,struct attest_result * res)95 static void attest_token_continue_write_state(struct rec *rec,
96 struct attest_result *res)
97 {
98 struct rd *rd = NULL;
99 struct granule *gr;
100 uint8_t *realm_att_token;
101 unsigned long realm_att_token_ipa = rec->regs[1];
102 enum s2_walk_status walk_status;
103 struct s2_walk_result walk_res = { 0UL };
104 struct q_useful_buf attest_token_buf;
105 size_t attest_token_len;
106
107 /*
108 * The refcount on rd and rec will protect from any changes
109 * while REC is running.
110 */
111 rd = granule_map(rec->realm_info.g_rd, SLOT_RD);
112
113 /*
114 * Translate realm granule IPA to PA. If returns with
115 * WALK_SUCCESS then the last level page table (llt),
116 * which holds the realm_att_token_buf mapping, is locked.
117 */
118 walk_status = realm_ipa_to_pa(rd, realm_att_token_ipa, &walk_res);
119 buffer_unmap(rd);
120
121 /* Walk parameter validity was checked by RSI_ATTESTATION_TOKEN_INIT */
122 assert(walk_status != WALK_INVALID_PARAMS);
123
124 if (walk_status == WALK_FAIL) {
125 if (s2_walk_result_match_ripas(&walk_res, RMI_EMPTY)) {
126 res->smc_res.x[0] = RSI_ERROR_INPUT;
127 } else {
128 /*
129 * Translation failed, IPA is not mapped. Return to NS host to
130 * fix the issue.
131 */
132 res->walk_result.abort = true;
133 res->walk_result.rtt_level = walk_res.rtt_level;
134 res->smc_res.x[0] = RSI_INCOMPLETE;
135 }
136 return;
137 }
138
139 /* Map realm data granule to RMM address space */
140 gr = find_granule(walk_res.pa);
141 realm_att_token = granule_map(gr, SLOT_RSI_CALL);
142
143 attest_token_buf.ptr = realm_att_token;
144 attest_token_buf.len = ATTEST_TOKEN_BUFFER_SIZE;
145
146 attest_token_len = attest_cca_token_create(&attest_token_buf,
147 &rec->rmm_realm_token);
148
149 /* Unmap realm granule */
150 buffer_unmap(realm_att_token);
151
152 /* Unlock last level page table (walk_res.g_llt) */
153 granule_unlock(walk_res.llt);
154
155 /* Write output parameters */
156 if (attest_token_len == 0) {
157 res->smc_res.x[0] = RSI_ERROR_INPUT;
158 } else {
159 res->smc_res.x[0] = RSI_SUCCESS;
160 res->smc_res.x[1] = attest_token_len;
161 }
162
163 /* The signing has either succeeded or failed. Reset the state. */
164 rec->token_sign_ctx.state = ATTEST_SIGN_NOT_STARTED;
165 }
166
handle_rsi_attest_token_init(struct rec * rec)167 unsigned long handle_rsi_attest_token_init(struct rec *rec)
168 {
169 struct rd *rd = NULL;
170 unsigned long ret;
171 unsigned long realm_buf_ipa = rec->regs[1];
172 struct q_useful_buf rmm_realm_token_buf = {
173 rec->rmm_realm_token_buf, sizeof(rec->rmm_realm_token_buf)};
174 struct q_useful_buf_c rpv;
175 int att_ret;
176
177 assert(rec != NULL);
178
179 /*
180 * Calling RSI_ATTESTATION_TOKEN_INIT any time aborts any ongoing
181 * operation.
182 * TODO: This can be moved to attestation lib
183 */
184 if (rec->token_sign_ctx.state != ATTEST_SIGN_NOT_STARTED) {
185 int restart;
186
187 rec->token_sign_ctx.state = ATTEST_SIGN_NOT_STARTED;
188 restart = attestation_heap_reinit_pe(rec->aux_data.attest_heap_buf,
189 REC_HEAP_PAGES * SZ_4K);
190 if (restart != 0) {
191 /* There is no provision for this failure so panic */
192 panic();
193 }
194 }
195
196 if (!GRANULE_ALIGNED(realm_buf_ipa)) {
197 return RSI_ERROR_INPUT;
198 }
199
200 /*
201 * rd lock is acquired so that measurement cannot be updated
202 * simultaneously by another rec
203 */
204 granule_lock(rec->realm_info.g_rd, GRANULE_STATE_RD);
205 rd = granule_map(rec->realm_info.g_rd, SLOT_RD);
206 if (!addr_in_par(rd, realm_buf_ipa)) {
207 ret = RSI_ERROR_INPUT;
208 goto out_unmap_rd;
209 }
210
211 /*
212 * Save the input parameters in the context for later iterations
213 * to check.
214 */
215 save_input_parameters(rec);
216
217 get_rpv(rd, &rpv);
218 att_ret = attest_realm_token_create(rd->algorithm, rd->measurement,
219 MEASUREMENT_SLOT_NR,
220 &rpv,
221 &rec->token_sign_ctx,
222 &rmm_realm_token_buf);
223 if (att_ret != 0) {
224 ERROR("FATAL_ERROR: Realm token creation failed,\n");
225 panic();
226 }
227
228 rec->token_sign_ctx.state = ATTEST_SIGN_IN_PROGRESS;
229 ret = RSI_SUCCESS;
230
231 out_unmap_rd:
232 buffer_unmap(rd);
233 granule_unlock(rec->realm_info.g_rd);
234 return ret;
235 }
236
attest_realm_token_sign_continue_start(void)237 void attest_realm_token_sign_continue_start(void)
238 {
239 fpu_save_my_state();
240 }
241
attest_realm_token_sign_continue_finish(void)242 void attest_realm_token_sign_continue_finish(void)
243 {
244 fpu_restore_my_state();
245 }
246
handle_rsi_attest_token_continue(struct rec * rec,struct attest_result * res)247 void handle_rsi_attest_token_continue(struct rec *rec,
248 struct attest_result *res)
249 {
250 assert(rec != NULL);
251 assert(res != NULL);
252
253 /* Initialize attest_result */
254 res->incomplete = false;
255 res->walk_result.abort = false;
256
257 if (!verify_input_parameters_consistency(rec)) {
258 res->smc_res.x[0] = RSI_ERROR_INPUT;
259 return;
260 }
261
262 switch (rec->token_sign_ctx.state) {
263 case ATTEST_SIGN_NOT_STARTED:
264 /*
265 * Before this call the initial attestation token call
266 * (SMC_RSI_ATTEST_TOKEN_INIT) must have been executed
267 * successfully.
268 */
269 res->smc_res.x[0] = RSI_ERROR_STATE;
270 break;
271 case ATTEST_SIGN_IN_PROGRESS:
272 attest_token_continue_sign_state(rec, res);
273 break;
274 case ATTEST_SIGN_TOKEN_WRITE_IN_PROGRESS:
275 attest_token_continue_write_state(rec, res);
276 break;
277 default:
278 /* Any other state is considered an error. */
279 assert(false);
280 }
281 }
282
handle_rsi_extend_measurement(struct rec * rec)283 unsigned long handle_rsi_extend_measurement(struct rec *rec)
284 {
285 struct granule *g_rd;
286 struct rd *rd;
287 unsigned long index;
288 unsigned long rd_addr;
289 size_t size;
290 unsigned long ret;
291 void *extend_measurement;
292 unsigned char *current_measurement;
293 int __unused meas_ret;
294
295 /*
296 * rd lock is acquired so that measurement cannot be updated
297 * simultaneously by another rec
298 */
299 rd_addr = granule_addr(rec->realm_info.g_rd);
300 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
301
302 assert(g_rd != NULL);
303
304 rd = granule_map(rec->realm_info.g_rd, SLOT_RD);
305
306 /*
307 * X1: index
308 * X2: size
309 * X3-X10: measurement value
310 */
311 index = rec->regs[1];
312
313 if ((index == RIM_MEASUREMENT_SLOT) ||
314 (index >= MEASUREMENT_SLOT_NR)) {
315 ret = RSI_ERROR_INPUT;
316 goto out_unmap_rd;
317 }
318
319 size = rec->regs[2];
320
321 if (size > MAX_EXTENDED_SIZE) {
322 ret = RSI_ERROR_INPUT;
323 goto out_unmap_rd;
324 }
325
326 extend_measurement = &rec->regs[3];
327 current_measurement = rd->measurement[index];
328
329 measurement_extend(rd->algorithm,
330 current_measurement,
331 extend_measurement,
332 size,
333 current_measurement);
334
335 ret = RSI_SUCCESS;
336
337 out_unmap_rd:
338 buffer_unmap(rd);
339 granule_unlock(g_rd);
340 return ret;
341 }
342
handle_rsi_read_measurement(struct rec * rec)343 unsigned long handle_rsi_read_measurement(struct rec *rec)
344 {
345 struct rd *rd;
346 unsigned long idx;
347 size_t measurement_size;
348
349 assert(rec != NULL);
350
351 /* X1: Index */
352 idx = rec->regs[1];
353
354 if (idx >= MEASUREMENT_SLOT_NR) {
355 return RSI_ERROR_INPUT;
356 }
357
358 /*
359 * rd lock is acquired so that measurement cannot be updated
360 * simultaneously by another rec
361 */
362 granule_lock(rec->realm_info.g_rd, GRANULE_STATE_RD);
363 rd = granule_map(rec->realm_info.g_rd, SLOT_RD);
364
365 measurement_size = measurement_get_size(rd->algorithm);
366
367 (void)memcpy(&rec->regs[1], rd->measurement[idx], measurement_size);
368
369 /* Zero-initialize the unused area */
370 if (measurement_size < MAX_MEASUREMENT_SIZE) {
371 (void)memset((char *)(&rec->regs[1]) + measurement_size,
372 0, MAX_MEASUREMENT_SIZE - measurement_size);
373 }
374
375 buffer_unmap(rd);
376 granule_unlock(rec->realm_info.g_rd);
377
378 return RSI_SUCCESS;
379 }
380