1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2018-2020, Linaro Limited 4 */ 5 6 #include <assert.h> 7 #include <pkcs11_ta.h> 8 #include <string.h> 9 #include <string_ext.h> 10 #include <tee_internal_api_extensions.h> 11 #include <util.h> 12 13 #include "pkcs11_token.h" 14 #include "pkcs11_helpers.h" 15 16 #define PERSISTENT_OBJECT_ID_LEN 32 17 18 /* 19 * Token persistent objects 20 * 21 * The persistent objects are each identified by a UUID. 22 * The persistent object database stores the list of the UUIDs registered. For 23 * each it is expected that a file of ID "UUID" is stored in the TA secure 24 * storage. 25 */ 26 static TEE_Result get_db_file_name(struct ck_token *token, 27 char *name, size_t size) 28 { 29 int n = snprintf(name, size, "token.db.%u", get_token_id(token)); 30 31 if (n < 0 || (size_t)n >= size) 32 return TEE_ERROR_SECURITY; 33 else 34 return TEE_SUCCESS; 35 } 36 37 static TEE_Result open_db_file(struct ck_token *token, 38 TEE_ObjectHandle *out_hdl) 39 { 40 char file[PERSISTENT_OBJECT_ID_LEN] = { }; 41 TEE_Result res = TEE_ERROR_GENERIC; 42 43 res = get_db_file_name(token, file, sizeof(file)); 44 if (res) 45 return res; 46 47 return TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, file, sizeof(file), 48 TEE_DATA_FLAG_ACCESS_READ | 49 TEE_DATA_FLAG_ACCESS_WRITE, 50 out_hdl); 51 } 52 53 void update_persistent_db(struct ck_token *token) 54 { 55 TEE_Result res = TEE_ERROR_GENERIC; 56 TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL; 57 58 res = open_db_file(token, &db_hdl); 59 if (res) { 60 EMSG("Failed to open token persistent db: %#"PRIx32, res); 61 TEE_Panic(0); 62 } 63 res = TEE_WriteObjectData(db_hdl, token->db_main, 64 sizeof(*token->db_main)); 65 if (res) { 66 EMSG("Failed to write to token persistent db: %#"PRIx32, res); 67 TEE_Panic(0); 68 } 69 70 TEE_CloseObject(db_hdl); 71 } 72 73 static enum pkcs11_rc do_hash(uint32_t user, const uint8_t *pin, 74 size_t pin_size, uint32_t salt, 75 uint8_t hash[TEE_MAX_HASH_SIZE]) 76 { 77 TEE_Result res = TEE_SUCCESS; 78 TEE_OperationHandle oh = TEE_HANDLE_NULL; 79 uint32_t sz = TEE_MAX_HASH_SIZE; 80 81 res = TEE_AllocateOperation(&oh, TEE_ALG_SHA256, TEE_MODE_DIGEST, 0); 82 if (res) 83 return tee2pkcs_error(res); 84 85 TEE_DigestUpdate(oh, &user, sizeof(user)); 86 TEE_DigestUpdate(oh, &salt, sizeof(salt)); 87 res = TEE_DigestDoFinal(oh, pin, pin_size, hash, &sz); 88 TEE_FreeOperation(oh); 89 90 if (res) 91 return PKCS11_CKR_GENERAL_ERROR; 92 93 memset(hash + sz, 0, TEE_MAX_HASH_SIZE - sz); 94 return PKCS11_CKR_OK; 95 } 96 97 enum pkcs11_rc hash_pin(enum pkcs11_user_type user, const uint8_t *pin, 98 size_t pin_size, uint32_t *salt, 99 uint8_t hash[TEE_MAX_HASH_SIZE]) 100 { 101 enum pkcs11_rc rc = PKCS11_CKR_OK; 102 uint32_t s = 0; 103 104 TEE_GenerateRandom(&s, sizeof(s)); 105 if (!s) 106 s++; 107 108 rc = do_hash(user, pin, pin_size, s, hash); 109 if (!rc) 110 *salt = s; 111 return rc; 112 } 113 114 enum pkcs11_rc verify_pin(enum pkcs11_user_type user, const uint8_t *pin, 115 size_t pin_size, uint32_t salt, 116 const uint8_t hash[TEE_MAX_HASH_SIZE]) 117 { 118 uint8_t tmp_hash[TEE_MAX_HASH_SIZE] = { 0 }; 119 enum pkcs11_rc rc = PKCS11_CKR_OK; 120 121 rc = do_hash(user, pin, pin_size, salt, tmp_hash); 122 if (rc) 123 return rc; 124 125 if (buf_compare_ct(tmp_hash, hash, TEE_MAX_HASH_SIZE)) 126 rc = PKCS11_CKR_PIN_INCORRECT; 127 128 return rc; 129 } 130 131 /* 132 * Release resources relate to persistent database 133 */ 134 void close_persistent_db(struct ck_token *token __unused) 135 { 136 } 137 138 static int get_persistent_obj_idx(struct ck_token *token, TEE_UUID *uuid) 139 { 140 size_t i = 0; 141 142 if (!uuid) 143 return -1; 144 145 for (i = 0; i < token->db_objs->count; i++) 146 if (!TEE_MemCompare(token->db_objs->uuids + i, 147 uuid, sizeof(TEE_UUID))) 148 return i; 149 150 return -1; 151 } 152 153 /* UUID for persistent object */ 154 enum pkcs11_rc create_object_uuid(struct ck_token *token, 155 struct pkcs11_object *obj) 156 { 157 assert(!obj->uuid); 158 159 obj->uuid = TEE_Malloc(sizeof(TEE_UUID), 160 TEE_USER_MEM_HINT_NO_FILL_ZERO); 161 if (!obj->uuid) 162 return PKCS11_CKR_DEVICE_MEMORY; 163 164 do { 165 TEE_GenerateRandom(obj->uuid, sizeof(TEE_UUID)); 166 } while (get_persistent_obj_idx(token, obj->uuid) >= 0); 167 168 return PKCS11_CKR_OK; 169 } 170 171 void destroy_object_uuid(struct ck_token *token __maybe_unused, 172 struct pkcs11_object *obj) 173 { 174 assert(get_persistent_obj_idx(token, obj->uuid) < 0); 175 176 TEE_Free(obj->uuid); 177 obj->uuid = NULL; 178 } 179 180 enum pkcs11_rc get_persistent_objects_list(struct ck_token *token, 181 TEE_UUID *array, size_t *size) 182 { 183 size_t out_size = *size; 184 185 *size = token->db_objs->count * sizeof(TEE_UUID); 186 187 if (out_size < *size) 188 return PKCS11_CKR_BUFFER_TOO_SMALL; 189 190 if (array) 191 TEE_MemMove(array, token->db_objs->uuids, *size); 192 193 return PKCS11_CKR_OK; 194 } 195 196 enum pkcs11_rc unregister_persistent_object(struct ck_token *token, 197 TEE_UUID *uuid) 198 { 199 TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL; 200 struct token_persistent_objs *ptr = NULL; 201 TEE_Result res = TEE_ERROR_GENERIC; 202 int count = 0; 203 int idx = 0; 204 205 if (!uuid) 206 return PKCS11_CKR_OK; 207 208 idx = get_persistent_obj_idx(token, uuid); 209 if (idx < 0) { 210 DMSG("Cannot unregister an invalid persistent object"); 211 return PKCS11_RV_NOT_FOUND; 212 } 213 214 ptr = TEE_Malloc(sizeof(struct token_persistent_objs) + 215 ((token->db_objs->count - 1) * sizeof(TEE_UUID)), 216 TEE_USER_MEM_HINT_NO_FILL_ZERO); 217 if (!ptr) 218 return PKCS11_CKR_DEVICE_MEMORY; 219 220 res = open_db_file(token, &db_hdl); 221 if (res) 222 goto out; 223 224 res = TEE_SeekObjectData(db_hdl, sizeof(struct token_persistent_main), 225 TEE_DATA_SEEK_SET); 226 if (res) { 227 DMSG("Failed to read database"); 228 goto out; 229 } 230 231 TEE_MemMove(ptr, token->db_objs, 232 sizeof(struct token_persistent_objs) + 233 idx * sizeof(TEE_UUID)); 234 235 ptr->count--; 236 count = ptr->count - idx; 237 238 TEE_MemMove(&ptr->uuids[idx], 239 &token->db_objs->uuids[idx + 1], 240 count * sizeof(TEE_UUID)); 241 242 res = TEE_WriteObjectData(db_hdl, ptr, 243 sizeof(struct token_persistent_objs) + 244 ptr->count * sizeof(TEE_UUID)); 245 if (res) 246 DMSG("Failed to update database"); 247 TEE_Free(token->db_objs); 248 token->db_objs = ptr; 249 ptr = NULL; 250 251 out: 252 TEE_CloseObject(db_hdl); 253 TEE_Free(ptr); 254 255 return tee2pkcs_error(res); 256 } 257 258 enum pkcs11_rc register_persistent_object(struct ck_token *token, 259 TEE_UUID *uuid) 260 { 261 TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL; 262 TEE_Result res = TEE_ERROR_GENERIC; 263 void *ptr = NULL; 264 size_t size = 0; 265 int count = 0; 266 267 if (get_persistent_obj_idx(token, uuid) >= 0) 268 TEE_Panic(0); 269 270 count = token->db_objs->count; 271 ptr = TEE_Realloc(token->db_objs, 272 sizeof(struct token_persistent_objs) + 273 ((count + 1) * sizeof(TEE_UUID))); 274 if (!ptr) 275 return PKCS11_CKR_DEVICE_MEMORY; 276 277 token->db_objs = ptr; 278 TEE_MemMove(token->db_objs->uuids + count, uuid, sizeof(TEE_UUID)); 279 280 size = sizeof(struct token_persistent_main) + 281 sizeof(struct token_persistent_objs) + 282 count * sizeof(TEE_UUID); 283 284 res = open_db_file(token, &db_hdl); 285 if (res) 286 goto out; 287 288 res = TEE_TruncateObjectData(db_hdl, size + sizeof(TEE_UUID)); 289 if (res) 290 goto out; 291 292 res = TEE_SeekObjectData(db_hdl, sizeof(struct token_persistent_main), 293 TEE_DATA_SEEK_SET); 294 if (res) 295 goto out; 296 297 token->db_objs->count++; 298 299 res = TEE_WriteObjectData(db_hdl, token->db_objs, 300 sizeof(struct token_persistent_objs) + 301 token->db_objs->count * sizeof(TEE_UUID)); 302 if (res) 303 token->db_objs->count--; 304 305 out: 306 TEE_CloseObject(db_hdl); 307 308 return tee2pkcs_error(res); 309 } 310 311 /* 312 * Return the token instance, either initialized from reset or initialized 313 * from the token persistent state if found. 314 */ 315 struct ck_token *init_persistent_db(unsigned int token_id) 316 { 317 struct ck_token *token = get_token(token_id); 318 TEE_Result res = TEE_ERROR_GENERIC; 319 TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL; 320 /* Copy persistent database: main db and object db */ 321 struct token_persistent_main *db_main = NULL; 322 struct token_persistent_objs *db_objs = NULL; 323 void *ptr = NULL; 324 325 if (!token) 326 return NULL; 327 328 LIST_INIT(&token->object_list); 329 330 db_main = TEE_Malloc(sizeof(*db_main), TEE_MALLOC_FILL_ZERO); 331 db_objs = TEE_Malloc(sizeof(*db_objs), TEE_MALLOC_FILL_ZERO); 332 if (!db_main || !db_objs) 333 goto error; 334 335 res = open_db_file(token, &db_hdl); 336 337 if (res == TEE_SUCCESS) { 338 uint32_t size = 0; 339 size_t idx = 0; 340 341 IMSG("PKCS11 token %u: load db", token_id); 342 343 size = sizeof(*db_main); 344 res = TEE_ReadObjectData(db_hdl, db_main, size, &size); 345 if (res || size != sizeof(*db_main)) 346 TEE_Panic(0); 347 348 size = sizeof(*db_objs); 349 res = TEE_ReadObjectData(db_hdl, db_objs, size, &size); 350 if (res || size != sizeof(*db_objs)) 351 TEE_Panic(0); 352 353 size += db_objs->count * sizeof(TEE_UUID); 354 ptr = TEE_Realloc(db_objs, size); 355 if (!ptr) 356 goto error; 357 358 db_objs = ptr; 359 size -= sizeof(struct token_persistent_objs); 360 res = TEE_ReadObjectData(db_hdl, db_objs->uuids, size, &size); 361 if (res || size != (db_objs->count * sizeof(TEE_UUID))) 362 TEE_Panic(0); 363 364 for (idx = 0; idx < db_objs->count; idx++) { 365 /* Create an empty object instance */ 366 struct pkcs11_object *obj = NULL; 367 TEE_UUID *uuid = NULL; 368 369 uuid = TEE_Malloc(sizeof(TEE_UUID), 370 TEE_USER_MEM_HINT_NO_FILL_ZERO); 371 if (!uuid) 372 goto error; 373 374 TEE_MemMove(uuid, &db_objs->uuids[idx], sizeof(*uuid)); 375 376 obj = create_token_object(NULL, uuid); 377 if (!obj) 378 TEE_Panic(0); 379 380 LIST_INSERT_HEAD(&token->object_list, obj, link); 381 } 382 383 } else if (res == TEE_ERROR_ITEM_NOT_FOUND) { 384 char file[PERSISTENT_OBJECT_ID_LEN] = { }; 385 386 IMSG("PKCS11 token %u: init db", token_id); 387 388 TEE_MemFill(db_main, 0, sizeof(*db_main)); 389 TEE_MemFill(db_main->label, '*', sizeof(db_main->label)); 390 391 db_main->flags = PKCS11_CKFT_SO_PIN_TO_BE_CHANGED | 392 PKCS11_CKFT_USER_PIN_TO_BE_CHANGED | 393 PKCS11_CKFT_RNG | 394 PKCS11_CKFT_DUAL_CRYPTO_OPERATIONS | 395 PKCS11_CKFT_LOGIN_REQUIRED; 396 397 res = get_db_file_name(token, file, sizeof(file)); 398 if (res) 399 TEE_Panic(0); 400 401 /* 402 * Object stores persistent state + persistent object 403 * references. 404 */ 405 res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE, 406 file, sizeof(file), 407 TEE_DATA_FLAG_ACCESS_READ | 408 TEE_DATA_FLAG_ACCESS_WRITE, 409 TEE_HANDLE_NULL, 410 db_main, sizeof(*db_main), 411 &db_hdl); 412 if (res) { 413 EMSG("Failed to create db: %#"PRIx32, res); 414 goto error; 415 } 416 417 res = TEE_TruncateObjectData(db_hdl, sizeof(*db_main) + 418 sizeof(*db_objs)); 419 if (res) 420 TEE_Panic(0); 421 422 res = TEE_SeekObjectData(db_hdl, sizeof(*db_main), 423 TEE_DATA_SEEK_SET); 424 if (res) 425 TEE_Panic(0); 426 427 db_objs->count = 0; 428 res = TEE_WriteObjectData(db_hdl, db_objs, sizeof(*db_objs)); 429 if (res) 430 TEE_Panic(0); 431 432 } else { 433 goto error; 434 } 435 436 token->db_main = db_main; 437 token->db_objs = db_objs; 438 TEE_CloseObject(db_hdl); 439 440 return token; 441 442 error: 443 TEE_Free(db_main); 444 TEE_Free(db_objs); 445 if (db_hdl != TEE_HANDLE_NULL) 446 TEE_CloseObject(db_hdl); 447 448 return NULL; 449 } 450