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 void update_persistent_db(struct ck_token *token) 49 { 50 TEE_Result res = TEE_ERROR_GENERIC; 51 TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL; 52 53 res = open_db_file(token, &db_hdl); 54 if (res) { 55 EMSG("Failed to open token persistent db: %#"PRIx32, res); 56 TEE_Panic(0); 57 } 58 res = TEE_WriteObjectData(db_hdl, token->db_main, 59 sizeof(*token->db_main)); 60 if (res) { 61 EMSG("Failed to write to token persistent db: %#"PRIx32, res); 62 TEE_Panic(0); 63 } 64 65 TEE_CloseObject(db_hdl); 66 } 67 68 static enum pkcs11_rc do_hash(uint32_t user, const uint8_t *pin, 69 size_t pin_size, uint32_t salt, 70 uint8_t hash[TEE_MAX_HASH_SIZE]) 71 { 72 TEE_Result res = TEE_SUCCESS; 73 TEE_OperationHandle oh = TEE_HANDLE_NULL; 74 uint32_t sz = TEE_MAX_HASH_SIZE; 75 76 res = TEE_AllocateOperation(&oh, TEE_ALG_SHA256, TEE_MODE_DIGEST, 0); 77 if (res) 78 return tee2pkcs_error(res); 79 80 TEE_DigestUpdate(oh, &user, sizeof(user)); 81 TEE_DigestUpdate(oh, &salt, sizeof(salt)); 82 res = TEE_DigestDoFinal(oh, pin, pin_size, hash, &sz); 83 TEE_FreeOperation(oh); 84 85 if (res) 86 return PKCS11_CKR_GENERAL_ERROR; 87 88 memset(hash + sz, 0, TEE_MAX_HASH_SIZE - sz); 89 return PKCS11_CKR_OK; 90 } 91 92 enum pkcs11_rc hash_pin(enum pkcs11_user_type user, const uint8_t *pin, 93 size_t pin_size, uint32_t *salt, 94 uint8_t hash[TEE_MAX_HASH_SIZE]) 95 { 96 enum pkcs11_rc rc = PKCS11_CKR_OK; 97 uint32_t s = 0; 98 99 TEE_GenerateRandom(&s, sizeof(s)); 100 if (!s) 101 s++; 102 103 rc = do_hash(user, pin, pin_size, s, hash); 104 if (!rc) 105 *salt = s; 106 return rc; 107 } 108 109 enum pkcs11_rc verify_pin(enum pkcs11_user_type user, const uint8_t *pin, 110 size_t pin_size, uint32_t salt, 111 const uint8_t hash[TEE_MAX_HASH_SIZE]) 112 { 113 uint8_t tmp_hash[TEE_MAX_HASH_SIZE] = { 0 }; 114 enum pkcs11_rc rc = PKCS11_CKR_OK; 115 116 rc = do_hash(user, pin, pin_size, salt, tmp_hash); 117 if (rc) 118 return rc; 119 120 if (buf_compare_ct(tmp_hash, hash, TEE_MAX_HASH_SIZE)) 121 rc = PKCS11_CKR_PIN_INCORRECT; 122 123 return rc; 124 } 125 126 /* 127 * Release resources relate to persistent database 128 */ 129 void close_persistent_db(struct ck_token *token __unused) 130 { 131 } 132 133 /* 134 * Return the token instance, either initialized from reset or initialized 135 * from the token persistent state if found. 136 */ 137 struct ck_token *init_persistent_db(unsigned int token_id) 138 { 139 struct ck_token *token = get_token(token_id); 140 TEE_Result res = TEE_ERROR_GENERIC; 141 TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL; 142 /* Copy persistent database: main db and object db */ 143 struct token_persistent_main *db_main = NULL; 144 145 if (!token) 146 return NULL; 147 148 db_main = TEE_Malloc(sizeof(*db_main), TEE_MALLOC_FILL_ZERO); 149 if (!db_main) 150 goto error; 151 152 res = open_db_file(token, &db_hdl); 153 154 if (res == TEE_SUCCESS) { 155 uint32_t size = 0; 156 157 IMSG("PKCS11 token %u: load db", token_id); 158 159 size = sizeof(*db_main); 160 res = TEE_ReadObjectData(db_hdl, db_main, size, &size); 161 if (res || size != sizeof(*db_main)) 162 TEE_Panic(0); 163 } else if (res == TEE_ERROR_ITEM_NOT_FOUND) { 164 char file[PERSISTENT_OBJECT_ID_LEN] = { }; 165 166 IMSG("PKCS11 token %u: init db", token_id); 167 168 TEE_MemFill(db_main, 0, sizeof(*db_main)); 169 TEE_MemFill(db_main->label, '*', sizeof(db_main->label)); 170 171 db_main->flags = PKCS11_CKFT_SO_PIN_TO_BE_CHANGED | 172 PKCS11_CKFT_USER_PIN_TO_BE_CHANGED | 173 PKCS11_CKFT_RNG | 174 PKCS11_CKFT_DUAL_CRYPTO_OPERATIONS | 175 PKCS11_CKFT_LOGIN_REQUIRED; 176 177 res = get_db_file_name(token, file, sizeof(file)); 178 if (res) 179 TEE_Panic(0); 180 181 res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE, 182 file, sizeof(file), 183 TEE_DATA_FLAG_ACCESS_READ | 184 TEE_DATA_FLAG_ACCESS_WRITE, 185 TEE_HANDLE_NULL, 186 db_main, sizeof(*db_main), 187 &db_hdl); 188 if (res) { 189 EMSG("Failed to create db: %"PRIx32, res); 190 goto error; 191 } 192 } else { 193 goto error; 194 } 195 196 token->db_main = db_main; 197 TEE_CloseObject(db_hdl); 198 199 return token; 200 201 error: 202 TEE_Free(db_main); 203 if (db_hdl != TEE_HANDLE_NULL) 204 TEE_CloseObject(db_hdl); 205 206 return NULL; 207 } 208