diff options
Diffstat (limited to 'srcs/key_handler.c')
-rw-r--r-- | srcs/key_handler.c | 224 |
1 files changed, 158 insertions, 66 deletions
diff --git a/srcs/key_handler.c b/srcs/key_handler.c index 905538e..cdc96af 100644 --- a/srcs/key_handler.c +++ b/srcs/key_handler.c @@ -103,17 +103,17 @@ int _get_random(raw_buffer_s *rb) return WAE_ERROR_NONE; } -static const char *_get_dek_kek_pub_key_path() +const char *_get_dek_kek_pub_key_path() { return tzplatform_mkpath4(TZ_SYS_SHARE, "wae", "app_dek", "WAE_APPDEK_KEK_PublicKey.pem"); } -static const char *_get_dek_kek_pri_key_path() +const char *_get_dek_kek_pri_key_path() { return tzplatform_mkpath4(TZ_SYS_SHARE, "wae", "app_dek", "WAE_APPDEK_KEK_PrivateKey.pem"); } -static const char *_get_dek_store_path() +const char *_get_dek_store_path() { return tzplatform_mkpath3(TZ_SYS_SHARE, "wae", "app_dek"); } @@ -188,15 +188,87 @@ error: return ret; } -int _get_preloaded_app_dek_file_path(const char *pkg_id, size_t size, char *path) +typedef int(*entry_callback)(const char *path, const struct dirent *entry, void *user_data); +static int traverse_directory(const char *path, entry_callback ecb, void *user_data) +{ + DIR *dir = opendir(path); + if (dir == NULL) { + if (errno == ENOENT) { + // it's not error for current cases of using traverse_directory. + // To open dek store directory for load/remove can be occured in some + // exception(or attacked) cases but we can just ignore it if it isn't the + // first time call load_preloaded_app_deks. + WAE_SLOGI("directory isn't exist(%s).", path); + return WAE_ERROR_NONE; + } else { + WAE_SLOGE("Failed to open dir(%s)", path); + return WAE_ERROR_FILE; + } + } + + int ret = WAE_ERROR_NONE; + struct dirent entry; + struct dirent *result = NULL; + while (true) { + if (readdir_r(dir, &entry, &result) != 0) { + WAE_SLOGE("readdir_r error on dir(%s) errno(%d)", path, errno); + break; + } else if (result == NULL) { + break; // end of directory + } else if (strcmp(entry.d_name, ".") == 0 || strcmp(entry.d_name, "..") == 0) { + continue; + } + + int _ret = ecb(path, result, user_data); + if (_ret != WAE_ERROR_NONE) + ret = _ret; + } + + closedir(dir); + return ret; +} + +static void _remove_file(const char *path) { - int ret = snprintf(path, size, "%s/%s_%s.adek", - _get_dek_store_path(), APP_DEK_FILE_PFX, pkg_id); + unlink(path); +} + +static int _entry_callback_remove_all( + const char *path, const struct dirent *entry, void *user_data) +{ + (void) user_data; // TODO: use UNUSED macro - if (ret < 0) + char file_path_buff[MAX_PATH_LEN] = {0, }; + if (snprintf(file_path_buff, sizeof(file_path_buff), "%s/%s", path, entry->d_name) < 0) return WAE_ERROR_INVALID_PARAMETER; /* buffer size too small */ - return WAE_ERROR_NONE; + int ret = WAE_ERROR_NONE; + if (entry->d_type == DT_DIR) { + int _ret = traverse_directory(file_path_buff, _entry_callback_remove_all, NULL); + if (_ret != WAE_ERROR_NONE) + ret = _ret; + rmdir(file_path_buff); + } else { + _remove_file(file_path_buff); + } + return ret; +} + +void _remove_directory(const char *path) +{ + traverse_directory(path, _entry_callback_remove_all, NULL); + + WAE_SLOGD("remove directory(%s)", path); + rmdir(path); +} + +int _get_preloaded_app_dek_file_path(const char *pkg_id, size_t size, char *path) +{ + if (snprintf(path, size, "%s/%s_%s.adek", + _get_dek_store_path(), APP_DEK_FILE_PFX, pkg_id) < 0) + return WAE_ERROR_INVALID_PARAMETER; /* buffer size too small */ + else + return WAE_ERROR_NONE; } static int _extract_pkg_id_from_file_name(const char *file_name, char *pkg_id) @@ -528,88 +600,108 @@ int _get_app_dek_kek(raw_buffer_s **pdek_kek) #endif } -int load_preloaded_app_deks(bool reload) +static int _entry_callback_load_preloaded_adeks( + const char *path, const struct dirent *entry, void *prikey) { - int ret = WAE_ERROR_NONE; + const char *pub_key_path = _get_dek_kek_pub_key_path(); + const char *pri_key_path = _get_dek_kek_pri_key_path(); - char pkg_id[MAX_PKGID_LEN] = {0, }; - char file_path_buff[MAX_PATH_LEN]; + char file_path_buff[MAX_PATH_LEN] = {0, }; + if (snprintf(file_path_buff, sizeof(file_path_buff), "%s/%s", path, entry->d_name) < 0) + return WAE_ERROR_INVALID_PARAMETER; /* buffer size too small */ - if (!reload) { - // check if all deks were already loaded into key-manager. - ret = is_app_deks_loaded_in_key_manager(); + if (strcmp(file_path_buff, pub_key_path) == 0 || + strcmp(file_path_buff, pri_key_path) == 0) + return WAE_ERROR_NONE; /* skip KEK files */ - if (ret == true) - return WAE_ERROR_NONE; - } + if (entry->d_type != DT_REG || strstr(entry->d_name, APP_DEK_FILE_PFX) == NULL) { + if (entry->d_type == DT_DIR) + WAE_SLOGW( + "Invalid file in dek store(%s). Directory shouldn't be here.", path); + else + WAE_SLOGW( + "Invalid file in dek store(%s). " + "Not regular file or prefix(%s) is invalid.", path, APP_DEK_FILE_PFX); - raw_buffer_s *prikey = NULL; - ret = _get_app_dek_kek(&prikey); + return WAE_ERROR_FILE; + } + char pkg_id[MAX_PKGID_LEN] = {0, }; + int ret = _extract_pkg_id_from_file_name(entry->d_name, pkg_id); if (ret != WAE_ERROR_NONE) { - WAE_SLOGE("Fail to get APP_DEK_KEK Private Key"); + WAE_SLOGW("Failed to extract pkgid from file(%s). It will be ignored.", file_path_buff); return ret; } - DIR *dir = opendir(_get_dek_store_path()); - - if (dir == NULL) { - WAE_SLOGE("Fail to open dir. dir=%s", _get_dek_store_path()); - buffer_destroy(prikey); - return WAE_ERROR_FILE; + ret = _load_preloaded_app_dek((raw_buffer_s *)prikey, file_path_buff, pkg_id); + if (ret == WAE_ERROR_NONE || ret == WAE_ERROR_KEY_EXISTS) { + WAE_SLOGI("Successfully load app dek(%s)", file_path_buff); + return WAE_ERROR_NONE; + } else { + WAE_SLOGW("Failed to load app dek(%s) ret(%d)", file_path_buff, ret); + return ret; } +} - struct dirent entry; - struct dirent *result = NULL; - - while (true) { - if (readdir_r(dir, &entry, &result) != 0) { - ret = WAE_ERROR_FILE; - break; - } - - // readdir_r returns NULL in *result if the end - // of the directory stream is reached - if (result == NULL) - break; - - // regular file && start with KEY_MANAGER_INITIAL_VALUE_FILE_PFX - if (entry.d_type != DT_REG || strstr(entry.d_name, APP_DEK_FILE_PFX) == NULL) - continue; +int load_preloaded_app_deks() +{ + WAE_SLOGI("load_preloaded_app_deks start"); - ret = snprintf(file_path_buff, sizeof(file_path_buff), "%s/%s", - _get_dek_store_path(), entry.d_name); + int ret = WAE_ERROR_NONE; - if (ret < 0) { - WAE_SLOGE("Failed to make file path by snprintf."); - ret = WAE_ERROR_INVALID_PARAMETER; /* buffer size too small */ - break; - } + const char *dek_store_path = _get_dek_store_path(); - ret = _extract_pkg_id_from_file_name(entry.d_name, pkg_id); + raw_buffer_s *prikey = NULL; + DIR *dir = NULL; - if (ret != WAE_ERROR_NONE) { - WAE_SLOGW("Failed to extract pkgid from file. It will be ignored. file=%s", - file_path_buff); - continue; - } + // check if all deks were already loaded into key-manager. + // TODO: instead of checking key-manager, check based on file existance + dir = opendir(dek_store_path); + if (dir == NULL) { + if (errno == ENOENT) { + WAE_SLOGI( + "dek store doesn't exist. " + "It might be loading preloaded app deks already done"); - ret = _load_preloaded_app_dek(prikey, file_path_buff, pkg_id); - if (ret != WAE_ERROR_NONE && ret != WAE_ERROR_KEY_EXISTS) { - WAE_SLOGW("Failed to load app dek(%s) ret(%d)", file_path_buff, ret); + return WAE_ERROR_NONE; } else { - WAE_SLOGI("Successfully load app dek(%s)", file_path_buff); - ret = WAE_ERROR_NONE; + WAE_SLOGE("Fail to open dir. dir=%s", dek_store_path); + ret = WAE_ERROR_FILE; + goto out; } } - buffer_destroy(prikey); + ret = _get_app_dek_kek(&prikey); + if (ret != WAE_ERROR_NONE) { + WAE_SLOGE("Fail to get APP_DEK_KEK Private Key. ret(%d)", ret); + goto out; + } + + // close dek store dir fd not to affect the traverse_directory call closedir(dir); + dir = NULL; + ret = traverse_directory(dek_store_path, _entry_callback_load_preloaded_adeks, prikey); if (ret != WAE_ERROR_NONE) - return ret; - else - return set_app_deks_loaded_to_key_manager(); + WAE_SLOGE("Fail when traverse dek store directory. ret(%d)", ret); + +out: + if (prikey != NULL) + buffer_destroy(prikey); + + if (dir != NULL) + closedir(dir); + + // remove dek store after loade done even though it's partially failed + // because malware can still put the file in dek store if it still system service's + // ownership and they can break this logic by inserting any file to dek store path. + // If KEK private key is inserted to key-manager with initial-value feature, malware + // cannot insert/encrypt/decrypt app dek so it's fine on preloaded app security but + // if we handle errors related loading file, malware can at least occur webappenc + // initializer service failure. + _remove_directory(dek_store_path); + + return ret; } int remove_app_ce(uid_t uid, const char *pkg_id, wae_app_type_e app_type) |