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 enum pkcs11_rc do_hash(uint32_t user, const uint8_t *pin, 77 size_t pin_size, uint32_t salt, 78 uint8_t hash[TEE_MAX_HASH_SIZE]) 79 { 80 TEE_Result res = TEE_SUCCESS; 81 TEE_OperationHandle oh = TEE_HANDLE_NULL; 82 uint32_t sz = TEE_MAX_HASH_SIZE; 83 84 res = TEE_AllocateOperation(&oh, TEE_ALG_SHA256, TEE_MODE_DIGEST, 0); 85 if (res) 86 return tee2pkcs_error(res); 87 88 TEE_DigestUpdate(oh, &user, sizeof(user)); 89 TEE_DigestUpdate(oh, &salt, sizeof(salt)); 90 res = TEE_DigestDoFinal(oh, pin, pin_size, hash, &sz); 91 TEE_FreeOperation(oh); 92 93 if (res) 94 return PKCS11_CKR_GENERAL_ERROR; 95 96 memset(hash + sz, 0, TEE_MAX_HASH_SIZE - sz); 97 return PKCS11_CKR_OK; 98 } 99 100 enum pkcs11_rc hash_pin(enum pkcs11_user_type user, const uint8_t *pin, 101 size_t pin_size, uint32_t *salt, 102 uint8_t hash[TEE_MAX_HASH_SIZE]) 103 { 104 enum pkcs11_rc rc = PKCS11_CKR_OK; 105 uint32_t s = 0; 106 107 TEE_GenerateRandom(&s, sizeof(s)); 108 if (!s) 109 s++; 110 111 rc = do_hash(user, pin, pin_size, s, hash); 112 if (!rc) 113 *salt = s; 114 return rc; 115 } 116 117 enum pkcs11_rc verify_pin(enum pkcs11_user_type user, const uint8_t *pin, 118 size_t pin_size, uint32_t salt, 119 const uint8_t hash[TEE_MAX_HASH_SIZE]) 120 { 121 uint8_t tmp_hash[TEE_MAX_HASH_SIZE] = { 0 }; 122 enum pkcs11_rc rc = PKCS11_CKR_OK; 123 124 rc = do_hash(user, pin, pin_size, salt, tmp_hash); 125 if (rc) 126 return rc; 127 128 if (buf_compare_ct(tmp_hash, hash, TEE_MAX_HASH_SIZE)) 129 rc = PKCS11_CKR_PIN_INCORRECT; 130 131 return rc; 132 } 133 134 static void init_pin_keys(struct ck_token *token, enum pkcs11_user_type user) 135 { 136 TEE_Result res = TEE_ERROR_GENERIC; 137 TEE_ObjectHandle key_hdl = TEE_HANDLE_NULL; 138 139 res = open_pin_file(token, user, &key_hdl); 140 141 if (res == TEE_SUCCESS) 142 DMSG("PIN key found"); 143 144 if (res == TEE_ERROR_ITEM_NOT_FOUND) { 145 TEE_Attribute attr = { }; 146 TEE_ObjectHandle hdl = TEE_HANDLE_NULL; 147 uint8_t pin_key[16] = { }; 148 char file[PERSISTENT_OBJECT_ID_LEN] = { }; 149 150 TEE_MemFill(&attr, 0, sizeof(attr)); 151 152 TEE_GenerateRandom(pin_key, sizeof(pin_key)); 153 TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE, 154 pin_key, sizeof(pin_key)); 155 156 res = TEE_AllocateTransientObject(TEE_TYPE_AES, 128, &hdl); 157 if (res) 158 TEE_Panic(0); 159 160 res = TEE_PopulateTransientObject(hdl, &attr, 1); 161 if (res) 162 TEE_Panic(0); 163 164 res = get_pin_file_name(token, user, file, sizeof(file)); 165 if (res) 166 TEE_Panic(0); 167 168 res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE, 169 file, sizeof(file), 0, hdl, 170 pin_key, sizeof(pin_key), 171 &key_hdl); 172 TEE_CloseObject(hdl); 173 174 if (res == TEE_SUCCESS) 175 DMSG("Token %u: PIN key created", get_token_id(token)); 176 } 177 178 if (res) 179 TEE_Panic(res); 180 181 TEE_CloseObject(key_hdl); 182 } 183 184 /* 185 * Release resources relate to persistent database 186 */ 187 void close_persistent_db(struct ck_token *token __unused) 188 { 189 } 190 191 /* 192 * Return the token instance, either initialized from reset or initialized 193 * from the token persistent state if found. 194 */ 195 struct ck_token *init_persistent_db(unsigned int token_id) 196 { 197 struct ck_token *token = get_token(token_id); 198 TEE_Result res = TEE_ERROR_GENERIC; 199 TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL; 200 /* Copy persistent database: main db and object db */ 201 struct token_persistent_main *db_main = NULL; 202 203 if (!token) 204 return NULL; 205 206 init_pin_keys(token, PKCS11_CKU_SO); 207 init_pin_keys(token, PKCS11_CKU_USER); 208 COMPILE_TIME_ASSERT(PKCS11_CKU_SO == 0 && PKCS11_CKU_USER == 1 && 209 PKCS11_MAX_USERS >= 2); 210 211 db_main = TEE_Malloc(sizeof(*db_main), TEE_MALLOC_FILL_ZERO); 212 if (!db_main) 213 goto error; 214 215 res = open_db_file(token, &db_hdl); 216 217 if (res == TEE_SUCCESS) { 218 uint32_t size = 0; 219 220 IMSG("PKCS11 token %u: load db", token_id); 221 222 size = sizeof(*db_main); 223 res = TEE_ReadObjectData(db_hdl, db_main, size, &size); 224 if (res || size != sizeof(*db_main)) 225 TEE_Panic(0); 226 } else if (res == TEE_ERROR_ITEM_NOT_FOUND) { 227 char file[PERSISTENT_OBJECT_ID_LEN] = { }; 228 229 IMSG("PKCS11 token %u: init db", token_id); 230 231 TEE_MemFill(db_main, 0, sizeof(*db_main)); 232 TEE_MemFill(db_main->label, '*', sizeof(db_main->label)); 233 234 db_main->flags = PKCS11_CKFT_SO_PIN_TO_BE_CHANGED | 235 PKCS11_CKFT_USER_PIN_TO_BE_CHANGED | 236 PKCS11_CKFT_RNG | 237 PKCS11_CKFT_DUAL_CRYPTO_OPERATIONS | 238 PKCS11_CKFT_LOGIN_REQUIRED; 239 240 res = get_db_file_name(token, file, sizeof(file)); 241 if (res) 242 TEE_Panic(0); 243 244 res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE, 245 file, sizeof(file), 246 TEE_DATA_FLAG_ACCESS_READ | 247 TEE_DATA_FLAG_ACCESS_WRITE, 248 TEE_HANDLE_NULL, 249 db_main, sizeof(*db_main), 250 &db_hdl); 251 if (res) { 252 EMSG("Failed to create db: %"PRIx32, res); 253 goto error; 254 } 255 } else { 256 goto error; 257 } 258 259 token->db_main = db_main; 260 TEE_CloseObject(db_hdl); 261 262 return token; 263 264 error: 265 TEE_Free(db_main); 266 if (db_hdl != TEE_HANDLE_NULL) 267 TEE_CloseObject(db_hdl); 268 269 return NULL; 270 } 271