xref: /optee_os/ta/pkcs11/src/persistent_token.c (revision 60659a861d1ddf11469fbae9015894c6a1907305)
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 
16*60659a86SEtienne Carriere #define PERSISTENT_OBJECT_ID_LEN	32
17*60659a86SEtienne Carriere 
18*60659a86SEtienne Carriere /*
19*60659a86SEtienne Carriere  * Token persistent objects
20*60659a86SEtienne Carriere  */
21*60659a86SEtienne Carriere static TEE_Result get_db_file_name(struct ck_token *token,
22*60659a86SEtienne Carriere 				   char *name, size_t size)
23c84ccd0aSEtienne Carriere {
24*60659a86SEtienne Carriere 	int n = snprintf(name, size, "token.db.%u", get_token_id(token));
25*60659a86SEtienne Carriere 
26*60659a86SEtienne Carriere 	if (n < 0 || (size_t)n >= size)
27*60659a86SEtienne Carriere 		return TEE_ERROR_SECURITY;
28*60659a86SEtienne Carriere 	else
29*60659a86SEtienne Carriere 		return TEE_SUCCESS;
30*60659a86SEtienne Carriere }
31*60659a86SEtienne Carriere 
32*60659a86SEtienne Carriere static TEE_Result open_db_file(struct ck_token *token,
33*60659a86SEtienne Carriere 			       TEE_ObjectHandle *out_hdl)
34*60659a86SEtienne Carriere {
35*60659a86SEtienne Carriere 	char file[PERSISTENT_OBJECT_ID_LEN] = { };
36*60659a86SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
37*60659a86SEtienne Carriere 
38*60659a86SEtienne Carriere 	res = get_db_file_name(token, file, sizeof(file));
39*60659a86SEtienne Carriere 	if (res)
40*60659a86SEtienne Carriere 		return res;
41*60659a86SEtienne Carriere 
42*60659a86SEtienne Carriere 	return TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, file, sizeof(file),
43*60659a86SEtienne Carriere 					TEE_DATA_FLAG_ACCESS_READ |
44*60659a86SEtienne Carriere 					TEE_DATA_FLAG_ACCESS_WRITE,
45*60659a86SEtienne Carriere 					out_hdl);
46*60659a86SEtienne Carriere }
47*60659a86SEtienne Carriere 
48*60659a86SEtienne Carriere static TEE_Result get_pin_file_name(struct ck_token *token,
49*60659a86SEtienne Carriere 				    enum pkcs11_user_type user,
50*60659a86SEtienne Carriere 				    char *name, size_t size)
51*60659a86SEtienne Carriere {
52*60659a86SEtienne Carriere 	int n = snprintf(name, size,
53*60659a86SEtienne Carriere 			 "token.db.%u-pin%d", get_token_id(token), user);
54*60659a86SEtienne Carriere 
55*60659a86SEtienne Carriere 	if (n < 0 || (size_t)n >= size)
56*60659a86SEtienne Carriere 		return TEE_ERROR_SECURITY;
57*60659a86SEtienne Carriere 	else
58*60659a86SEtienne Carriere 		return TEE_SUCCESS;
59*60659a86SEtienne Carriere }
60*60659a86SEtienne Carriere 
61*60659a86SEtienne Carriere static TEE_Result open_pin_file(struct ck_token *token,
62*60659a86SEtienne Carriere 				enum pkcs11_user_type user,
63*60659a86SEtienne Carriere 				TEE_ObjectHandle *out_hdl)
64*60659a86SEtienne Carriere {
65*60659a86SEtienne Carriere 	char file[PERSISTENT_OBJECT_ID_LEN] = { };
66*60659a86SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
67*60659a86SEtienne Carriere 
68*60659a86SEtienne Carriere 	res = get_pin_file_name(token, user, file, sizeof(file));
69*60659a86SEtienne Carriere 	if (res)
70*60659a86SEtienne Carriere 		return res;
71*60659a86SEtienne Carriere 
72*60659a86SEtienne Carriere 	return TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, file, sizeof(file),
73*60659a86SEtienne Carriere 					0, out_hdl);
74c84ccd0aSEtienne Carriere }
75c84ccd0aSEtienne Carriere 
76c84ccd0aSEtienne Carriere static void init_pin_keys(struct ck_token *token, unsigned int uid)
77c84ccd0aSEtienne Carriere {
78c84ccd0aSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
79c84ccd0aSEtienne Carriere 	TEE_ObjectHandle key_hdl = TEE_HANDLE_NULL;
80*60659a86SEtienne Carriere 	enum pkcs11_user_type user = uid;
81c84ccd0aSEtienne Carriere 
82*60659a86SEtienne Carriere 	res = open_pin_file(token, user, &key_hdl);
83c84ccd0aSEtienne Carriere 
84*60659a86SEtienne Carriere 	if (res == TEE_SUCCESS)
85*60659a86SEtienne Carriere 		DMSG("PIN key found");
86c84ccd0aSEtienne Carriere 
87c84ccd0aSEtienne Carriere 	if (res == TEE_ERROR_ITEM_NOT_FOUND) {
88c84ccd0aSEtienne Carriere 		TEE_Attribute attr = { };
89c84ccd0aSEtienne Carriere 		TEE_ObjectHandle hdl = TEE_HANDLE_NULL;
90*60659a86SEtienne Carriere 		uint8_t pin_key[16] = { };
91*60659a86SEtienne Carriere 		char file[PERSISTENT_OBJECT_ID_LEN] = { };
92c84ccd0aSEtienne Carriere 
93c84ccd0aSEtienne Carriere 		TEE_MemFill(&attr, 0, sizeof(attr));
94c84ccd0aSEtienne Carriere 
95c84ccd0aSEtienne Carriere 		TEE_GenerateRandom(pin_key, sizeof(pin_key));
96c84ccd0aSEtienne Carriere 		TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE,
97c84ccd0aSEtienne Carriere 				     pin_key, sizeof(pin_key));
98c84ccd0aSEtienne Carriere 
99c84ccd0aSEtienne Carriere 		res = TEE_AllocateTransientObject(TEE_TYPE_AES, 128, &hdl);
100c84ccd0aSEtienne Carriere 		if (res)
101c84ccd0aSEtienne Carriere 			TEE_Panic(0);
102c84ccd0aSEtienne Carriere 
103c84ccd0aSEtienne Carriere 		res = TEE_PopulateTransientObject(hdl, &attr, 1);
104c84ccd0aSEtienne Carriere 		if (res)
105c84ccd0aSEtienne Carriere 			TEE_Panic(0);
106c84ccd0aSEtienne Carriere 
107*60659a86SEtienne Carriere 		res = get_pin_file_name(token, user, file, sizeof(file));
108*60659a86SEtienne Carriere 		if (res)
109*60659a86SEtienne Carriere 			TEE_Panic(0);
110*60659a86SEtienne Carriere 
111c84ccd0aSEtienne Carriere 		res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE,
112c84ccd0aSEtienne Carriere 						 file, sizeof(file), 0, hdl,
113c84ccd0aSEtienne Carriere 						 pin_key, sizeof(pin_key),
114c84ccd0aSEtienne Carriere 						 &key_hdl);
115c84ccd0aSEtienne Carriere 		TEE_CloseObject(hdl);
116c84ccd0aSEtienne Carriere 
117c84ccd0aSEtienne Carriere 		if (res == TEE_SUCCESS)
118*60659a86SEtienne Carriere 			DMSG("Token %u: PIN key created", get_token_id(token));
119c84ccd0aSEtienne Carriere 	}
120c84ccd0aSEtienne Carriere 
121c84ccd0aSEtienne Carriere 	if (res)
122c84ccd0aSEtienne Carriere 		TEE_Panic(res);
123c84ccd0aSEtienne Carriere 
124c84ccd0aSEtienne Carriere 	TEE_CloseObject(key_hdl);
125c84ccd0aSEtienne Carriere }
126c84ccd0aSEtienne Carriere 
127c84ccd0aSEtienne Carriere /*
128*60659a86SEtienne Carriere  * Release resources relate to persistent database
129*60659a86SEtienne Carriere  */
130*60659a86SEtienne Carriere void close_persistent_db(struct ck_token *token __unused)
131*60659a86SEtienne Carriere {
132*60659a86SEtienne Carriere }
133*60659a86SEtienne Carriere 
134*60659a86SEtienne Carriere /*
135c84ccd0aSEtienne Carriere  * Return the token instance, either initialized from reset or initialized
136c84ccd0aSEtienne Carriere  * from the token persistent state if found.
137c84ccd0aSEtienne Carriere  */
138c84ccd0aSEtienne Carriere struct ck_token *init_persistent_db(unsigned int token_id)
139c84ccd0aSEtienne Carriere {
140c84ccd0aSEtienne Carriere 	struct ck_token *token = get_token(token_id);
141c84ccd0aSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
142c84ccd0aSEtienne Carriere 	TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL;
143*60659a86SEtienne Carriere 	/* Copy persistent database: main db and object db */
144c84ccd0aSEtienne Carriere 	struct token_persistent_main *db_main = NULL;
145c84ccd0aSEtienne Carriere 
146c84ccd0aSEtienne Carriere 	if (!token)
147c84ccd0aSEtienne Carriere 		return NULL;
148c84ccd0aSEtienne Carriere 
1499dbdd8cdSEtienne Carriere 	init_pin_keys(token, PKCS11_CKU_SO);
1509dbdd8cdSEtienne Carriere 	init_pin_keys(token, PKCS11_CKU_USER);
1519dbdd8cdSEtienne Carriere 	COMPILE_TIME_ASSERT(PKCS11_CKU_SO == 0 && PKCS11_CKU_USER == 1 &&
1529dbdd8cdSEtienne Carriere 			    PKCS11_MAX_USERS >= 2);
153c84ccd0aSEtienne Carriere 
154c84ccd0aSEtienne Carriere 	db_main = TEE_Malloc(sizeof(*db_main), TEE_MALLOC_FILL_ZERO);
155c84ccd0aSEtienne Carriere 	if (!db_main)
156c84ccd0aSEtienne Carriere 		goto error;
157c84ccd0aSEtienne Carriere 
158*60659a86SEtienne Carriere 	res = open_db_file(token, &db_hdl);
159c84ccd0aSEtienne Carriere 
160c84ccd0aSEtienne Carriere 	if (res == TEE_SUCCESS) {
161c84ccd0aSEtienne Carriere 		uint32_t size = 0;
162c84ccd0aSEtienne Carriere 
163c84ccd0aSEtienne Carriere 		IMSG("PKCS11 token %u: load db", token_id);
164c84ccd0aSEtienne Carriere 
165c84ccd0aSEtienne Carriere 		size = sizeof(*db_main);
166c84ccd0aSEtienne Carriere 		res = TEE_ReadObjectData(db_hdl, db_main, size, &size);
167c84ccd0aSEtienne Carriere 		if (res || size != sizeof(*db_main))
168c84ccd0aSEtienne Carriere 			TEE_Panic(0);
169c84ccd0aSEtienne Carriere 	} else if (res == TEE_ERROR_ITEM_NOT_FOUND) {
170*60659a86SEtienne Carriere 		char file[PERSISTENT_OBJECT_ID_LEN] = { };
171*60659a86SEtienne Carriere 
172c84ccd0aSEtienne Carriere 		IMSG("PKCS11 token %u: init db", token_id);
173c84ccd0aSEtienne Carriere 
174c84ccd0aSEtienne Carriere 		TEE_MemFill(db_main, 0, sizeof(*db_main));
175c84ccd0aSEtienne Carriere 		TEE_MemFill(db_main->label, '*', sizeof(db_main->label));
176c84ccd0aSEtienne Carriere 
177c84ccd0aSEtienne Carriere 		db_main->flags = PKCS11_CKFT_SO_PIN_TO_BE_CHANGED |
178c84ccd0aSEtienne Carriere 				 PKCS11_CKFT_USER_PIN_TO_BE_CHANGED |
179c84ccd0aSEtienne Carriere 				 PKCS11_CKFT_RNG |
180c84ccd0aSEtienne Carriere 				 PKCS11_CKFT_DUAL_CRYPTO_OPERATIONS |
181c84ccd0aSEtienne Carriere 				 PKCS11_CKFT_LOGIN_REQUIRED;
182c84ccd0aSEtienne Carriere 
183*60659a86SEtienne Carriere 		res = get_db_file_name(token, file, sizeof(file));
184*60659a86SEtienne Carriere 		if (res)
185*60659a86SEtienne Carriere 			TEE_Panic(0);
186*60659a86SEtienne Carriere 
187*60659a86SEtienne Carriere 		/* 2 files: persistent state + persistent object references */
188c84ccd0aSEtienne Carriere 		res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE,
189*60659a86SEtienne Carriere 						 file, sizeof(file),
190c84ccd0aSEtienne Carriere 						 TEE_DATA_FLAG_ACCESS_READ |
191c84ccd0aSEtienne Carriere 						 TEE_DATA_FLAG_ACCESS_WRITE,
192c84ccd0aSEtienne Carriere 						 TEE_HANDLE_NULL,
193c84ccd0aSEtienne Carriere 						 db_main, sizeof(*db_main),
194c84ccd0aSEtienne Carriere 						 &db_hdl);
195c84ccd0aSEtienne Carriere 		if (res) {
196c84ccd0aSEtienne Carriere 			EMSG("Failed to create db: %"PRIx32, res);
197c84ccd0aSEtienne Carriere 			goto error;
198c84ccd0aSEtienne Carriere 		}
199c84ccd0aSEtienne Carriere 	} else {
200c84ccd0aSEtienne Carriere 		goto error;
201c84ccd0aSEtienne Carriere 	}
202c84ccd0aSEtienne Carriere 
203c84ccd0aSEtienne Carriere 	token->db_main = db_main;
204c84ccd0aSEtienne Carriere 	TEE_CloseObject(db_hdl);
205c84ccd0aSEtienne Carriere 
206c84ccd0aSEtienne Carriere 	return token;
207c84ccd0aSEtienne Carriere 
208c84ccd0aSEtienne Carriere error:
209c84ccd0aSEtienne Carriere 	TEE_Free(db_main);
210c84ccd0aSEtienne Carriere 	if (db_hdl != TEE_HANDLE_NULL)
211c84ccd0aSEtienne Carriere 		TEE_CloseObject(db_hdl);
212c84ccd0aSEtienne Carriere 
213c84ccd0aSEtienne Carriere 	return NULL;
214c84ccd0aSEtienne Carriere }
215