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