xref: /optee_os/ta/pkcs11/src/persistent_token.c (revision fa1ac7676f39a86a2a56b707a20fff43f095d685)
1c84ccd0aSEtienne Carriere // SPDX-License-Identifier: BSD-2-Clause
2c84ccd0aSEtienne Carriere /*
3c84ccd0aSEtienne Carriere  * Copyright (c) 2018-2020, Linaro Limited
4c84ccd0aSEtienne Carriere  */
5c84ccd0aSEtienne Carriere 
6c84ccd0aSEtienne Carriere #include <assert.h>
7c84ccd0aSEtienne Carriere #include <pkcs11_ta.h>
8c84ccd0aSEtienne Carriere #include <string.h>
9c84ccd0aSEtienne Carriere #include <string_ext.h>
10c84ccd0aSEtienne Carriere #include <tee_internal_api_extensions.h>
11c84ccd0aSEtienne Carriere #include <util.h>
12c84ccd0aSEtienne Carriere 
13c84ccd0aSEtienne Carriere #include "pkcs11_token.h"
14c84ccd0aSEtienne Carriere #include "pkcs11_helpers.h"
15c84ccd0aSEtienne Carriere 
1660659a86SEtienne Carriere #define PERSISTENT_OBJECT_ID_LEN	32
1760659a86SEtienne Carriere 
1860659a86SEtienne Carriere /*
1960659a86SEtienne Carriere  * Token persistent objects
20334316feSJens Wiklander  *
21334316feSJens Wiklander  * The persistent objects are each identified by a UUID.
22334316feSJens Wiklander  * The persistent object database stores the list of the UUIDs registered. For
23334316feSJens Wiklander  * each it is expected that a file of ID "UUID" is stored in the TA secure
24334316feSJens Wiklander  * storage.
2560659a86SEtienne Carriere  */
2660659a86SEtienne Carriere static TEE_Result get_db_file_name(struct ck_token *token,
2760659a86SEtienne Carriere 				   char *name, size_t size)
28c84ccd0aSEtienne Carriere {
2960659a86SEtienne Carriere 	int n = snprintf(name, size, "token.db.%u", get_token_id(token));
3060659a86SEtienne Carriere 
3160659a86SEtienne Carriere 	if (n < 0 || (size_t)n >= size)
3260659a86SEtienne Carriere 		return TEE_ERROR_SECURITY;
3360659a86SEtienne Carriere 	else
3460659a86SEtienne Carriere 		return TEE_SUCCESS;
3560659a86SEtienne Carriere }
3660659a86SEtienne Carriere 
3760659a86SEtienne Carriere static TEE_Result open_db_file(struct ck_token *token,
3860659a86SEtienne Carriere 			       TEE_ObjectHandle *out_hdl)
3960659a86SEtienne Carriere {
4060659a86SEtienne Carriere 	char file[PERSISTENT_OBJECT_ID_LEN] = { };
4160659a86SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
4260659a86SEtienne Carriere 
4360659a86SEtienne Carriere 	res = get_db_file_name(token, file, sizeof(file));
4460659a86SEtienne Carriere 	if (res)
4560659a86SEtienne Carriere 		return res;
4660659a86SEtienne Carriere 
4760659a86SEtienne Carriere 	return TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, file, sizeof(file),
4860659a86SEtienne Carriere 					TEE_DATA_FLAG_ACCESS_READ |
4960659a86SEtienne Carriere 					TEE_DATA_FLAG_ACCESS_WRITE,
5060659a86SEtienne Carriere 					out_hdl);
5160659a86SEtienne Carriere }
5260659a86SEtienne Carriere 
53e86828f4SJens Wiklander void update_persistent_db(struct ck_token *token)
54e86828f4SJens Wiklander {
55e86828f4SJens Wiklander 	TEE_Result res = TEE_ERROR_GENERIC;
56e86828f4SJens Wiklander 	TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL;
57e86828f4SJens Wiklander 
58e86828f4SJens Wiklander 	res = open_db_file(token, &db_hdl);
59e86828f4SJens Wiklander 	if (res) {
60e86828f4SJens Wiklander 		EMSG("Failed to open token persistent db: %#"PRIx32, res);
61e86828f4SJens Wiklander 		TEE_Panic(0);
62e86828f4SJens Wiklander 	}
63e86828f4SJens Wiklander 	res = TEE_WriteObjectData(db_hdl, token->db_main,
64e86828f4SJens Wiklander 				  sizeof(*token->db_main));
65e86828f4SJens Wiklander 	if (res) {
66e86828f4SJens Wiklander 		EMSG("Failed to write to token persistent db: %#"PRIx32, res);
67e86828f4SJens Wiklander 		TEE_Panic(0);
68e86828f4SJens Wiklander 	}
69e86828f4SJens Wiklander 
70e86828f4SJens Wiklander 	TEE_CloseObject(db_hdl);
71e86828f4SJens Wiklander }
72e86828f4SJens Wiklander 
73bef8bc68SJens Wiklander static enum pkcs11_rc do_hash(uint32_t user, const uint8_t *pin,
74bef8bc68SJens Wiklander 			      size_t pin_size, uint32_t salt,
75bef8bc68SJens Wiklander 			      uint8_t hash[TEE_MAX_HASH_SIZE])
76bef8bc68SJens Wiklander {
77bef8bc68SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
78bef8bc68SJens Wiklander 	TEE_OperationHandle oh = TEE_HANDLE_NULL;
79bef8bc68SJens Wiklander 	uint32_t sz = TEE_MAX_HASH_SIZE;
80bef8bc68SJens Wiklander 
81bef8bc68SJens Wiklander 	res = TEE_AllocateOperation(&oh, TEE_ALG_SHA256, TEE_MODE_DIGEST, 0);
82bef8bc68SJens Wiklander 	if (res)
83bef8bc68SJens Wiklander 		return tee2pkcs_error(res);
84bef8bc68SJens Wiklander 
85bef8bc68SJens Wiklander 	TEE_DigestUpdate(oh, &user, sizeof(user));
86bef8bc68SJens Wiklander 	TEE_DigestUpdate(oh, &salt, sizeof(salt));
87bef8bc68SJens Wiklander 	res = TEE_DigestDoFinal(oh, pin, pin_size, hash, &sz);
88bef8bc68SJens Wiklander 	TEE_FreeOperation(oh);
89bef8bc68SJens Wiklander 
90bef8bc68SJens Wiklander 	if (res)
91bef8bc68SJens Wiklander 		return PKCS11_CKR_GENERAL_ERROR;
92bef8bc68SJens Wiklander 
93bef8bc68SJens Wiklander 	memset(hash + sz, 0, TEE_MAX_HASH_SIZE - sz);
94bef8bc68SJens Wiklander 	return PKCS11_CKR_OK;
95bef8bc68SJens Wiklander }
96bef8bc68SJens Wiklander 
97bef8bc68SJens Wiklander enum pkcs11_rc hash_pin(enum pkcs11_user_type user, const uint8_t *pin,
98bef8bc68SJens Wiklander 			size_t pin_size, uint32_t *salt,
99bef8bc68SJens Wiklander 			uint8_t hash[TEE_MAX_HASH_SIZE])
100bef8bc68SJens Wiklander {
101bef8bc68SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
102bef8bc68SJens Wiklander 	uint32_t s = 0;
103bef8bc68SJens Wiklander 
104bef8bc68SJens Wiklander 	TEE_GenerateRandom(&s, sizeof(s));
105bef8bc68SJens Wiklander 	if (!s)
106bef8bc68SJens Wiklander 		s++;
107bef8bc68SJens Wiklander 
108bef8bc68SJens Wiklander 	rc = do_hash(user, pin, pin_size, s, hash);
109bef8bc68SJens Wiklander 	if (!rc)
110bef8bc68SJens Wiklander 		*salt = s;
111bef8bc68SJens Wiklander 	return rc;
112bef8bc68SJens Wiklander }
113bef8bc68SJens Wiklander 
114bef8bc68SJens Wiklander enum pkcs11_rc verify_pin(enum pkcs11_user_type user, const uint8_t *pin,
115bef8bc68SJens Wiklander 			  size_t pin_size, uint32_t salt,
116bef8bc68SJens Wiklander 			  const uint8_t hash[TEE_MAX_HASH_SIZE])
117bef8bc68SJens Wiklander {
118bef8bc68SJens Wiklander 	uint8_t tmp_hash[TEE_MAX_HASH_SIZE] = { 0 };
119bef8bc68SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
120bef8bc68SJens Wiklander 
121bef8bc68SJens Wiklander 	rc = do_hash(user, pin, pin_size, salt, tmp_hash);
122bef8bc68SJens Wiklander 	if (rc)
123bef8bc68SJens Wiklander 		return rc;
124bef8bc68SJens Wiklander 
125bef8bc68SJens Wiklander 	if (buf_compare_ct(tmp_hash, hash, TEE_MAX_HASH_SIZE))
126bef8bc68SJens Wiklander 		rc = PKCS11_CKR_PIN_INCORRECT;
127bef8bc68SJens Wiklander 
128bef8bc68SJens Wiklander 	return rc;
129bef8bc68SJens Wiklander }
130bef8bc68SJens Wiklander 
1311a27b197SVesa Jääskeläinen #if defined(CFG_PKCS11_TA_AUTH_TEE_IDENTITY)
1321a27b197SVesa Jääskeläinen enum pkcs11_rc setup_so_identity_auth_from_client(struct ck_token *token)
1331a27b197SVesa Jääskeläinen {
1341a27b197SVesa Jääskeläinen 	TEE_Identity identity = { };
1351a27b197SVesa Jääskeläinen 	TEE_Result res = TEE_SUCCESS;
1361a27b197SVesa Jääskeläinen 
1371a27b197SVesa Jääskeläinen 	res = TEE_GetPropertyAsIdentity(TEE_PROPSET_CURRENT_CLIENT,
1381a27b197SVesa Jääskeläinen 					"gpd.client.identity", &identity);
1391a27b197SVesa Jääskeläinen 	if (res != TEE_SUCCESS) {
1401a27b197SVesa Jääskeläinen 		EMSG("TEE_GetPropertyAsIdentity: returned %#"PRIx32, res);
1411a27b197SVesa Jääskeläinen 		return PKCS11_CKR_PIN_INVALID;
1421a27b197SVesa Jääskeläinen 	}
1431a27b197SVesa Jääskeläinen 
1441a27b197SVesa Jääskeläinen 	TEE_MemMove(&token->db_main->so_identity, &identity, sizeof(identity));
1451a27b197SVesa Jääskeläinen 	token->db_main->flags |= PKCS11_CKFT_PROTECTED_AUTHENTICATION_PATH;
1461a27b197SVesa Jääskeläinen 
1471a27b197SVesa Jääskeläinen 	token->db_main->so_pin_salt = 0;
1481a27b197SVesa Jääskeläinen 
1491a27b197SVesa Jääskeläinen 	return PKCS11_CKR_OK;
1501a27b197SVesa Jääskeläinen }
1511a27b197SVesa Jääskeläinen 
1521a27b197SVesa Jääskeläinen enum pkcs11_rc setup_identity_auth_from_pin(struct ck_token *token,
1531a27b197SVesa Jääskeläinen 					    enum pkcs11_user_type user_type,
1541a27b197SVesa Jääskeläinen 					    const uint8_t *pin,
1551a27b197SVesa Jääskeläinen 					    size_t pin_size)
1561a27b197SVesa Jääskeläinen {
1571a27b197SVesa Jääskeläinen 	TEE_Identity identity = { };
1581a27b197SVesa Jääskeläinen 	TEE_Result res = TEE_SUCCESS;
1591a27b197SVesa Jääskeläinen 	uint32_t flags_clear = 0;
1601a27b197SVesa Jääskeläinen 	uint32_t flags_set = 0;
1611a27b197SVesa Jääskeläinen 	char *acl_string = NULL;
1621a27b197SVesa Jääskeläinen 	char *uuid_str = NULL;
1631a27b197SVesa Jääskeläinen 
1641a27b197SVesa Jääskeläinen 	assert(token->db_main->flags &
1651a27b197SVesa Jääskeläinen 	       PKCS11_CKFT_PROTECTED_AUTHENTICATION_PATH);
1661a27b197SVesa Jääskeläinen 
1671a27b197SVesa Jääskeläinen 	if (!pin) {
1681a27b197SVesa Jääskeläinen 		/* Use client identity */
1691a27b197SVesa Jääskeläinen 		res = TEE_GetPropertyAsIdentity(TEE_PROPSET_CURRENT_CLIENT,
1701a27b197SVesa Jääskeläinen 						"gpd.client.identity",
1711a27b197SVesa Jääskeläinen 						&identity);
1721a27b197SVesa Jääskeläinen 		if (res != TEE_SUCCESS) {
1731a27b197SVesa Jääskeläinen 			EMSG("TEE_GetPropertyAsIdentity: returned %#"PRIx32,
1741a27b197SVesa Jääskeläinen 			     res);
1751a27b197SVesa Jääskeläinen 			return PKCS11_CKR_PIN_INVALID;
1761a27b197SVesa Jääskeläinen 		}
1771a27b197SVesa Jääskeläinen 	} else {
1781a27b197SVesa Jääskeläinen 		/* Parse PIN ACL string: <login type>:<client id> */
1791a27b197SVesa Jääskeläinen 		acl_string = TEE_Malloc(pin_size + 1, TEE_MALLOC_FILL_ZERO);
1801a27b197SVesa Jääskeläinen 		if (!acl_string)
1811a27b197SVesa Jääskeläinen 			return PKCS11_CKR_DEVICE_MEMORY;
1821a27b197SVesa Jääskeläinen 		TEE_MemMove(acl_string, pin, pin_size);
1831a27b197SVesa Jääskeläinen 
1841a27b197SVesa Jääskeläinen 		uuid_str = strstr(acl_string, ":");
1851a27b197SVesa Jääskeläinen 		if (uuid_str)
1861a27b197SVesa Jääskeläinen 			uuid_str++;
1871a27b197SVesa Jääskeläinen 		if (strcmp(PKCS11_AUTH_TEE_IDENTITY_PUBLIC, acl_string) == 0) {
1881a27b197SVesa Jääskeläinen 			identity.login = TEE_LOGIN_PUBLIC;
1891a27b197SVesa Jääskeläinen 		} else if (strstr(acl_string, PKCS11_AUTH_TEE_IDENTITY_USER) ==
1901a27b197SVesa Jääskeläinen 			   acl_string) {
1911a27b197SVesa Jääskeläinen 			identity.login = TEE_LOGIN_USER;
1921a27b197SVesa Jääskeläinen 		} else if (strstr(acl_string, PKCS11_AUTH_TEE_IDENTITY_GROUP) ==
1931a27b197SVesa Jääskeläinen 			   acl_string) {
1941a27b197SVesa Jääskeläinen 			identity.login = TEE_LOGIN_GROUP;
1951a27b197SVesa Jääskeläinen 		} else {
1961a27b197SVesa Jääskeläinen 			EMSG("Invalid PIN ACL string - login");
1971a27b197SVesa Jääskeläinen 			TEE_Free(acl_string);
1981a27b197SVesa Jääskeläinen 			return PKCS11_CKR_PIN_INVALID;
1991a27b197SVesa Jääskeläinen 		}
2001a27b197SVesa Jääskeläinen 
2011a27b197SVesa Jääskeläinen 		if (identity.login != TEE_LOGIN_PUBLIC) {
2021a27b197SVesa Jääskeläinen 			if (!uuid_str) {
2031a27b197SVesa Jääskeläinen 				EMSG("Invalid PIN ACL string - colon");
2041a27b197SVesa Jääskeläinen 				TEE_Free(acl_string);
2051a27b197SVesa Jääskeläinen 				return PKCS11_CKR_PIN_INVALID;
2061a27b197SVesa Jääskeläinen 			}
2071a27b197SVesa Jääskeläinen 
2081a27b197SVesa Jääskeläinen 			res = tee_uuid_from_str(&identity.uuid, uuid_str);
2091a27b197SVesa Jääskeläinen 			if (res) {
2101a27b197SVesa Jääskeläinen 				EMSG("Invalid PIN ACL string - client id");
2111a27b197SVesa Jääskeläinen 				TEE_Free(acl_string);
2121a27b197SVesa Jääskeläinen 				return PKCS11_CKR_PIN_INVALID;
2131a27b197SVesa Jääskeläinen 			}
2141a27b197SVesa Jääskeläinen 		}
2151a27b197SVesa Jääskeläinen 
2161a27b197SVesa Jääskeläinen 		TEE_Free(acl_string);
2171a27b197SVesa Jääskeläinen 	}
2181a27b197SVesa Jääskeläinen 
2191a27b197SVesa Jääskeläinen 	switch (user_type) {
2201a27b197SVesa Jääskeläinen 	case PKCS11_CKU_SO:
2211a27b197SVesa Jääskeläinen 		token->db_main->so_pin_count = 0;
2221a27b197SVesa Jääskeläinen 		token->db_main->so_pin_salt = 0;
2231a27b197SVesa Jääskeläinen 		flags_clear = PKCS11_CKFT_SO_PIN_COUNT_LOW |
2241a27b197SVesa Jääskeläinen 			      PKCS11_CKFT_SO_PIN_FINAL_TRY |
2251a27b197SVesa Jääskeläinen 			      PKCS11_CKFT_SO_PIN_LOCKED |
2261a27b197SVesa Jääskeläinen 			      PKCS11_CKFT_SO_PIN_TO_BE_CHANGED;
2271a27b197SVesa Jääskeläinen 
2281a27b197SVesa Jääskeläinen 		TEE_MemMove(&token->db_main->so_identity, &identity,
2291a27b197SVesa Jääskeläinen 			    sizeof(identity));
2301a27b197SVesa Jääskeläinen 		break;
2311a27b197SVesa Jääskeläinen 	case PKCS11_CKU_USER:
2321a27b197SVesa Jääskeläinen 		token->db_main->user_pin_count = 0;
2331a27b197SVesa Jääskeläinen 		token->db_main->user_pin_salt = 0;
2341a27b197SVesa Jääskeläinen 		flags_clear = PKCS11_CKFT_USER_PIN_COUNT_LOW |
2351a27b197SVesa Jääskeläinen 			      PKCS11_CKFT_USER_PIN_FINAL_TRY |
2361a27b197SVesa Jääskeläinen 			      PKCS11_CKFT_USER_PIN_LOCKED |
2371a27b197SVesa Jääskeläinen 			      PKCS11_CKFT_USER_PIN_TO_BE_CHANGED;
2381a27b197SVesa Jääskeläinen 		flags_set = PKCS11_CKFT_USER_PIN_INITIALIZED;
2391a27b197SVesa Jääskeläinen 
2401a27b197SVesa Jääskeläinen 		TEE_MemMove(&token->db_main->user_identity, &identity,
2411a27b197SVesa Jääskeläinen 			    sizeof(identity));
2421a27b197SVesa Jääskeläinen 		break;
2431a27b197SVesa Jääskeläinen 	default:
2441a27b197SVesa Jääskeläinen 		return PKCS11_CKR_FUNCTION_FAILED;
2451a27b197SVesa Jääskeläinen 	}
2461a27b197SVesa Jääskeläinen 
2471a27b197SVesa Jääskeläinen 	token->db_main->flags &= ~flags_clear;
2481a27b197SVesa Jääskeläinen 	token->db_main->flags |= flags_set;
2491a27b197SVesa Jääskeläinen 
2501a27b197SVesa Jääskeläinen 	return PKCS11_CKR_OK;
2511a27b197SVesa Jääskeläinen }
2521a27b197SVesa Jääskeläinen 
2531a27b197SVesa Jääskeläinen enum pkcs11_rc verify_identity_auth(struct ck_token *token,
2541a27b197SVesa Jääskeläinen 				    enum pkcs11_user_type user_type)
2551a27b197SVesa Jääskeläinen {
2561a27b197SVesa Jääskeläinen 	TEE_Identity identity = { };
2571a27b197SVesa Jääskeläinen 	TEE_Result res = TEE_SUCCESS;
2581a27b197SVesa Jääskeläinen 
2591a27b197SVesa Jääskeläinen 	assert(token->db_main->flags &
2601a27b197SVesa Jääskeläinen 	       PKCS11_CKFT_PROTECTED_AUTHENTICATION_PATH);
2611a27b197SVesa Jääskeläinen 
2621a27b197SVesa Jääskeläinen 	res = TEE_GetPropertyAsIdentity(TEE_PROPSET_CURRENT_CLIENT,
2631a27b197SVesa Jääskeläinen 					"gpd.client.identity", &identity);
2641a27b197SVesa Jääskeläinen 	if (res != TEE_SUCCESS) {
2651a27b197SVesa Jääskeläinen 		EMSG("TEE_GetPropertyAsIdentity: returned %#"PRIx32, res);
2661a27b197SVesa Jääskeläinen 		return PKCS11_CKR_PIN_INVALID;
2671a27b197SVesa Jääskeläinen 	}
2681a27b197SVesa Jääskeläinen 
2691a27b197SVesa Jääskeläinen 	if (user_type == PKCS11_CKU_SO) {
2701a27b197SVesa Jääskeläinen 		if (TEE_MemCompare(&token->db_main->so_identity, &identity,
2711a27b197SVesa Jääskeläinen 				   sizeof(identity)))
2721a27b197SVesa Jääskeläinen 			return PKCS11_CKR_PIN_INCORRECT;
2731a27b197SVesa Jääskeläinen 	} else if (user_type == PKCS11_CKU_USER) {
2741a27b197SVesa Jääskeläinen 		if (TEE_MemCompare(&token->db_main->user_identity, &identity,
2751a27b197SVesa Jääskeläinen 				   sizeof(identity)))
2761a27b197SVesa Jääskeläinen 			return PKCS11_CKR_PIN_INCORRECT;
2771a27b197SVesa Jääskeläinen 	} else {
2781a27b197SVesa Jääskeläinen 		return PKCS11_CKR_PIN_INCORRECT;
2791a27b197SVesa Jääskeläinen 	}
2801a27b197SVesa Jääskeläinen 
2811a27b197SVesa Jääskeläinen 	return PKCS11_CKR_OK;
2821a27b197SVesa Jääskeläinen }
2831a27b197SVesa Jääskeläinen #endif /* CFG_PKCS11_TA_AUTH_TEE_IDENTITY */
2841a27b197SVesa Jääskeläinen 
285c84ccd0aSEtienne Carriere /*
28660659a86SEtienne Carriere  * Release resources relate to persistent database
28760659a86SEtienne Carriere  */
28860659a86SEtienne Carriere void close_persistent_db(struct ck_token *token __unused)
28960659a86SEtienne Carriere {
29060659a86SEtienne Carriere }
29160659a86SEtienne Carriere 
292334316feSJens Wiklander static int get_persistent_obj_idx(struct ck_token *token, TEE_UUID *uuid)
293334316feSJens Wiklander {
294334316feSJens Wiklander 	size_t i = 0;
295334316feSJens Wiklander 
296334316feSJens Wiklander 	if (!uuid)
297334316feSJens Wiklander 		return -1;
298334316feSJens Wiklander 
299334316feSJens Wiklander 	for (i = 0; i < token->db_objs->count; i++)
300334316feSJens Wiklander 		if (!TEE_MemCompare(token->db_objs->uuids + i,
301334316feSJens Wiklander 				    uuid, sizeof(TEE_UUID)))
302334316feSJens Wiklander 			return i;
303334316feSJens Wiklander 
304334316feSJens Wiklander 	return -1;
305334316feSJens Wiklander }
306334316feSJens Wiklander 
307334316feSJens Wiklander /* UUID for persistent object */
308334316feSJens Wiklander enum pkcs11_rc create_object_uuid(struct ck_token *token,
309334316feSJens Wiklander 				  struct pkcs11_object *obj)
310334316feSJens Wiklander {
311334316feSJens Wiklander 	assert(!obj->uuid);
312334316feSJens Wiklander 
313334316feSJens Wiklander 	obj->uuid = TEE_Malloc(sizeof(TEE_UUID),
314334316feSJens Wiklander 			       TEE_USER_MEM_HINT_NO_FILL_ZERO);
315334316feSJens Wiklander 	if (!obj->uuid)
316334316feSJens Wiklander 		return PKCS11_CKR_DEVICE_MEMORY;
317334316feSJens Wiklander 
318334316feSJens Wiklander 	do {
319334316feSJens Wiklander 		TEE_GenerateRandom(obj->uuid, sizeof(TEE_UUID));
320334316feSJens Wiklander 	} while (get_persistent_obj_idx(token, obj->uuid) >= 0);
321334316feSJens Wiklander 
322334316feSJens Wiklander 	return PKCS11_CKR_OK;
323334316feSJens Wiklander }
324334316feSJens Wiklander 
325334316feSJens Wiklander void destroy_object_uuid(struct ck_token *token __maybe_unused,
326334316feSJens Wiklander 			 struct pkcs11_object *obj)
327334316feSJens Wiklander {
328334316feSJens Wiklander 	assert(get_persistent_obj_idx(token, obj->uuid) < 0);
329334316feSJens Wiklander 
330334316feSJens Wiklander 	TEE_Free(obj->uuid);
331334316feSJens Wiklander 	obj->uuid = NULL;
332334316feSJens Wiklander }
333334316feSJens Wiklander 
334334316feSJens Wiklander enum pkcs11_rc get_persistent_objects_list(struct ck_token *token,
335334316feSJens Wiklander 					   TEE_UUID *array, size_t *size)
336334316feSJens Wiklander {
337334316feSJens Wiklander 	size_t out_size = *size;
338334316feSJens Wiklander 
339334316feSJens Wiklander 	*size = token->db_objs->count * sizeof(TEE_UUID);
340334316feSJens Wiklander 
341334316feSJens Wiklander 	if (out_size < *size)
342334316feSJens Wiklander 		return PKCS11_CKR_BUFFER_TOO_SMALL;
343334316feSJens Wiklander 
344334316feSJens Wiklander 	if (array)
345334316feSJens Wiklander 		TEE_MemMove(array, token->db_objs->uuids, *size);
346334316feSJens Wiklander 
347334316feSJens Wiklander 	return PKCS11_CKR_OK;
348334316feSJens Wiklander }
349334316feSJens Wiklander 
350334316feSJens Wiklander enum pkcs11_rc unregister_persistent_object(struct ck_token *token,
351334316feSJens Wiklander 					    TEE_UUID *uuid)
352334316feSJens Wiklander {
353334316feSJens Wiklander 	TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL;
354334316feSJens Wiklander 	struct token_persistent_objs *ptr = NULL;
355334316feSJens Wiklander 	TEE_Result res = TEE_ERROR_GENERIC;
356334316feSJens Wiklander 	int count = 0;
357334316feSJens Wiklander 	int idx = 0;
358334316feSJens Wiklander 
359334316feSJens Wiklander 	if (!uuid)
360334316feSJens Wiklander 		return PKCS11_CKR_OK;
361334316feSJens Wiklander 
362334316feSJens Wiklander 	idx = get_persistent_obj_idx(token, uuid);
363334316feSJens Wiklander 	if (idx < 0) {
364334316feSJens Wiklander 		DMSG("Cannot unregister an invalid persistent object");
365334316feSJens Wiklander 		return PKCS11_RV_NOT_FOUND;
366334316feSJens Wiklander 	}
367334316feSJens Wiklander 
368334316feSJens Wiklander 	ptr = TEE_Malloc(sizeof(struct token_persistent_objs) +
369334316feSJens Wiklander 			 ((token->db_objs->count - 1) * sizeof(TEE_UUID)),
370334316feSJens Wiklander 			 TEE_USER_MEM_HINT_NO_FILL_ZERO);
371334316feSJens Wiklander 	if (!ptr)
372334316feSJens Wiklander 		return PKCS11_CKR_DEVICE_MEMORY;
373334316feSJens Wiklander 
374334316feSJens Wiklander 	res = open_db_file(token, &db_hdl);
375334316feSJens Wiklander 	if (res)
376334316feSJens Wiklander 		goto out;
377334316feSJens Wiklander 
378334316feSJens Wiklander 	res = TEE_SeekObjectData(db_hdl, sizeof(struct token_persistent_main),
379334316feSJens Wiklander 				 TEE_DATA_SEEK_SET);
380334316feSJens Wiklander 	if (res) {
381334316feSJens Wiklander 		DMSG("Failed to read database");
382334316feSJens Wiklander 		goto out;
383334316feSJens Wiklander 	}
384334316feSJens Wiklander 
385334316feSJens Wiklander 	TEE_MemMove(ptr, token->db_objs,
386334316feSJens Wiklander 		    sizeof(struct token_persistent_objs) +
387334316feSJens Wiklander 		    idx * sizeof(TEE_UUID));
388334316feSJens Wiklander 
389334316feSJens Wiklander 	ptr->count--;
390334316feSJens Wiklander 	count = ptr->count - idx;
391334316feSJens Wiklander 
392334316feSJens Wiklander 	TEE_MemMove(&ptr->uuids[idx],
393334316feSJens Wiklander 		    &token->db_objs->uuids[idx + 1],
394334316feSJens Wiklander 		    count * sizeof(TEE_UUID));
395334316feSJens Wiklander 
396334316feSJens Wiklander 	res = TEE_WriteObjectData(db_hdl, ptr,
397334316feSJens Wiklander 				  sizeof(struct token_persistent_objs) +
398334316feSJens Wiklander 				  ptr->count * sizeof(TEE_UUID));
399334316feSJens Wiklander 	if (res)
400334316feSJens Wiklander 		DMSG("Failed to update database");
401334316feSJens Wiklander 	TEE_Free(token->db_objs);
402334316feSJens Wiklander 	token->db_objs = ptr;
403334316feSJens Wiklander 	ptr = NULL;
404334316feSJens Wiklander 
405334316feSJens Wiklander out:
406334316feSJens Wiklander 	TEE_CloseObject(db_hdl);
407334316feSJens Wiklander 	TEE_Free(ptr);
408334316feSJens Wiklander 
409334316feSJens Wiklander 	return tee2pkcs_error(res);
410334316feSJens Wiklander }
411334316feSJens Wiklander 
412334316feSJens Wiklander enum pkcs11_rc register_persistent_object(struct ck_token *token,
413334316feSJens Wiklander 					  TEE_UUID *uuid)
414334316feSJens Wiklander {
415334316feSJens Wiklander 	TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL;
416334316feSJens Wiklander 	TEE_Result res = TEE_ERROR_GENERIC;
417334316feSJens Wiklander 	void *ptr = NULL;
418334316feSJens Wiklander 	size_t size = 0;
419334316feSJens Wiklander 	int count = 0;
420334316feSJens Wiklander 
421334316feSJens Wiklander 	if (get_persistent_obj_idx(token, uuid) >= 0)
422334316feSJens Wiklander 		TEE_Panic(0);
423334316feSJens Wiklander 
424334316feSJens Wiklander 	count = token->db_objs->count;
425334316feSJens Wiklander 	ptr = TEE_Realloc(token->db_objs,
426334316feSJens Wiklander 			  sizeof(struct token_persistent_objs) +
427334316feSJens Wiklander 			  ((count + 1) * sizeof(TEE_UUID)));
428334316feSJens Wiklander 	if (!ptr)
429334316feSJens Wiklander 		return PKCS11_CKR_DEVICE_MEMORY;
430334316feSJens Wiklander 
431334316feSJens Wiklander 	token->db_objs = ptr;
432334316feSJens Wiklander 	TEE_MemMove(token->db_objs->uuids + count, uuid, sizeof(TEE_UUID));
433334316feSJens Wiklander 
434334316feSJens Wiklander 	size = sizeof(struct token_persistent_main) +
435334316feSJens Wiklander 	       sizeof(struct token_persistent_objs) +
436334316feSJens Wiklander 	       count * sizeof(TEE_UUID);
437334316feSJens Wiklander 
438334316feSJens Wiklander 	res = open_db_file(token, &db_hdl);
439334316feSJens Wiklander 	if (res)
440334316feSJens Wiklander 		goto out;
441334316feSJens Wiklander 
442334316feSJens Wiklander 	res = TEE_TruncateObjectData(db_hdl, size + sizeof(TEE_UUID));
443334316feSJens Wiklander 	if (res)
444334316feSJens Wiklander 		goto out;
445334316feSJens Wiklander 
446334316feSJens Wiklander 	res = TEE_SeekObjectData(db_hdl, sizeof(struct token_persistent_main),
447334316feSJens Wiklander 				 TEE_DATA_SEEK_SET);
448334316feSJens Wiklander 	if (res)
449334316feSJens Wiklander 		goto out;
450334316feSJens Wiklander 
451334316feSJens Wiklander 	token->db_objs->count++;
452334316feSJens Wiklander 
453334316feSJens Wiklander 	res = TEE_WriteObjectData(db_hdl, token->db_objs,
454334316feSJens Wiklander 				  sizeof(struct token_persistent_objs) +
455334316feSJens Wiklander 				  token->db_objs->count * sizeof(TEE_UUID));
456334316feSJens Wiklander 	if (res)
457334316feSJens Wiklander 		token->db_objs->count--;
458334316feSJens Wiklander 
459334316feSJens Wiklander out:
460334316feSJens Wiklander 	TEE_CloseObject(db_hdl);
461334316feSJens Wiklander 
462334316feSJens Wiklander 	return tee2pkcs_error(res);
463334316feSJens Wiklander }
464334316feSJens Wiklander 
465*fa1ac767SRobin van der Gracht enum pkcs11_rc load_persistent_object_attributes(struct pkcs11_object *obj)
466*fa1ac767SRobin van der Gracht {
467*fa1ac767SRobin van der Gracht 	enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
468*fa1ac767SRobin van der Gracht 	TEE_Result res = TEE_ERROR_GENERIC;
469*fa1ac767SRobin van der Gracht 	TEE_ObjectHandle hdl = obj->attribs_hdl;
470*fa1ac767SRobin van der Gracht 	TEE_ObjectInfo info = { };
471*fa1ac767SRobin van der Gracht 	struct obj_attrs *attr = NULL;
472*fa1ac767SRobin van der Gracht 	uint32_t read_bytes = 0;
473*fa1ac767SRobin van der Gracht 
474*fa1ac767SRobin van der Gracht 	if (obj->attributes)
475*fa1ac767SRobin van der Gracht 		return PKCS11_CKR_OK;
476*fa1ac767SRobin van der Gracht 
477*fa1ac767SRobin van der Gracht 	if (hdl == TEE_HANDLE_NULL) {
478*fa1ac767SRobin van der Gracht 		res = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE,
479*fa1ac767SRobin van der Gracht 					       obj->uuid, sizeof(*obj->uuid),
480*fa1ac767SRobin van der Gracht 					       TEE_DATA_FLAG_ACCESS_READ, &hdl);
481*fa1ac767SRobin van der Gracht 		if (res) {
482*fa1ac767SRobin van der Gracht 			EMSG("OpenPersistent failed %#"PRIx32, res);
483*fa1ac767SRobin van der Gracht 			return tee2pkcs_error(res);
484*fa1ac767SRobin van der Gracht 		}
485*fa1ac767SRobin van der Gracht 	}
486*fa1ac767SRobin van der Gracht 
487*fa1ac767SRobin van der Gracht 	TEE_MemFill(&info, 0, sizeof(info));
488*fa1ac767SRobin van der Gracht 	res = TEE_GetObjectInfo1(hdl, &info);
489*fa1ac767SRobin van der Gracht 	if (res) {
490*fa1ac767SRobin van der Gracht 		EMSG("GetObjectInfo failed %#"PRIx32, res);
491*fa1ac767SRobin van der Gracht 		rc = tee2pkcs_error(res);
492*fa1ac767SRobin van der Gracht 		goto out;
493*fa1ac767SRobin van der Gracht 	}
494*fa1ac767SRobin van der Gracht 
495*fa1ac767SRobin van der Gracht 	attr = TEE_Malloc(info.dataSize, TEE_MALLOC_FILL_ZERO);
496*fa1ac767SRobin van der Gracht 	if (!attr) {
497*fa1ac767SRobin van der Gracht 		rc = PKCS11_CKR_DEVICE_MEMORY;
498*fa1ac767SRobin van der Gracht 		goto out;
499*fa1ac767SRobin van der Gracht 	}
500*fa1ac767SRobin van der Gracht 
501*fa1ac767SRobin van der Gracht 	res = TEE_ReadObjectData(hdl, attr, info.dataSize, &read_bytes);
502*fa1ac767SRobin van der Gracht 	if (!res) {
503*fa1ac767SRobin van der Gracht 		res = TEE_SeekObjectData(hdl, 0, TEE_DATA_SEEK_SET);
504*fa1ac767SRobin van der Gracht 		if (res)
505*fa1ac767SRobin van der Gracht 			EMSG("Seek to 0 failed %#"PRIx32, res);
506*fa1ac767SRobin van der Gracht 	}
507*fa1ac767SRobin van der Gracht 
508*fa1ac767SRobin van der Gracht 	if (res) {
509*fa1ac767SRobin van der Gracht 		rc = tee2pkcs_error(res);
510*fa1ac767SRobin van der Gracht 		EMSG("Read %"PRIu32" bytes, failed %#"PRIx32,
511*fa1ac767SRobin van der Gracht 		     read_bytes, res);
512*fa1ac767SRobin van der Gracht 		goto out;
513*fa1ac767SRobin van der Gracht 	}
514*fa1ac767SRobin van der Gracht 	if (read_bytes != info.dataSize) {
515*fa1ac767SRobin van der Gracht 		EMSG("Read %"PRIu32" bytes, expected %"PRIu32,
516*fa1ac767SRobin van der Gracht 		     read_bytes, info.dataSize);
517*fa1ac767SRobin van der Gracht 		rc = PKCS11_CKR_GENERAL_ERROR;
518*fa1ac767SRobin van der Gracht 		goto out;
519*fa1ac767SRobin van der Gracht 	}
520*fa1ac767SRobin van der Gracht 
521*fa1ac767SRobin van der Gracht 	obj->attributes = attr;
522*fa1ac767SRobin van der Gracht 	attr = NULL;
523*fa1ac767SRobin van der Gracht 
524*fa1ac767SRobin van der Gracht 	rc = PKCS11_CKR_OK;
525*fa1ac767SRobin van der Gracht 
526*fa1ac767SRobin van der Gracht out:
527*fa1ac767SRobin van der Gracht 	TEE_Free(attr);
528*fa1ac767SRobin van der Gracht 	/* Close object only if it was open from this function */
529*fa1ac767SRobin van der Gracht 	if (obj->attribs_hdl == TEE_HANDLE_NULL)
530*fa1ac767SRobin van der Gracht 		TEE_CloseObject(hdl);
531*fa1ac767SRobin van der Gracht 
532*fa1ac767SRobin van der Gracht 	return rc;
533*fa1ac767SRobin van der Gracht }
534*fa1ac767SRobin van der Gracht 
535*fa1ac767SRobin van der Gracht void release_persistent_object_attributes(struct pkcs11_object *obj)
536*fa1ac767SRobin van der Gracht {
537*fa1ac767SRobin van der Gracht 	TEE_Free(obj->attributes);
538*fa1ac767SRobin van der Gracht 	obj->attributes = NULL;
539*fa1ac767SRobin van der Gracht }
540*fa1ac767SRobin van der Gracht 
54160659a86SEtienne Carriere /*
542c84ccd0aSEtienne Carriere  * Return the token instance, either initialized from reset or initialized
543c84ccd0aSEtienne Carriere  * from the token persistent state if found.
544c84ccd0aSEtienne Carriere  */
545c84ccd0aSEtienne Carriere struct ck_token *init_persistent_db(unsigned int token_id)
546c84ccd0aSEtienne Carriere {
547c84ccd0aSEtienne Carriere 	struct ck_token *token = get_token(token_id);
548c84ccd0aSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
549c84ccd0aSEtienne Carriere 	TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL;
55060659a86SEtienne Carriere 	/* Copy persistent database: main db and object db */
551c84ccd0aSEtienne Carriere 	struct token_persistent_main *db_main = NULL;
552334316feSJens Wiklander 	struct token_persistent_objs *db_objs = NULL;
553334316feSJens Wiklander 	void *ptr = NULL;
554c84ccd0aSEtienne Carriere 
555c84ccd0aSEtienne Carriere 	if (!token)
556c84ccd0aSEtienne Carriere 		return NULL;
557c84ccd0aSEtienne Carriere 
558334316feSJens Wiklander 	LIST_INIT(&token->object_list);
559334316feSJens Wiklander 
560c84ccd0aSEtienne Carriere 	db_main = TEE_Malloc(sizeof(*db_main), TEE_MALLOC_FILL_ZERO);
561334316feSJens Wiklander 	db_objs = TEE_Malloc(sizeof(*db_objs), TEE_MALLOC_FILL_ZERO);
562334316feSJens Wiklander 	if (!db_main || !db_objs)
563c84ccd0aSEtienne Carriere 		goto error;
564c84ccd0aSEtienne Carriere 
56560659a86SEtienne Carriere 	res = open_db_file(token, &db_hdl);
566c84ccd0aSEtienne Carriere 
567c84ccd0aSEtienne Carriere 	if (res == TEE_SUCCESS) {
568c84ccd0aSEtienne Carriere 		uint32_t size = 0;
569334316feSJens Wiklander 		size_t idx = 0;
570c84ccd0aSEtienne Carriere 
571c84ccd0aSEtienne Carriere 		IMSG("PKCS11 token %u: load db", token_id);
572c84ccd0aSEtienne Carriere 
573c84ccd0aSEtienne Carriere 		size = sizeof(*db_main);
574c84ccd0aSEtienne Carriere 		res = TEE_ReadObjectData(db_hdl, db_main, size, &size);
575c84ccd0aSEtienne Carriere 		if (res || size != sizeof(*db_main))
576c84ccd0aSEtienne Carriere 			TEE_Panic(0);
577334316feSJens Wiklander 
578334316feSJens Wiklander 		size = sizeof(*db_objs);
579334316feSJens Wiklander 		res = TEE_ReadObjectData(db_hdl, db_objs, size, &size);
580334316feSJens Wiklander 		if (res || size != sizeof(*db_objs))
581334316feSJens Wiklander 			TEE_Panic(0);
582334316feSJens Wiklander 
583974adb9fSRobin van der Gracht 		if (db_objs->count > 0) {
584334316feSJens Wiklander 			size += db_objs->count * sizeof(TEE_UUID);
585334316feSJens Wiklander 			ptr = TEE_Realloc(db_objs, size);
586334316feSJens Wiklander 			if (!ptr)
587334316feSJens Wiklander 				goto error;
588334316feSJens Wiklander 
589334316feSJens Wiklander 			db_objs = ptr;
590a3c511dfSRobin van der Gracht 			size -= sizeof(*db_objs);
591974adb9fSRobin van der Gracht 			res = TEE_ReadObjectData(db_hdl, db_objs->uuids, size,
592974adb9fSRobin van der Gracht 						 &size);
593334316feSJens Wiklander 			if (res || size != (db_objs->count * sizeof(TEE_UUID)))
594334316feSJens Wiklander 				TEE_Panic(0);
595974adb9fSRobin van der Gracht 		}
596334316feSJens Wiklander 
597334316feSJens Wiklander 		for (idx = 0; idx < db_objs->count; idx++) {
598334316feSJens Wiklander 			/* Create an empty object instance */
599334316feSJens Wiklander 			struct pkcs11_object *obj = NULL;
600334316feSJens Wiklander 			TEE_UUID *uuid = NULL;
601334316feSJens Wiklander 
602334316feSJens Wiklander 			uuid = TEE_Malloc(sizeof(TEE_UUID),
603334316feSJens Wiklander 					  TEE_USER_MEM_HINT_NO_FILL_ZERO);
604334316feSJens Wiklander 			if (!uuid)
605334316feSJens Wiklander 				goto error;
606334316feSJens Wiklander 
607334316feSJens Wiklander 			TEE_MemMove(uuid, &db_objs->uuids[idx], sizeof(*uuid));
608334316feSJens Wiklander 
609334316feSJens Wiklander 			obj = create_token_object(NULL, uuid);
610334316feSJens Wiklander 			if (!obj)
611334316feSJens Wiklander 				TEE_Panic(0);
612334316feSJens Wiklander 
613334316feSJens Wiklander 			LIST_INSERT_HEAD(&token->object_list, obj, link);
614334316feSJens Wiklander 		}
615334316feSJens Wiklander 
616c84ccd0aSEtienne Carriere 	} else if (res == TEE_ERROR_ITEM_NOT_FOUND) {
61760659a86SEtienne Carriere 		char file[PERSISTENT_OBJECT_ID_LEN] = { };
61860659a86SEtienne Carriere 
619c84ccd0aSEtienne Carriere 		IMSG("PKCS11 token %u: init db", token_id);
620c84ccd0aSEtienne Carriere 
621c84ccd0aSEtienne Carriere 		TEE_MemFill(db_main, 0, sizeof(*db_main));
622c84ccd0aSEtienne Carriere 		TEE_MemFill(db_main->label, '*', sizeof(db_main->label));
623c84ccd0aSEtienne Carriere 
624c84ccd0aSEtienne Carriere 		db_main->flags = PKCS11_CKFT_SO_PIN_TO_BE_CHANGED |
625c84ccd0aSEtienne Carriere 				 PKCS11_CKFT_USER_PIN_TO_BE_CHANGED |
626c84ccd0aSEtienne Carriere 				 PKCS11_CKFT_RNG |
627c84ccd0aSEtienne Carriere 				 PKCS11_CKFT_DUAL_CRYPTO_OPERATIONS |
628c84ccd0aSEtienne Carriere 				 PKCS11_CKFT_LOGIN_REQUIRED;
629c84ccd0aSEtienne Carriere 
63060659a86SEtienne Carriere 		res = get_db_file_name(token, file, sizeof(file));
63160659a86SEtienne Carriere 		if (res)
63260659a86SEtienne Carriere 			TEE_Panic(0);
63360659a86SEtienne Carriere 
634334316feSJens Wiklander 		/*
635334316feSJens Wiklander 		 * Object stores persistent state + persistent object
636334316feSJens Wiklander 		 * references.
637334316feSJens Wiklander 		 */
638c84ccd0aSEtienne Carriere 		res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE,
63960659a86SEtienne Carriere 						 file, sizeof(file),
640c84ccd0aSEtienne Carriere 						 TEE_DATA_FLAG_ACCESS_READ |
641c84ccd0aSEtienne Carriere 						 TEE_DATA_FLAG_ACCESS_WRITE,
642c84ccd0aSEtienne Carriere 						 TEE_HANDLE_NULL,
643c84ccd0aSEtienne Carriere 						 db_main, sizeof(*db_main),
644c84ccd0aSEtienne Carriere 						 &db_hdl);
645c84ccd0aSEtienne Carriere 		if (res) {
64659a5257eSEtienne Carriere 			EMSG("Failed to create db: %#"PRIx32, res);
647c84ccd0aSEtienne Carriere 			goto error;
648c84ccd0aSEtienne Carriere 		}
649334316feSJens Wiklander 
650334316feSJens Wiklander 		res = TEE_TruncateObjectData(db_hdl, sizeof(*db_main) +
651334316feSJens Wiklander 						     sizeof(*db_objs));
652334316feSJens Wiklander 		if (res)
653334316feSJens Wiklander 			TEE_Panic(0);
654334316feSJens Wiklander 
655334316feSJens Wiklander 		res = TEE_SeekObjectData(db_hdl, sizeof(*db_main),
656334316feSJens Wiklander 					 TEE_DATA_SEEK_SET);
657334316feSJens Wiklander 		if (res)
658334316feSJens Wiklander 			TEE_Panic(0);
659334316feSJens Wiklander 
660334316feSJens Wiklander 		db_objs->count = 0;
661334316feSJens Wiklander 		res = TEE_WriteObjectData(db_hdl, db_objs, sizeof(*db_objs));
662334316feSJens Wiklander 		if (res)
663334316feSJens Wiklander 			TEE_Panic(0);
664334316feSJens Wiklander 
665c84ccd0aSEtienne Carriere 	} else {
666c84ccd0aSEtienne Carriere 		goto error;
667c84ccd0aSEtienne Carriere 	}
668c84ccd0aSEtienne Carriere 
669c84ccd0aSEtienne Carriere 	token->db_main = db_main;
670334316feSJens Wiklander 	token->db_objs = db_objs;
671c84ccd0aSEtienne Carriere 	TEE_CloseObject(db_hdl);
672c84ccd0aSEtienne Carriere 
673c84ccd0aSEtienne Carriere 	return token;
674c84ccd0aSEtienne Carriere 
675c84ccd0aSEtienne Carriere error:
676c84ccd0aSEtienne Carriere 	TEE_Free(db_main);
677334316feSJens Wiklander 	TEE_Free(db_objs);
678c84ccd0aSEtienne Carriere 	if (db_hdl != TEE_HANDLE_NULL)
679c84ccd0aSEtienne Carriere 		TEE_CloseObject(db_hdl);
680c84ccd0aSEtienne Carriere 
681c84ccd0aSEtienne Carriere 	return NULL;
682c84ccd0aSEtienne Carriere }
683