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