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