1 /*
2 * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7 #include <string.h>
8 #include "tfm_builtin_key_loader.h"
9 #if defined(TFM_BUILTIN_KEY_LOADER_DERIVE_KEY_USING_PSA)
10 #include "tfm_mbedcrypto_include.h"
11 #else
12 #include "mbedtls/hkdf.h"
13 #endif /* TFM_BUILTIN_KEY_LOADER_DERIVE_KEY_USING_PSA */
14 #include "psa_manifest/pid.h"
15 #include "tfm_plat_crypto_keys.h"
16 #include "crypto_library.h"
17
18 #ifndef TFM_BUILTIN_MAX_KEY_LEN
19 #define TFM_BUILTIN_MAX_KEY_LEN (48)
20 #endif /* TFM_BUILTIN_MAX_KEY_LEN */
21
22 #ifndef TFM_BUILTIN_MAX_KEYS
23 #define TFM_BUILTIN_MAX_KEYS (TFM_BUILTIN_KEY_SLOT_MAX)
24 #endif /* TFM_BUILTIN_MAX_KEYS */
25
26 #define NUMBER_OF_ELEMENTS_OF(x) sizeof(x)/sizeof(*x)
27
28 /*!
29 * \brief A structure which describes a builtin key slot
30 */
31 struct tfm_builtin_key_t {
32 uint8_t __attribute__((aligned(4))) key[TFM_BUILTIN_MAX_KEY_LEN]; /*!< Raw key material, 4-byte aligned */
33 size_t key_len; /*!< Size of the key material held in the key buffer */
34 psa_key_attributes_t attr; /*!< Key attributes associated to the key */
35 uint32_t is_loaded; /*!< Boolean indicating whether the slot is being used */
36 };
37
38 /*!
39 * \brief The below array is used by the driver to store key material in secure memory, in order
40 * for the keys and relevant metadata to be accessible by the PSA Crypto core layer
41 */
42 static struct tfm_builtin_key_t g_builtin_key_slots[TFM_BUILTIN_MAX_KEYS] = {0};
43
44 /*!
45 * \brief This functions returns the slot associated to a key id interrogating the
46 * platform HAL table
47 */
builtin_key_get_slot(psa_key_id_t key_id,psa_drv_slot_number_t * slot_ptr)48 static psa_status_t builtin_key_get_slot(psa_key_id_t key_id, psa_drv_slot_number_t *slot_ptr)
49 {
50 const tfm_plat_builtin_key_descriptor_t *desc_table = NULL;
51 size_t number_of_keys = tfm_plat_builtin_key_get_desc_table_ptr(&desc_table);
52 psa_drv_slot_number_t slot_number = TFM_BUILTIN_KEY_SLOT_MAX;
53
54 for (size_t idx = 0; idx < number_of_keys; idx++) {
55 if (desc_table[idx].key_id == key_id) {
56 slot_number = desc_table[idx].slot_number;
57 break;
58 }
59 }
60
61 if (slot_number == TFM_BUILTIN_KEY_SLOT_MAX) {
62 *slot_ptr = TFM_BUILTIN_KEY_SLOT_MAX;
63 return PSA_ERROR_DOES_NOT_EXIST;
64 }
65
66 *slot_ptr = slot_number;
67 return PSA_SUCCESS;
68 }
69
70 /*!
71 * \brief This functions returns the attributes of the key interrogating the
72 * platform HAL
73 */
builtin_key_get_attributes(struct tfm_builtin_key_t * key_slot,int32_t user,psa_key_id_t key_id,psa_key_attributes_t * attr)74 static psa_status_t builtin_key_get_attributes(
75 struct tfm_builtin_key_t *key_slot, int32_t user, psa_key_id_t key_id, psa_key_attributes_t *attr)
76 {
77 psa_key_usage_t usage = 0x0;
78
79 /* Retrieve the usage policy based on the key_id and the user of the key */
80 const tfm_plat_builtin_key_policy_t *policy_table = NULL;
81 size_t number_of_keys = tfm_plat_builtin_key_get_policy_table_ptr(&policy_table);
82
83 for (size_t idx = 0; idx < number_of_keys; idx++) {
84 if (policy_table[idx].key_id == key_id) {
85 if (policy_table[idx].per_user_policy == 0) {
86 usage = policy_table[idx].usage;
87 } else {
88 /* The policy depedends also on the user of the key */
89 size_t num_users = policy_table[idx].per_user_policy;
90 const tfm_plat_builtin_key_per_user_policy_t *p_policy = policy_table[idx].policy_ptr;
91
92 for (size_t j = 0; j < num_users; j++) {
93 if (p_policy[j].user == user) {
94 usage = p_policy[j].usage;
95 break;
96 }
97 }
98 }
99 break;
100 }
101 }
102
103 /* A normal copy is enough to copy all the fields as there no pointers */
104 memcpy(attr, &(key_slot->attr), sizeof(psa_key_attributes_t));
105 /* The stored attributes have an owner == 0, but we need to preserve the
106 * user received from the caller, which is stored in user_id
107 */
108 psa_set_key_id(attr, tfm_crypto_library_key_id_init(user, key_id));
109 /* Set the flags according to the policy for the user for this key_id */
110 psa_set_key_usage_flags(attr, usage);
111
112 return PSA_SUCCESS;
113 }
114
115 /*!
116 * \brief This function derives a key into a provided buffer, to make sure that
117 * keys that are returned for usage to the PSA Crypto core, are differentiated
118 * based on the partition user. The derived keys are described as platform keys
119 */
120 #if defined(TFM_BUILTIN_KEY_LOADER_DERIVE_KEY_USING_PSA)
derive_subkey_into_buffer(struct tfm_builtin_key_t * key_slot,int32_t user,uint8_t * key_buffer,size_t key_buffer_size,size_t * key_buffer_length)121 static psa_status_t derive_subkey_into_buffer(
122 struct tfm_builtin_key_t *key_slot, int32_t user,
123 uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length)
124 {
125 #ifdef TFM_PARTITION_TEST_PS
126 /* Hack to allow the PS tests to work, since they directly call
127 * ps_system_prepare from the test partition which would otherwise derive a
128 * different key.
129 */
130 if (user == TFM_SP_PS_TEST) {
131 user = TFM_SP_PS;
132 }
133 #endif /* TFM_PARTITION_TEST_PS */
134
135 psa_status_t status;
136 tfm_crypto_library_key_id_t output_key_id_local = tfm_crypto_library_key_id_init_default();
137 tfm_crypto_library_key_id_t builtin_key = psa_get_key_id(&key_slot->attr);
138 tfm_crypto_library_key_id_t input_key_id_local = tfm_crypto_library_key_id_init(
139 TFM_SP_CRYPTO, CRYPTO_LIBRARY_GET_KEY_ID(builtin_key));
140 psa_key_derivation_operation_t deriv_ops = psa_key_derivation_operation_init();
141 psa_key_attributes_t output_key_attr = PSA_KEY_ATTRIBUTES_INIT;
142 psa_key_attributes_t input_key_attr = PSA_KEY_ATTRIBUTES_INIT;
143
144 /* Set properties for the output key */
145 psa_set_key_type(&output_key_attr, PSA_KEY_TYPE_RAW_DATA);
146 psa_set_key_bits(&output_key_attr, PSA_BYTES_TO_BITS(key_buffer_size));
147 psa_set_key_usage_flags(&output_key_attr, PSA_KEY_USAGE_EXPORT);
148
149 /* Import the key material as a volatiile key */
150 psa_set_key_usage_flags(&input_key_attr, PSA_KEY_USAGE_DERIVE);
151 psa_set_key_algorithm(&input_key_attr, PSA_ALG_HKDF(PSA_ALG_SHA_256));
152 psa_set_key_type(&input_key_attr, PSA_KEY_TYPE_DERIVE);
153 status = psa_import_key(&input_key_attr, key_slot->key, key_slot->key_len, &input_key_id_local);
154 if (status != PSA_SUCCESS) {
155 goto wrap_up;
156 }
157
158 status = psa_key_derivation_setup(&deriv_ops, PSA_ALG_HKDF(PSA_ALG_SHA_256));
159 if (status != PSA_SUCCESS) {
160 goto wrap_up;
161 }
162
163 /* No salt is being used for the derivation */
164
165 status = psa_key_derivation_input_key(
166 &deriv_ops, PSA_KEY_DERIVATION_INPUT_SECRET, input_key_id_local);
167 if (status != PSA_SUCCESS) {
168 goto wrap_up;
169 }
170
171 status = psa_key_derivation_input_bytes(
172 &deriv_ops, PSA_KEY_DERIVATION_INPUT_INFO, (uint8_t *)&user, sizeof(user));
173 if (status != PSA_SUCCESS) {
174 goto wrap_up;
175 }
176
177 status = psa_key_derivation_output_key(&output_key_attr, &deriv_ops,
178 &output_key_id_local);
179 if (status != PSA_SUCCESS) {
180 goto wrap_up;
181 }
182
183 status = psa_export_key(output_key_id_local, key_buffer, key_buffer_size, key_buffer_length);
184 if (status != PSA_SUCCESS) {
185 goto wrap_up;
186 }
187
188 wrap_up:
189 (void)psa_key_derivation_abort(&deriv_ops);
190 (void)psa_destroy_key(input_key_id_local);
191 (void)psa_destroy_key(output_key_id_local);
192
193 return status;
194 }
195 #else
derive_subkey_into_buffer(struct tfm_builtin_key_t * key_slot,int32_t user,uint8_t * key_buffer,size_t key_buffer_size,size_t * key_buffer_length)196 static psa_status_t derive_subkey_into_buffer(
197 struct tfm_builtin_key_t *key_slot, int32_t user,
198 uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length)
199 {
200 int mbedtls_err;
201
202 #ifdef TFM_PARTITION_TEST_PS
203 /* Hack to allow the PS tests to work, since they directly call
204 * ps_system_prepare from the test partition which would otherwise derive a
205 * different key.
206 */
207 if (user == TFM_SP_PS_TEST) {
208 user = TFM_SP_PS;
209 }
210 #endif /* TFM_PARTITION_TEST_PS */
211
212 /* FIXME this should be moved to using the PSA APIs once key derivation is
213 * implemented in the PSA driver wrapper. Using the external PSA apis
214 * directly creates a keyslot and we'd need to read the data from it and
215 * then destroy it, so isn't ideal. In order to avoid infinite recursion,
216 * it'll be necessary to add a special case (probably if owner == 0) to make
217 * sure the new PSA derivation request doesn't end up back here.
218 */
219 mbedtls_err = mbedtls_hkdf(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
220 NULL, 0, key_slot->key, key_slot->key_len,
221 (uint8_t *)&user, sizeof(user), key_buffer,
222 key_buffer_size);
223 if (mbedtls_err) {
224 return PSA_ERROR_GENERIC_ERROR;
225 }
226
227 *key_buffer_length = key_buffer_size;
228
229 return PSA_SUCCESS;
230 }
231 #endif /* TFM_BUILTIN_KEY_LOADER_DERIVE_KEY_USING_PSA */
232
builtin_key_copy_to_buffer(struct tfm_builtin_key_t * key_slot,uint8_t * key_buffer,size_t key_buffer_size,size_t * key_buffer_length)233 static psa_status_t builtin_key_copy_to_buffer(
234 struct tfm_builtin_key_t *key_slot, uint8_t *key_buffer,
235 size_t key_buffer_size, size_t *key_buffer_length)
236 {
237 memcpy(key_buffer, key_slot->key, key_slot->key_len);
238 *key_buffer_length = key_slot->key_len;
239
240 return PSA_SUCCESS;
241 }
242
243 /*!
244 * \defgroup tfm_builtin_key_loader
245 *
246 */
247 /*!@{*/
tfm_builtin_key_loader_init(void)248 psa_status_t tfm_builtin_key_loader_init(void)
249 {
250 psa_status_t err = PSA_ERROR_CORRUPTION_DETECTED;
251 const tfm_plat_builtin_key_descriptor_t *desc_table = NULL;
252 size_t number_of_keys = tfm_plat_builtin_key_get_desc_table_ptr(&desc_table);
253
254 /* These properties and key material are filled by the loaders */
255 uint8_t buf[TFM_BUILTIN_MAX_KEY_LEN];
256 size_t key_len;
257 size_t key_bits;
258 psa_algorithm_t algorithm;
259 psa_key_type_t type;
260
261 for (size_t key = 0; key < number_of_keys; key++) {
262 if (desc_table[key].lifetime != TFM_BUILTIN_KEY_LOADER_LIFETIME) {
263 /* If the key is not bound to this driver, just don't load it */
264 continue;
265 }
266 psa_drv_slot_number_t slot_number = desc_table[key].slot_number;
267 /* The owner of a builtin key is set to 0 */
268 tfm_crypto_library_key_id_t key_id = tfm_crypto_library_key_id_init(0, desc_table[key].key_id);
269 psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT;
270 enum tfm_plat_err_t plat_err = desc_table[key].loader_key_func(
271 &buf[0], TFM_BUILTIN_MAX_KEY_LEN, &key_len, &key_bits, &algorithm, &type);
272 if (plat_err != TFM_PLAT_ERR_SUCCESS) {
273 err = PSA_ERROR_HARDWARE_FAILURE;
274 goto wrap_up;
275 }
276
277 /* Build the attributes with the metadata retrieved from the platform and desc table */
278 psa_set_key_id(&attr, key_id);
279 psa_set_key_bits(&attr, key_bits);
280 psa_set_key_algorithm(&attr, algorithm);
281 psa_set_key_type(&attr, type);
282 psa_set_key_lifetime(&attr, desc_table[key].lifetime);
283
284 /* Populate the internal table of the tfm_builtin_key_loader driver with key and metadata */
285 memcpy(&(g_builtin_key_slots[slot_number].attr), &attr, sizeof(psa_key_attributes_t));
286 memcpy(&(g_builtin_key_slots[slot_number].key), buf, key_len);
287 g_builtin_key_slots[slot_number].key_len = key_len;
288 g_builtin_key_slots[slot_number].is_loaded = 1;
289 }
290 /* At this point the discovered keys have been loaded successfully into the driver */
291 err = PSA_SUCCESS;
292
293 wrap_up:
294 return err;
295 }
296
tfm_builtin_key_loader_get_key_buffer_size(tfm_crypto_library_key_id_t key_id,size_t * len)297 psa_status_t tfm_builtin_key_loader_get_key_buffer_size(
298 tfm_crypto_library_key_id_t key_id, size_t *len)
299 {
300 psa_status_t err;
301 psa_drv_slot_number_t slot_number;
302
303 if (len == NULL) {
304 err = PSA_ERROR_INVALID_ARGUMENT;
305 goto wrap_up;
306 }
307
308 *len = 0;
309
310 err = builtin_key_get_slot(CRYPTO_LIBRARY_GET_KEY_ID(key_id), &slot_number);
311 if (err != PSA_SUCCESS) {
312 goto wrap_up;
313 }
314
315 *len = g_builtin_key_slots[slot_number].key_len;
316 err = PSA_SUCCESS;
317
318 wrap_up:
319 return err;
320 }
321
tfm_builtin_key_loader_get_builtin_key(psa_drv_slot_number_t slot_number,psa_key_attributes_t * attributes,uint8_t * key_buffer,size_t key_buffer_size,size_t * key_buffer_length)322 psa_status_t tfm_builtin_key_loader_get_builtin_key(
323 psa_drv_slot_number_t slot_number, psa_key_attributes_t *attributes,
324 uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length)
325 {
326 psa_status_t err;
327 struct tfm_builtin_key_t *key_slot;
328 tfm_crypto_library_key_id_t key_id;
329
330 if ((uint32_t)slot_number >= NUMBER_OF_ELEMENTS_OF(g_builtin_key_slots)) {
331 err = PSA_ERROR_INVALID_ARGUMENT;
332 goto wrap_up;
333 }
334
335 key_slot = &g_builtin_key_slots[slot_number];
336
337 /* The request is for a valid slot that has not been loaded*/
338 if (!key_slot->is_loaded) {
339 err = PSA_ERROR_DOES_NOT_EXIST;
340 goto wrap_up;
341 }
342
343 if (attributes == NULL) {
344 err = PSA_ERROR_INVALID_ARGUMENT;
345 goto wrap_up;
346 }
347
348 key_id = psa_get_key_id(attributes);
349 err = builtin_key_get_attributes(key_slot,
350 CRYPTO_LIBRARY_GET_OWNER(key_id),
351 CRYPTO_LIBRARY_GET_KEY_ID(key_id),
352 attributes);
353 if (err != PSA_SUCCESS) {
354 goto wrap_up;
355 }
356
357 /* Note that the core layer might use this function just to probe, for a loaded
358 * key, the attributes of the key. In this case, key_buffer and key_buffer_length
359 * could be NULL hence the validation of those pointers must happen after this
360 * check here. In fact, PSA_ERROR_BUFFER_TOO_SMALL is considered in the crypto
361 * core as a safe failure value that lets the caller continue.
362 */
363 if (key_buffer_size < key_slot->key_len) {
364 err = PSA_ERROR_BUFFER_TOO_SMALL;
365 goto wrap_up;
366 }
367
368 if (key_buffer == NULL || key_buffer_length == NULL) {
369 err = PSA_ERROR_INVALID_ARGUMENT;
370 goto wrap_up;
371 }
372
373 /* If a key can be used for derivation, we derive a further subkey for each
374 * users to prevent multiple users deriving the same keys as each other.
375 * For keys for encryption and signing, it's assumed that if multiple
376 * partitions have access to the key, there is a good reason and therefore
377 * they all need access to the raw builtin key.
378 */
379 int32_t user = CRYPTO_LIBRARY_GET_OWNER(key_id);
380 if (psa_get_key_usage_flags(attributes) & PSA_KEY_USAGE_DERIVE && user != TFM_SP_CRYPTO) {
381
382 err = derive_subkey_into_buffer(key_slot, user,
383 key_buffer, key_buffer_size,
384 key_buffer_length);
385 } else {
386 err = builtin_key_copy_to_buffer(key_slot, key_buffer, key_buffer_size,
387 key_buffer_length);
388 }
389
390 wrap_up:
391 return err;
392 }
393 /*!@}*/
394