xref: /optee_os/ta/pkcs11/src/persistent_token.c (revision a1d5c81f8834a9d2c6f4372cce2e59e70e709121)
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