xref: /optee_os/ta/pkcs11/src/persistent_token.c (revision e86828f46493b322e7a595f91fa8a73855f9a6a7)
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 static TEE_Result get_db_file_name(struct ck_token *token,
22 				   char *name, size_t size)
23 {
24 	int n = snprintf(name, size, "token.db.%u", get_token_id(token));
25 
26 	if (n < 0 || (size_t)n >= size)
27 		return TEE_ERROR_SECURITY;
28 	else
29 		return TEE_SUCCESS;
30 }
31 
32 static TEE_Result open_db_file(struct ck_token *token,
33 			       TEE_ObjectHandle *out_hdl)
34 {
35 	char file[PERSISTENT_OBJECT_ID_LEN] = { };
36 	TEE_Result res = TEE_ERROR_GENERIC;
37 
38 	res = get_db_file_name(token, file, sizeof(file));
39 	if (res)
40 		return res;
41 
42 	return TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, file, sizeof(file),
43 					TEE_DATA_FLAG_ACCESS_READ |
44 					TEE_DATA_FLAG_ACCESS_WRITE,
45 					out_hdl);
46 }
47 
48 static TEE_Result get_pin_file_name(struct ck_token *token,
49 				    enum pkcs11_user_type user,
50 				    char *name, size_t size)
51 {
52 	int n = snprintf(name, size,
53 			 "token.db.%u-pin%d", get_token_id(token), user);
54 
55 	if (n < 0 || (size_t)n >= size)
56 		return TEE_ERROR_SECURITY;
57 	else
58 		return TEE_SUCCESS;
59 }
60 
61 static TEE_Result open_pin_file(struct ck_token *token,
62 				enum pkcs11_user_type user,
63 				TEE_ObjectHandle *out_hdl)
64 {
65 	char file[PERSISTENT_OBJECT_ID_LEN] = { };
66 	TEE_Result res = TEE_ERROR_GENERIC;
67 
68 	res = get_pin_file_name(token, user, file, sizeof(file));
69 	if (res)
70 		return res;
71 
72 	return TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, file, sizeof(file),
73 					0, out_hdl);
74 }
75 
76 void update_persistent_db(struct ck_token *token)
77 {
78 	TEE_Result res = TEE_ERROR_GENERIC;
79 	TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL;
80 
81 	res = open_db_file(token, &db_hdl);
82 	if (res) {
83 		EMSG("Failed to open token persistent db: %#"PRIx32, res);
84 		TEE_Panic(0);
85 	}
86 	res = TEE_WriteObjectData(db_hdl, token->db_main,
87 				  sizeof(*token->db_main));
88 	if (res) {
89 		EMSG("Failed to write to token persistent db: %#"PRIx32, res);
90 		TEE_Panic(0);
91 	}
92 
93 	TEE_CloseObject(db_hdl);
94 }
95 
96 static enum pkcs11_rc do_hash(uint32_t user, const uint8_t *pin,
97 			      size_t pin_size, uint32_t salt,
98 			      uint8_t hash[TEE_MAX_HASH_SIZE])
99 {
100 	TEE_Result res = TEE_SUCCESS;
101 	TEE_OperationHandle oh = TEE_HANDLE_NULL;
102 	uint32_t sz = TEE_MAX_HASH_SIZE;
103 
104 	res = TEE_AllocateOperation(&oh, TEE_ALG_SHA256, TEE_MODE_DIGEST, 0);
105 	if (res)
106 		return tee2pkcs_error(res);
107 
108 	TEE_DigestUpdate(oh, &user, sizeof(user));
109 	TEE_DigestUpdate(oh, &salt, sizeof(salt));
110 	res = TEE_DigestDoFinal(oh, pin, pin_size, hash, &sz);
111 	TEE_FreeOperation(oh);
112 
113 	if (res)
114 		return PKCS11_CKR_GENERAL_ERROR;
115 
116 	memset(hash + sz, 0, TEE_MAX_HASH_SIZE - sz);
117 	return PKCS11_CKR_OK;
118 }
119 
120 enum pkcs11_rc hash_pin(enum pkcs11_user_type user, const uint8_t *pin,
121 			size_t pin_size, uint32_t *salt,
122 			uint8_t hash[TEE_MAX_HASH_SIZE])
123 {
124 	enum pkcs11_rc rc = PKCS11_CKR_OK;
125 	uint32_t s = 0;
126 
127 	TEE_GenerateRandom(&s, sizeof(s));
128 	if (!s)
129 		s++;
130 
131 	rc = do_hash(user, pin, pin_size, s, hash);
132 	if (!rc)
133 		*salt = s;
134 	return rc;
135 }
136 
137 enum pkcs11_rc verify_pin(enum pkcs11_user_type user, const uint8_t *pin,
138 			  size_t pin_size, uint32_t salt,
139 			  const uint8_t hash[TEE_MAX_HASH_SIZE])
140 {
141 	uint8_t tmp_hash[TEE_MAX_HASH_SIZE] = { 0 };
142 	enum pkcs11_rc rc = PKCS11_CKR_OK;
143 
144 	rc = do_hash(user, pin, pin_size, salt, tmp_hash);
145 	if (rc)
146 		return rc;
147 
148 	if (buf_compare_ct(tmp_hash, hash, TEE_MAX_HASH_SIZE))
149 		rc = PKCS11_CKR_PIN_INCORRECT;
150 
151 	return rc;
152 }
153 
154 static void init_pin_keys(struct ck_token *token, enum pkcs11_user_type user)
155 {
156 	TEE_Result res = TEE_ERROR_GENERIC;
157 	TEE_ObjectHandle key_hdl = TEE_HANDLE_NULL;
158 
159 	res = open_pin_file(token, user, &key_hdl);
160 
161 	if (res == TEE_SUCCESS)
162 		DMSG("PIN key found");
163 
164 	if (res == TEE_ERROR_ITEM_NOT_FOUND) {
165 		TEE_Attribute attr = { };
166 		TEE_ObjectHandle hdl = TEE_HANDLE_NULL;
167 		uint8_t pin_key[16] = { };
168 		char file[PERSISTENT_OBJECT_ID_LEN] = { };
169 
170 		TEE_MemFill(&attr, 0, sizeof(attr));
171 
172 		TEE_GenerateRandom(pin_key, sizeof(pin_key));
173 		TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE,
174 				     pin_key, sizeof(pin_key));
175 
176 		res = TEE_AllocateTransientObject(TEE_TYPE_AES, 128, &hdl);
177 		if (res)
178 			TEE_Panic(0);
179 
180 		res = TEE_PopulateTransientObject(hdl, &attr, 1);
181 		if (res)
182 			TEE_Panic(0);
183 
184 		res = get_pin_file_name(token, user, file, sizeof(file));
185 		if (res)
186 			TEE_Panic(0);
187 
188 		res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE,
189 						 file, sizeof(file), 0, hdl,
190 						 pin_key, sizeof(pin_key),
191 						 &key_hdl);
192 		TEE_CloseObject(hdl);
193 
194 		if (res == TEE_SUCCESS)
195 			DMSG("Token %u: PIN key created", get_token_id(token));
196 	}
197 
198 	if (res)
199 		TEE_Panic(res);
200 
201 	TEE_CloseObject(key_hdl);
202 }
203 
204 /*
205  * Release resources relate to persistent database
206  */
207 void close_persistent_db(struct ck_token *token __unused)
208 {
209 }
210 
211 /*
212  * Return the token instance, either initialized from reset or initialized
213  * from the token persistent state if found.
214  */
215 struct ck_token *init_persistent_db(unsigned int token_id)
216 {
217 	struct ck_token *token = get_token(token_id);
218 	TEE_Result res = TEE_ERROR_GENERIC;
219 	TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL;
220 	/* Copy persistent database: main db and object db */
221 	struct token_persistent_main *db_main = NULL;
222 
223 	if (!token)
224 		return NULL;
225 
226 	init_pin_keys(token, PKCS11_CKU_SO);
227 	init_pin_keys(token, PKCS11_CKU_USER);
228 	COMPILE_TIME_ASSERT(PKCS11_CKU_SO == 0 && PKCS11_CKU_USER == 1 &&
229 			    PKCS11_MAX_USERS >= 2);
230 
231 	db_main = TEE_Malloc(sizeof(*db_main), TEE_MALLOC_FILL_ZERO);
232 	if (!db_main)
233 		goto error;
234 
235 	res = open_db_file(token, &db_hdl);
236 
237 	if (res == TEE_SUCCESS) {
238 		uint32_t size = 0;
239 
240 		IMSG("PKCS11 token %u: load db", token_id);
241 
242 		size = sizeof(*db_main);
243 		res = TEE_ReadObjectData(db_hdl, db_main, size, &size);
244 		if (res || size != sizeof(*db_main))
245 			TEE_Panic(0);
246 	} else if (res == TEE_ERROR_ITEM_NOT_FOUND) {
247 		char file[PERSISTENT_OBJECT_ID_LEN] = { };
248 
249 		IMSG("PKCS11 token %u: init db", token_id);
250 
251 		TEE_MemFill(db_main, 0, sizeof(*db_main));
252 		TEE_MemFill(db_main->label, '*', sizeof(db_main->label));
253 
254 		db_main->flags = PKCS11_CKFT_SO_PIN_TO_BE_CHANGED |
255 				 PKCS11_CKFT_USER_PIN_TO_BE_CHANGED |
256 				 PKCS11_CKFT_RNG |
257 				 PKCS11_CKFT_DUAL_CRYPTO_OPERATIONS |
258 				 PKCS11_CKFT_LOGIN_REQUIRED;
259 
260 		res = get_db_file_name(token, file, sizeof(file));
261 		if (res)
262 			TEE_Panic(0);
263 
264 		res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE,
265 						 file, sizeof(file),
266 						 TEE_DATA_FLAG_ACCESS_READ |
267 						 TEE_DATA_FLAG_ACCESS_WRITE,
268 						 TEE_HANDLE_NULL,
269 						 db_main, sizeof(*db_main),
270 						 &db_hdl);
271 		if (res) {
272 			EMSG("Failed to create db: %"PRIx32, res);
273 			goto error;
274 		}
275 	} else {
276 		goto error;
277 	}
278 
279 	token->db_main = db_main;
280 	TEE_CloseObject(db_hdl);
281 
282 	return token;
283 
284 error:
285 	TEE_Free(db_main);
286 	if (db_hdl != TEE_HANDLE_NULL)
287 		TEE_CloseObject(db_hdl);
288 
289 	return NULL;
290 }
291