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