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