/src/mbedtls/library/psa_crypto_se.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * PSA crypto support for secure element drivers |
3 | | */ |
4 | | /* |
5 | | * Copyright The Mbed TLS Contributors |
6 | | * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later |
7 | | */ |
8 | | |
9 | | #include "common.h" |
10 | | |
11 | | #if defined(MBEDTLS_PSA_CRYPTO_SE_C) |
12 | | |
13 | | #include <stdint.h> |
14 | | #include <string.h> |
15 | | |
16 | | #include "psa/crypto_se_driver.h" |
17 | | |
18 | | #include "psa_crypto_se.h" |
19 | | |
20 | | #if defined(MBEDTLS_PSA_ITS_FILE_C) |
21 | | #include "psa_crypto_its.h" |
22 | | #else /* Native ITS implementation */ |
23 | | #include "psa/error.h" |
24 | | #include "psa/internal_trusted_storage.h" |
25 | | #endif |
26 | | |
27 | | #include "mbedtls/platform.h" |
28 | | |
29 | | |
30 | | |
31 | | /****************************************************************/ |
32 | | /* Driver lookup */ |
33 | | /****************************************************************/ |
34 | | |
35 | | /* This structure is identical to psa_drv_se_context_t declared in |
36 | | * `crypto_se_driver.h`, except that some parts are writable here |
37 | | * (non-const, or pointer to non-const). */ |
38 | | typedef struct { |
39 | | void *persistent_data; |
40 | | size_t persistent_data_size; |
41 | | uintptr_t transient_data; |
42 | | } psa_drv_se_internal_context_t; |
43 | | |
44 | | struct psa_se_drv_table_entry_s { |
45 | | psa_key_location_t location; |
46 | | const psa_drv_se_t *methods; |
47 | | union { |
48 | | psa_drv_se_internal_context_t internal; |
49 | | psa_drv_se_context_t context; |
50 | | } u; |
51 | | }; |
52 | | |
53 | | static psa_se_drv_table_entry_t driver_table[PSA_MAX_SE_DRIVERS]; |
54 | | |
55 | | psa_se_drv_table_entry_t *psa_get_se_driver_entry( |
56 | | psa_key_lifetime_t lifetime) |
57 | 0 | { |
58 | 0 | size_t i; |
59 | 0 | psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(lifetime); |
60 | | /* In the driver table, location=0 means an entry that isn't used. |
61 | | * No driver has a location of 0 because it's a reserved value |
62 | | * (which designates transparent keys). Make sure we never return |
63 | | * a driver entry for location 0. */ |
64 | 0 | if (location == 0) { |
65 | 0 | return NULL; |
66 | 0 | } |
67 | 0 | for (i = 0; i < PSA_MAX_SE_DRIVERS; i++) { |
68 | 0 | if (driver_table[i].location == location) { |
69 | 0 | return &driver_table[i]; |
70 | 0 | } |
71 | 0 | } |
72 | 0 | return NULL; |
73 | 0 | } |
74 | | |
75 | | const psa_drv_se_t *psa_get_se_driver_methods( |
76 | | const psa_se_drv_table_entry_t *driver) |
77 | 0 | { |
78 | 0 | return driver->methods; |
79 | 0 | } |
80 | | |
81 | | psa_drv_se_context_t *psa_get_se_driver_context( |
82 | | psa_se_drv_table_entry_t *driver) |
83 | 0 | { |
84 | 0 | return &driver->u.context; |
85 | 0 | } |
86 | | |
87 | | int psa_get_se_driver(psa_key_lifetime_t lifetime, |
88 | | const psa_drv_se_t **p_methods, |
89 | | psa_drv_se_context_t **p_drv_context) |
90 | 0 | { |
91 | 0 | psa_se_drv_table_entry_t *driver = psa_get_se_driver_entry(lifetime); |
92 | 0 | if (p_methods != NULL) { |
93 | 0 | *p_methods = (driver ? driver->methods : NULL); |
94 | 0 | } |
95 | 0 | if (p_drv_context != NULL) { |
96 | 0 | *p_drv_context = (driver ? &driver->u.context : NULL); |
97 | 0 | } |
98 | 0 | return driver != NULL; |
99 | 0 | } |
100 | | |
101 | | |
102 | | |
103 | | /****************************************************************/ |
104 | | /* Persistent data management */ |
105 | | /****************************************************************/ |
106 | | |
107 | | static psa_status_t psa_get_se_driver_its_file_uid( |
108 | | const psa_se_drv_table_entry_t *driver, |
109 | | psa_storage_uid_t *uid) |
110 | 0 | { |
111 | 0 | if (driver->location > PSA_MAX_SE_LOCATION) { |
112 | 0 | return PSA_ERROR_NOT_SUPPORTED; |
113 | 0 | } |
114 | | |
115 | | /* ITS file sizes are limited to 32 bits. */ |
116 | 0 | if (driver->u.internal.persistent_data_size > UINT32_MAX) { |
117 | 0 | return PSA_ERROR_NOT_SUPPORTED; |
118 | 0 | } |
119 | | |
120 | | /* See the documentation of PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE. */ |
121 | 0 | *uid = PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE + driver->location; |
122 | 0 | return PSA_SUCCESS; |
123 | 0 | } |
124 | | |
125 | | psa_status_t psa_load_se_persistent_data( |
126 | | const psa_se_drv_table_entry_t *driver) |
127 | 0 | { |
128 | 0 | psa_status_t status; |
129 | 0 | psa_storage_uid_t uid; |
130 | 0 | size_t length; |
131 | |
|
132 | 0 | status = psa_get_se_driver_its_file_uid(driver, &uid); |
133 | 0 | if (status != PSA_SUCCESS) { |
134 | 0 | return status; |
135 | 0 | } |
136 | | |
137 | | /* Read the amount of persistent data that the driver requests. |
138 | | * If the data in storage is larger, it is truncated. If the data |
139 | | * in storage is smaller, silently keep what is already at the end |
140 | | * of the output buffer. */ |
141 | | /* psa_get_se_driver_its_file_uid ensures that the size_t |
142 | | * persistent_data_size is in range, but compilers don't know that, |
143 | | * so cast to reassure them. */ |
144 | 0 | return psa_its_get(uid, 0, |
145 | 0 | (uint32_t) driver->u.internal.persistent_data_size, |
146 | 0 | driver->u.internal.persistent_data, |
147 | 0 | &length); |
148 | 0 | } |
149 | | |
150 | | psa_status_t psa_save_se_persistent_data( |
151 | | const psa_se_drv_table_entry_t *driver) |
152 | 0 | { |
153 | 0 | psa_status_t status; |
154 | 0 | psa_storage_uid_t uid; |
155 | |
|
156 | 0 | status = psa_get_se_driver_its_file_uid(driver, &uid); |
157 | 0 | if (status != PSA_SUCCESS) { |
158 | 0 | return status; |
159 | 0 | } |
160 | | |
161 | | /* psa_get_se_driver_its_file_uid ensures that the size_t |
162 | | * persistent_data_size is in range, but compilers don't know that, |
163 | | * so cast to reassure them. */ |
164 | 0 | return psa_its_set(uid, |
165 | 0 | (uint32_t) driver->u.internal.persistent_data_size, |
166 | 0 | driver->u.internal.persistent_data, |
167 | 0 | 0); |
168 | 0 | } |
169 | | |
170 | | psa_status_t psa_destroy_se_persistent_data(psa_key_location_t location) |
171 | 0 | { |
172 | 0 | psa_storage_uid_t uid; |
173 | 0 | if (location > PSA_MAX_SE_LOCATION) { |
174 | 0 | return PSA_ERROR_NOT_SUPPORTED; |
175 | 0 | } |
176 | 0 | uid = PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE + location; |
177 | 0 | return psa_its_remove(uid); |
178 | 0 | } |
179 | | |
180 | | psa_status_t psa_find_se_slot_for_key( |
181 | | const psa_key_attributes_t *attributes, |
182 | | psa_key_creation_method_t method, |
183 | | psa_se_drv_table_entry_t *driver, |
184 | | psa_key_slot_number_t *slot_number) |
185 | 0 | { |
186 | 0 | psa_status_t status; |
187 | 0 | psa_key_location_t key_location = |
188 | 0 | PSA_KEY_LIFETIME_GET_LOCATION(psa_get_key_lifetime(attributes)); |
189 | | |
190 | | /* If the location is wrong, it's a bug in the library. */ |
191 | 0 | if (driver->location != key_location) { |
192 | 0 | return PSA_ERROR_CORRUPTION_DETECTED; |
193 | 0 | } |
194 | | |
195 | | /* If the driver doesn't support key creation in any way, give up now. */ |
196 | 0 | if (driver->methods->key_management == NULL) { |
197 | 0 | return PSA_ERROR_NOT_SUPPORTED; |
198 | 0 | } |
199 | | |
200 | 0 | if (psa_get_key_slot_number(attributes, slot_number) == PSA_SUCCESS) { |
201 | | /* The application wants to use a specific slot. Allow it if |
202 | | * the driver supports it. On a system with isolation, |
203 | | * the crypto service must check that the application is |
204 | | * permitted to request this slot. */ |
205 | 0 | psa_drv_se_validate_slot_number_t p_validate_slot_number = |
206 | 0 | driver->methods->key_management->p_validate_slot_number; |
207 | 0 | if (p_validate_slot_number == NULL) { |
208 | 0 | return PSA_ERROR_NOT_SUPPORTED; |
209 | 0 | } |
210 | 0 | status = p_validate_slot_number(&driver->u.context, |
211 | 0 | driver->u.internal.persistent_data, |
212 | 0 | attributes, method, |
213 | 0 | *slot_number); |
214 | 0 | } else if (method == PSA_KEY_CREATION_REGISTER) { |
215 | | /* The application didn't specify a slot number. This doesn't |
216 | | * make sense when registering a slot. */ |
217 | 0 | return PSA_ERROR_INVALID_ARGUMENT; |
218 | 0 | } else { |
219 | | /* The application didn't tell us which slot to use. Let the driver |
220 | | * choose. This is the normal case. */ |
221 | 0 | psa_drv_se_allocate_key_t p_allocate = |
222 | 0 | driver->methods->key_management->p_allocate; |
223 | 0 | if (p_allocate == NULL) { |
224 | 0 | return PSA_ERROR_NOT_SUPPORTED; |
225 | 0 | } |
226 | 0 | status = p_allocate(&driver->u.context, |
227 | 0 | driver->u.internal.persistent_data, |
228 | 0 | attributes, method, |
229 | 0 | slot_number); |
230 | 0 | } |
231 | 0 | return status; |
232 | 0 | } |
233 | | |
234 | | psa_status_t psa_destroy_se_key(psa_se_drv_table_entry_t *driver, |
235 | | psa_key_slot_number_t slot_number) |
236 | 0 | { |
237 | 0 | psa_status_t status; |
238 | 0 | psa_status_t storage_status; |
239 | | /* Normally a missing method would mean that the action is not |
240 | | * supported. But psa_destroy_key() is not supposed to return |
241 | | * PSA_ERROR_NOT_SUPPORTED: if you can create a key, you should |
242 | | * be able to destroy it. The only use case for a driver that |
243 | | * does not have a way to destroy keys at all is if the keys are |
244 | | * locked in a read-only state: we can use the keys but not |
245 | | * destroy them. Hence, if the driver doesn't support destroying |
246 | | * keys, it's really a lack of permission. */ |
247 | 0 | if (driver->methods->key_management == NULL || |
248 | 0 | driver->methods->key_management->p_destroy == NULL) { |
249 | 0 | return PSA_ERROR_NOT_PERMITTED; |
250 | 0 | } |
251 | 0 | status = driver->methods->key_management->p_destroy( |
252 | 0 | &driver->u.context, |
253 | 0 | driver->u.internal.persistent_data, |
254 | 0 | slot_number); |
255 | 0 | storage_status = psa_save_se_persistent_data(driver); |
256 | 0 | return status == PSA_SUCCESS ? storage_status : status; |
257 | 0 | } |
258 | | |
259 | | psa_status_t psa_init_all_se_drivers(void) |
260 | 0 | { |
261 | 0 | size_t i; |
262 | 0 | for (i = 0; i < PSA_MAX_SE_DRIVERS; i++) { |
263 | 0 | psa_se_drv_table_entry_t *driver = &driver_table[i]; |
264 | 0 | if (driver->location == 0) { |
265 | 0 | continue; /* skipping unused entry */ |
266 | 0 | } |
267 | 0 | const psa_drv_se_t *methods = psa_get_se_driver_methods(driver); |
268 | 0 | if (methods->p_init != NULL) { |
269 | 0 | psa_status_t status = methods->p_init( |
270 | 0 | &driver->u.context, |
271 | 0 | driver->u.internal.persistent_data, |
272 | 0 | driver->location); |
273 | 0 | if (status != PSA_SUCCESS) { |
274 | 0 | return status; |
275 | 0 | } |
276 | 0 | status = psa_save_se_persistent_data(driver); |
277 | 0 | if (status != PSA_SUCCESS) { |
278 | 0 | return status; |
279 | 0 | } |
280 | 0 | } |
281 | 0 | } |
282 | 0 | return PSA_SUCCESS; |
283 | 0 | } |
284 | | |
285 | | |
286 | | |
287 | | /****************************************************************/ |
288 | | /* Driver registration */ |
289 | | /****************************************************************/ |
290 | | |
291 | | psa_status_t psa_register_se_driver( |
292 | | psa_key_location_t location, |
293 | | const psa_drv_se_t *methods) |
294 | 0 | { |
295 | 0 | size_t i; |
296 | 0 | psa_status_t status; |
297 | |
|
298 | 0 | if (methods->hal_version != PSA_DRV_SE_HAL_VERSION) { |
299 | 0 | return PSA_ERROR_NOT_SUPPORTED; |
300 | 0 | } |
301 | | /* Driver table entries are 0-initialized. 0 is not a valid driver |
302 | | * location because it means a transparent key. */ |
303 | 0 | MBEDTLS_STATIC_ASSERT(PSA_KEY_LOCATION_LOCAL_STORAGE == 0, |
304 | 0 | "Secure element support requires 0 to mean a local key"); |
305 | |
|
306 | 0 | if (location == PSA_KEY_LOCATION_LOCAL_STORAGE) { |
307 | 0 | return PSA_ERROR_INVALID_ARGUMENT; |
308 | 0 | } |
309 | 0 | if (location > PSA_MAX_SE_LOCATION) { |
310 | 0 | return PSA_ERROR_NOT_SUPPORTED; |
311 | 0 | } |
312 | | |
313 | 0 | for (i = 0; i < PSA_MAX_SE_DRIVERS; i++) { |
314 | 0 | if (driver_table[i].location == 0) { |
315 | 0 | break; |
316 | 0 | } |
317 | | /* Check that location isn't already in use up to the first free |
318 | | * entry. Since entries are created in order and never deleted, |
319 | | * there can't be a used entry after the first free entry. */ |
320 | 0 | if (driver_table[i].location == location) { |
321 | 0 | return PSA_ERROR_ALREADY_EXISTS; |
322 | 0 | } |
323 | 0 | } |
324 | 0 | if (i == PSA_MAX_SE_DRIVERS) { |
325 | 0 | return PSA_ERROR_INSUFFICIENT_MEMORY; |
326 | 0 | } |
327 | | |
328 | 0 | driver_table[i].location = location; |
329 | 0 | driver_table[i].methods = methods; |
330 | 0 | driver_table[i].u.internal.persistent_data_size = |
331 | 0 | methods->persistent_data_size; |
332 | |
|
333 | 0 | if (methods->persistent_data_size != 0) { |
334 | 0 | driver_table[i].u.internal.persistent_data = |
335 | 0 | mbedtls_calloc(1, methods->persistent_data_size); |
336 | 0 | if (driver_table[i].u.internal.persistent_data == NULL) { |
337 | 0 | status = PSA_ERROR_INSUFFICIENT_MEMORY; |
338 | 0 | goto error; |
339 | 0 | } |
340 | | /* Load the driver's persistent data. On first use, the persistent |
341 | | * data does not exist in storage, and is initialized to |
342 | | * all-bits-zero by the calloc call just above. */ |
343 | 0 | status = psa_load_se_persistent_data(&driver_table[i]); |
344 | 0 | if (status != PSA_SUCCESS && status != PSA_ERROR_DOES_NOT_EXIST) { |
345 | 0 | goto error; |
346 | 0 | } |
347 | 0 | } |
348 | | |
349 | 0 | return PSA_SUCCESS; |
350 | | |
351 | 0 | error: |
352 | 0 | memset(&driver_table[i], 0, sizeof(driver_table[i])); |
353 | 0 | return status; |
354 | 0 | } |
355 | | |
356 | | void psa_unregister_all_se_drivers(void) |
357 | 0 | { |
358 | 0 | size_t i; |
359 | 0 | for (i = 0; i < PSA_MAX_SE_DRIVERS; i++) { |
360 | 0 | if (driver_table[i].u.internal.persistent_data != NULL) { |
361 | 0 | mbedtls_free(driver_table[i].u.internal.persistent_data); |
362 | 0 | } |
363 | 0 | } |
364 | 0 | memset(driver_table, 0, sizeof(driver_table)); |
365 | 0 | } |
366 | | |
367 | | |
368 | | |
369 | | /****************************************************************/ |
370 | | /* The end */ |
371 | | /****************************************************************/ |
372 | | |
373 | | #endif /* MBEDTLS_PSA_CRYPTO_SE_C */ |