blob: 87509228fcacd00181ca5ce53f6c85f315e8058d [file] [log] [blame]
Maulik Patelad2f3db2023-05-17 15:41:36 +01001/*
2 * Copyright (c) 2023, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8#include "dpe_context_mngr.h"
9#include <assert.h>
10#include <string.h>
11#include "dice_protection_environment.h"
12#include "dpe_log.h"
13#include "psa/crypto.h"
14
15static struct component_context_t component_ctx_array[MAX_NUM_OF_COMPONENTS];
16static struct layer_context_t layer_ctx_array[MAX_NUM_OF_LAYERS];
17
18static int get_free_component_context_index(void)
19{
20 int i;
21
22 for (i = 0; i < MAX_NUM_OF_COMPONENTS; i++) {
23 if (!component_ctx_array[i].in_use) {
24 break;
25 }
26 }
27
28 if (i >= MAX_NUM_OF_COMPONENTS) {
29 /* No free index left in the array -- all used up! */
30 return -1;
31 }
32
33 return i;
34}
35
36static inline void invalidate_handle(int *handle)
37{
38 *handle = INVALID_HANDLE;
39}
40
41static dpe_error_t renew_nonce(int *handle)
42{
43 uint16_t nonce;
44
45 psa_status_t status = psa_generate_random((uint8_t *)&nonce, sizeof(nonce));
46 if (status != PSA_SUCCESS) {
47 return DPE_INTERNAL_ERROR;
48 }
49 *handle = SET_NONCE(*handle, nonce);
50
51 return DPE_NO_ERROR;
52}
53
54static dpe_error_t generate_new_handle(int *out_handle)
55{
56 /* Find the free component array element */
57 int free_component_idx = get_free_component_context_index();
58 if (free_component_idx < 0) {
59 return DPE_INSUFFICIENT_MEMORY;
60 }
61
62 *out_handle = SET_IDX(*out_handle, free_component_idx);
63
64 return renew_nonce(out_handle);
65}
66
67static void set_context_to_default(int i)
68{
69 component_ctx_array[i].in_use = false;
70 component_ctx_array[i].is_leaf = false;
71 component_ctx_array[i].nonce = INVALID_NONCE_VALUE;
72 component_ctx_array[i].parent_idx = INVALID_COMPONENT_IDX;
73 component_ctx_array[i].linked_layer_idx = INVALID_LAYER_IDX;
74 (void)memset(&component_ctx_array[i].data, 0, sizeof(struct component_context_data_t));
75 //TODO: Question: how to initialise MHU Id mapping?
76 /* Allow component to be derived by default */
77}
78
79static void invalidate_layer(int i)
80{
81 layer_ctx_array[i].state = LAYER_STATE_CLOSED;
82 layer_ctx_array[i].parent_layer_idx = INVALID_LAYER_IDX;
83 (void)memset(&layer_ctx_array[i].data, 0, sizeof(struct layer_context_data_t));
84}
85
86void initialise_all_dpe_contexts(void)
87{
88 int i;
89
90 for (i = 0; i < MAX_NUM_OF_COMPONENTS; i++) {
91 set_context_to_default(i);
92 }
93
94 for (i = 0; i < MAX_NUM_OF_LAYERS; i++) {
95 invalidate_layer(i);
96 }
97}
98
99static dpe_error_t copy_dice_input(struct component_context_t *dest_ctx,
100 const DiceInputValues *dice_inputs)
101{
102 size_t hash_len;
103 psa_status_t status;
104
105 memcpy(&dest_ctx->data.measurement_value, dice_inputs->code_hash,
106 DICE_HASH_SIZE);
107 memcpy(&dest_ctx->data.measurement_descriptor,
108 dice_inputs->code_descriptor,
109 dice_inputs->code_descriptor_size);
110
111 dest_ctx->data.measurement_descriptor_size =
112 dice_inputs->code_descriptor_size;
113
114 memcpy(&dest_ctx->data.signer_id, dice_inputs->authority_hash, DICE_HASH_SIZE);
115 memcpy(&dest_ctx->data.signer_id_descriptor,
116 dice_inputs->authority_descriptor,
117 dice_inputs->authority_descriptor_size);
118
119 dest_ctx->data.signer_id_descriptor_size =
120 dice_inputs->authority_descriptor_size;
121
122 if (dice_inputs->config_type == kDiceConfigTypeInline) {
123 /* Copy config_value */
124 memcpy(&dest_ctx->data.config_value, dice_inputs->config_value,
125 DICE_INLINE_CONFIG_SIZE);
126
127 } else {
128 /* Copy config descriptor */
129 memcpy(&dest_ctx->data.config_descriptor, dice_inputs->config_descriptor,
130 dice_inputs->config_descriptor_size);
131 dest_ctx->data.config_descriptor_size = dice_inputs->config_descriptor_size;
132
133 /* Calculate config value as hash of input config descriptor */
134 status = psa_hash_compute(PSA_ALG_SHA_256,
135 dice_inputs->config_descriptor,
136 dice_inputs->config_descriptor_size,
137 dest_ctx->data.config_value,
138 sizeof(dest_ctx->data.config_value),
139 &hash_len);
140
141 if (status != PSA_SUCCESS) {
142 return DPE_INTERNAL_ERROR;
143 }
144 }
145
146 dest_ctx->data.mode = dice_inputs->mode;
147 memcpy(&dest_ctx->data.hidden, dice_inputs->hidden, DICE_HIDDEN_SIZE);
148
149 return DPE_NO_ERROR;
150}
151
152static bool is_dice_input_valid(const DiceInputValues *dice_inputs)
153{
154 if ((dice_inputs->code_descriptor_size > DICE_CODE_DESCRIPTOR_MAX_SIZE) ||
155 (dice_inputs->authority_descriptor_size > DICE_AUTHORITY_DESCRIPTOR_MAX_SIZE) ||
156 (dice_inputs->config_descriptor_size > DICE_CONFIG_DESCRIPTOR_MAX_SIZE)) {
157 return false;
158 }
159
160 return true;
161}
162
163static bool is_input_handle_valid(int input_context_handle)
164{
165 uint16_t idx = GET_IDX(input_context_handle);
166 uint16_t nonce = GET_NONCE(input_context_handle);
167
168 /* Validate input handle id and nonce */
169 if ((idx >= MAX_NUM_OF_COMPONENTS) || (nonce == INVALID_NONCE_VALUE)) {
170 return false;
171 }
172
173 if (nonce == component_ctx_array[idx].nonce) {
174 return true;
175 }
176
177 return false;
178}
179
180static dpe_error_t derive_child_create_certificate(uint16_t curr_idx)
181{
182 //TODO: Implementation pending
183 /* Finalise the layer */
184 layer_ctx_array[curr_idx].state = LAYER_STATE_FINALISED;
185 return DPE_NO_ERROR;
186}
187
188static uint16_t open_new_layer(void)
189{
190 int i;
191
192 for (i = 0; i < MAX_NUM_OF_LAYERS; i++) {
193 if (layer_ctx_array[i].state == LAYER_STATE_CLOSED) {
194 layer_ctx_array[i].state = LAYER_STATE_OPEN;
195 return i;
196 }
197 }
198
199 return INVALID_LAYER_IDX;
200}
201
202static inline void link_layer(uint16_t child_layer, uint16_t parent_layer)
203{
204 layer_ctx_array[child_layer].parent_layer_idx = parent_layer;
205}
206
207dpe_error_t derive_rot_context(const DiceInputValues *dice_inputs,
208 int *new_child_ctx_handle,
209 int *new_parent_ctx_handle)
210{
211 int status;
212 struct component_context_t *child_comp_ctx, *new_child_ctx;
213 uint16_t new_layer_idx;
214
215 log_derive_rot_context(dice_inputs);
216
217 /* Validate dice inputs */
218 if (!is_dice_input_valid(dice_inputs)) {
219 return DPE_INVALID_ARGUMENT;
220 }
221
222 child_comp_ctx = &component_ctx_array[0];
223 status = copy_dice_input(child_comp_ctx, dice_inputs);
224 if (status != DPE_NO_ERROR) {
225 return status;
226 }
227
228 child_comp_ctx->in_use = true;
229 /* Link context to RoT Layer */
230 child_comp_ctx->linked_layer_idx = DPE_ROT_LAYER_IDX;
231 /* Parent is same as child for RoT context */
232 child_comp_ctx->parent_idx = 0;
233 /* Parent not deriving any more children */
234 invalidate_handle(new_parent_ctx_handle);
235
236 //TODO: Update expected_mhu_id of derived child
237 /* Create certificate for RoT layer */
238 status = derive_child_create_certificate(DPE_ROT_LAYER_IDX);
239 if (status != DPE_NO_ERROR) {
240 return status;
241 }
242
243 /* Generate new handle for child for subsequent requests */
244 if (generate_new_handle(new_child_ctx_handle) != DPE_NO_ERROR) {
245 return DPE_INTERNAL_ERROR;
246 }
247
248 /* Update the component context array element as pointed by newly generated handle */
249 new_child_ctx = &component_ctx_array[GET_IDX(*new_child_ctx_handle)];
250 new_child_ctx->nonce = GET_NONCE(*new_child_ctx_handle);
251 new_child_ctx->in_use = true;
252 /* New child's parent is current RoT component which is evaluated as 0 */
253 new_child_ctx->parent_idx = 0;
254
255 /* Open new layer since RoT layer is finalised and
256 * link the new child to this new layer
257 */
258 new_layer_idx = open_new_layer();
259 new_child_ctx->linked_layer_idx = new_layer_idx;
260
261 /* Link this new layer to the RoT Layer */
262 link_layer(new_layer_idx, DPE_ROT_LAYER_IDX);
263
264 return DPE_NO_ERROR;
265}
266
267static inline bool is_input_client_id_valid(int32_t client_id)
268{
269 //TODO: Waiting for implementation
270 return true;
271}
272
273static void assign_layer_to_context(struct component_context_t *new_ctx)
274{
275 uint16_t new_layer_idx, parent_layer_idx;
276
277 assert(new_ctx->parent_idx < MAX_NUM_OF_COMPONENTS);
278
279 parent_layer_idx = component_ctx_array[new_ctx->parent_idx].linked_layer_idx;
280 assert(parent_layer_idx < MAX_NUM_OF_LAYERS);
281
282 if (layer_ctx_array[parent_layer_idx].state == LAYER_STATE_FINALISED) {
283 /* Parent comp's layer of new child is finalised; open a new layer */
284 new_layer_idx = open_new_layer();
285 /* Link this context to the new layer */
286 new_ctx->linked_layer_idx = new_layer_idx;
287 /* New layer's parent is current layer */
288 link_layer(new_layer_idx, parent_layer_idx);
289
290 } else {
291 /* Parent comp's layer is not yet finalised, link
292 * new component to the same layer as parent
293 */
294 new_ctx->linked_layer_idx = parent_layer_idx;
295 }
296}
297
298dpe_error_t derive_child_request(int input_ctx_handle,
299 bool retain_parent_context,
300 bool allow_child_to_derive,
301 bool create_certificate,
302 const DiceInputValues *dice_inputs,
303 int32_t client_id,
304 int *new_child_ctx_handle,
305 int *new_parent_ctx_handle)
306{
307 dpe_error_t status;
308 struct component_context_t *child_ctx, *parent_ctx, *new_ctx;
309 uint16_t input_child_idx, input_parent_idx;
310
311#ifdef TFM_S_REG_TEST
312 if (layer_ctx_array[DPE_ROT_LAYER_IDX].state != LAYER_STATE_FINALISED) {
313 return derive_rot_context(dice_inputs,
314 new_child_ctx_handle,
315 new_parent_ctx_handle);
316 }
317#endif /* TFM_S_REG_TEST */
318
319 log_derive_child(input_ctx_handle, retain_parent_context,
320 allow_child_to_derive, create_certificate, dice_inputs,
321 client_id);
322
323 /* Validate dice inputs */
324 if (!is_dice_input_valid(dice_inputs)) {
325 return DPE_INVALID_ARGUMENT;
326 }
327
328 /* Validate input handle */
329 if (!is_input_handle_valid(input_ctx_handle)) {
330 return DPE_INVALID_ARGUMENT;
331 }
332 /* Get child component index from the input handle */
333 input_child_idx = GET_IDX(input_ctx_handle);
334 /* Get parent index of input referenced child component */
335 input_parent_idx = component_ctx_array[input_child_idx].parent_idx;
336
337 /* Below check is for safety only; It should not happen
338 * input_child_idx is already checked above in is_input_handle_valid()
339 */
340 assert(input_parent_idx < MAX_NUM_OF_COMPONENTS);
341
342 child_ctx = &component_ctx_array[input_child_idx];
343 parent_ctx = &component_ctx_array[input_parent_idx];
344
345 //TODO: Question: how to get mhu id of incoming request?
346 if (!is_input_client_id_valid(client_id)) {
347 return DPE_INVALID_ARGUMENT;
348 }
349
350 /* Copy dice input to the child component context */
351 status = copy_dice_input(child_ctx, dice_inputs);
352 if (status != DPE_NO_ERROR) {
353 return status;
354 }
355
356 if (create_certificate) {
357 status = derive_child_create_certificate(child_ctx->linked_layer_idx);
358 if (status != DPE_NO_ERROR) {
359 return status;
360 }
361 }
362
363 if (allow_child_to_derive) {
364 /* Generate new handle for child for subsequent requests */
365 if (generate_new_handle(new_child_ctx_handle) != DPE_NO_ERROR) {
366 return DPE_INTERNAL_ERROR;
367 }
368 /* Update the component context array element as pointed by newly generated handle */
369 new_ctx = &component_ctx_array[GET_IDX(*new_child_ctx_handle)];
370 /* Update nonce in new child component context */
371 new_ctx->nonce = GET_NONCE(*new_child_ctx_handle);
372 /* Update parent idx in new child component context */
373 new_ctx->parent_idx = input_child_idx;
374 /* Mark new child component index as in use */
375 new_ctx->in_use = true;
376 assign_layer_to_context(new_ctx);
377
378 } else {
379 /* Child not deriving any children */
380 /* Tag this component as a leaf */
381 child_ctx->is_leaf = true;
382 invalidate_handle(new_child_ctx_handle);
383 /* Renew nonce of child context so it cannot be used again */
384 child_ctx->nonce = INVALID_NONCE_VALUE;
385 }
386
387 if (retain_parent_context) {
388 /* Parent deriving multiple children */
389 /* Generate new handle for child for the same parent for subsequent requests */
390 if (generate_new_handle(new_parent_ctx_handle) != DPE_NO_ERROR) {
391 return DPE_INTERNAL_ERROR;
392 }
393 /* Update the component context array element as pointed by newly generated handle */
394 new_ctx = &component_ctx_array[GET_IDX(*new_parent_ctx_handle)];
395 /* Update nonce in new child component context */
396 new_ctx->nonce = GET_NONCE(*new_parent_ctx_handle);
397 /* Update parent idx in new child component context */
398 new_ctx->parent_idx = input_parent_idx;
399 /* Mark new child component index as in use */
400 new_ctx->in_use = true;
401 assign_layer_to_context(new_ctx);
402
403 } else {
404 /* Parent not deriving any more children */
405 /* No need to return parent handle */
406 invalidate_handle(new_parent_ctx_handle);
407 /* Renew nonce of parent context so it cannot be used again */
408 parent_ctx->nonce = INVALID_NONCE_VALUE;
409 }
410
411 return DPE_NO_ERROR;
412}
Maulik Patel54d65f72023-06-28 13:04:36 +0100413
414dpe_error_t destroy_context_request(int input_ctx_handle,
415 bool destroy_recursively)
416{
417 uint16_t input_ctx_idx, linked_layer_idx;
418 int i;
419 bool is_layer_empty;
420
421 log_destroy_context(input_ctx_handle, destroy_recursively);
422
423 /* Get child component index and linked layer from the input handle */
424 input_ctx_idx = GET_IDX(input_ctx_handle);
425
426#ifdef TFM_S_REG_TEST
427 if (input_ctx_idx == 0) {
428 invalidate_layer(DPE_ROT_LAYER_IDX);
429 set_context_to_default(0);
430 return DPE_NO_ERROR;
431 }
432#endif /* TFM_S_REG_TEST */
433
434 /* Validate input handle */
435 if (!is_input_handle_valid(input_ctx_handle)) {
436 return DPE_INVALID_ARGUMENT;
437 }
438 linked_layer_idx = component_ctx_array[input_ctx_idx].linked_layer_idx;
439
440#ifndef TFM_S_REG_TEST
441 if (linked_layer_idx <= DPE_DESTROY_CONTEXT_THRESHOLD_LAYER_IDX) {
442 /* All layers till hypervisor cannot be destroyed dynamically */
443 return DPE_INVALID_ARGUMENT;
444 }
445#endif /* !TFM_S_REG_TEST */
446
447
448 if (!destroy_recursively) {
449 set_context_to_default(input_ctx_idx);
450 } else {
451 //TODO: To be implemented
452 }
453
454 assert(linked_layer_idx < MAX_NUM_OF_LAYERS);
455
456 /* Close the layer if all of its contexts are destroyed */
457 is_layer_empty = true;
458 for (i = 0; i < MAX_NUM_OF_COMPONENTS; i++) {
459 if (component_ctx_array[i].linked_layer_idx == linked_layer_idx) {
460 /* There are active component context in the layer */
461 is_layer_empty = false;
462 break;
463 }
464 }
465
466 if (is_layer_empty) {
467 invalidate_layer(linked_layer_idx);
468 }
469
470 return DPE_NO_ERROR;
471}