xref: /optee_os/ta/pkcs11/src/persistent_token.c (revision a31e8303cf2e6cb5dac2823ff86d03f96554e219)
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 static void init_pin_keys(struct ck_token *token, unsigned int uid)
77 {
78 	TEE_Result res = TEE_ERROR_GENERIC;
79 	TEE_ObjectHandle key_hdl = TEE_HANDLE_NULL;
80 	enum pkcs11_user_type user = uid;
81 
82 	res = open_pin_file(token, user, &key_hdl);
83 
84 	if (res == TEE_SUCCESS)
85 		DMSG("PIN key found");
86 
87 	if (res == TEE_ERROR_ITEM_NOT_FOUND) {
88 		TEE_Attribute attr = { };
89 		TEE_ObjectHandle hdl = TEE_HANDLE_NULL;
90 		uint8_t pin_key[16] = { };
91 		char file[PERSISTENT_OBJECT_ID_LEN] = { };
92 
93 		TEE_MemFill(&attr, 0, sizeof(attr));
94 
95 		TEE_GenerateRandom(pin_key, sizeof(pin_key));
96 		TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE,
97 				     pin_key, sizeof(pin_key));
98 
99 		res = TEE_AllocateTransientObject(TEE_TYPE_AES, 128, &hdl);
100 		if (res)
101 			TEE_Panic(0);
102 
103 		res = TEE_PopulateTransientObject(hdl, &attr, 1);
104 		if (res)
105 			TEE_Panic(0);
106 
107 		res = get_pin_file_name(token, user, file, sizeof(file));
108 		if (res)
109 			TEE_Panic(0);
110 
111 		res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE,
112 						 file, sizeof(file), 0, hdl,
113 						 pin_key, sizeof(pin_key),
114 						 &key_hdl);
115 		TEE_CloseObject(hdl);
116 
117 		if (res == TEE_SUCCESS)
118 			DMSG("Token %u: PIN key created", get_token_id(token));
119 	}
120 
121 	if (res)
122 		TEE_Panic(res);
123 
124 	TEE_CloseObject(key_hdl);
125 }
126 
127 /*
128  * Release resources relate to persistent database
129  */
130 void close_persistent_db(struct ck_token *token __unused)
131 {
132 }
133 
134 /*
135  * Return the token instance, either initialized from reset or initialized
136  * from the token persistent state if found.
137  */
138 struct ck_token *init_persistent_db(unsigned int token_id)
139 {
140 	struct ck_token *token = get_token(token_id);
141 	TEE_Result res = TEE_ERROR_GENERIC;
142 	TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL;
143 	/* Copy persistent database: main db and object db */
144 	struct token_persistent_main *db_main = NULL;
145 
146 	if (!token)
147 		return NULL;
148 
149 	init_pin_keys(token, PKCS11_CKU_SO);
150 	init_pin_keys(token, PKCS11_CKU_USER);
151 	COMPILE_TIME_ASSERT(PKCS11_CKU_SO == 0 && PKCS11_CKU_USER == 1 &&
152 			    PKCS11_MAX_USERS >= 2);
153 
154 	db_main = TEE_Malloc(sizeof(*db_main), TEE_MALLOC_FILL_ZERO);
155 	if (!db_main)
156 		goto error;
157 
158 	res = open_db_file(token, &db_hdl);
159 
160 	if (res == TEE_SUCCESS) {
161 		uint32_t size = 0;
162 
163 		IMSG("PKCS11 token %u: load db", token_id);
164 
165 		size = sizeof(*db_main);
166 		res = TEE_ReadObjectData(db_hdl, db_main, size, &size);
167 		if (res || size != sizeof(*db_main))
168 			TEE_Panic(0);
169 	} else if (res == TEE_ERROR_ITEM_NOT_FOUND) {
170 		char file[PERSISTENT_OBJECT_ID_LEN] = { };
171 
172 		IMSG("PKCS11 token %u: init db", token_id);
173 
174 		TEE_MemFill(db_main, 0, sizeof(*db_main));
175 		TEE_MemFill(db_main->label, '*', sizeof(db_main->label));
176 
177 		db_main->flags = PKCS11_CKFT_SO_PIN_TO_BE_CHANGED |
178 				 PKCS11_CKFT_USER_PIN_TO_BE_CHANGED |
179 				 PKCS11_CKFT_RNG |
180 				 PKCS11_CKFT_DUAL_CRYPTO_OPERATIONS |
181 				 PKCS11_CKFT_LOGIN_REQUIRED;
182 
183 		res = get_db_file_name(token, file, sizeof(file));
184 		if (res)
185 			TEE_Panic(0);
186 
187 		/* 2 files: persistent state + persistent object references */
188 		res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE,
189 						 file, sizeof(file),
190 						 TEE_DATA_FLAG_ACCESS_READ |
191 						 TEE_DATA_FLAG_ACCESS_WRITE,
192 						 TEE_HANDLE_NULL,
193 						 db_main, sizeof(*db_main),
194 						 &db_hdl);
195 		if (res) {
196 			EMSG("Failed to create db: %"PRIx32, res);
197 			goto error;
198 		}
199 	} else {
200 		goto error;
201 	}
202 
203 	token->db_main = db_main;
204 	TEE_CloseObject(db_hdl);
205 
206 	return token;
207 
208 error:
209 	TEE_Free(db_main);
210 	if (db_hdl != TEE_HANDLE_NULL)
211 		TEE_CloseObject(db_hdl);
212 
213 	return NULL;
214 }
215