/* * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License * * * @file key_handler.c * @author Dongsun Lee (ds73.lee@samsung.com) * @version 1.0 * @brief a header for key manupulatation. */ #include #include #include #include #include #include #include "wae_log.h" #include "web_app_enc.h" #include "key_handler.h" #include "crypto_service.h" #include #define APP_DEK_KEK_PRIKEY_PASSWORD "wae_appdek_kek_1q2w3e4r" typedef struct _dek_cache_element{ char pkgId[MAX_PKGID_LEN]; unsigned char dek[DEK_LEN]; } dek_cache_element; dek_cache_element APP_DEK_CACHE[MAX_CACHE_SIZE]; int NEXT_CACHE_IDX = -1; void _initialize_cache() { NEXT_CACHE_IDX = 0; memset(APP_DEK_CACHE, 0, sizeof(dek_cache_element)*MAX_CACHE_SIZE); } unsigned char* _get_app_dek_from_cache(const char* pkgId) { int i = 0; if(NEXT_CACHE_IDX < 0) _initialize_cache(); for(i =0; i= MAX_CACHE_SIZE) NEXT_CACHE_IDX = 0; } void _remove_app_dek_from_cache(const char* pkgId) { int i = 0; for(i =0; idata, DEK_LEN); *ppDek = pDek; *dekLen = DEK_LEN; WAE_SLOGI("Success to get APP_DEK from key-manager. pkgId=%s", pPkgId); error: if(pDekBuffer != NULL) ckmc_buffer_free(pDekBuffer); if(ret != WAE_ERROR_NONE && pDek != NULL) free(pDek); return ret; } int create_app_dek(const char* pPkgId, unsigned char** ppDek, size_t* dekLen) { int ret = WAE_ERROR_NONE; unsigned char *dek= NULL; dek = (unsigned char*) malloc(DEK_LEN); if(dek == NULL) { ret = WAE_ERROR_MEMORY; goto error; } ret = _get_random(DEK_LEN, dek); if(ret != WAE_ERROR_NONE) { WAE_SLOGE("Fail to get random for APP_DEK. pkgId=%s, ret=%d", pPkgId, ret); goto error; } // save app_dek in key_manager ret = _add_dek_to_key_manager(pPkgId, dek, DEK_LEN); if(ret != WAE_ERROR_NONE) { goto error; } // store APP_DEK in cache _add_app_dek_to_cache(pPkgId, dek); *ppDek = dek; *dekLen = DEK_LEN; WAE_SLOGI("Success to create APP_DEK and store it in key-manager. pkgId=%s", pPkgId); error: if(ret != WAE_ERROR_NONE && dek != NULL) free(dek); return ret; } int get_preloaded_app_dek(const char* pPkgId, unsigned char** ppDek, size_t* dekLen) { int ret = WAE_ERROR_NONE; unsigned char* cached_dek= NULL; unsigned char* dek = NULL; // get dek from cache cached_dek = _get_app_dek_from_cache(pPkgId); if(cached_dek == NULL) { WAE_SLOGE("Fail to get APP_DEK from cache for preloaded app"); ret = WAE_ERROR_NO_KEY; goto error; } dek = (unsigned char*) malloc(DEK_LEN); if(dek == NULL) { WAE_SLOGE("Fail to allocate memory for preloaded app dek"); ret = WAE_ERROR_MEMORY; goto error; } memcpy(dek, cached_dek, DEK_LEN); *ppDek = dek; *dekLen = DEK_LEN; error: if(ret != WAE_ERROR_NONE && dek != NULL) free(dek); return ret; } int create_preloaded_app_dek(const char* pPkgId, unsigned char** ppDek, size_t* dekLen) { int ret = WAE_ERROR_NONE; unsigned char* dek = NULL; unsigned char* encrypted_app_dek = NULL; size_t encrypted_app_dek_len = 0; unsigned char* pubKey = NULL; size_t pubKeyLen = 0; // create APP_DEK dek = (unsigned char*) malloc(DEK_LEN); if(dek == NULL) { ret = WAE_ERROR_MEMORY; goto error; } ret = _get_random(DEK_LEN, dek); if(ret != WAE_ERROR_NONE) { goto error; } // encrypt APP_DEK with APP_DEK_KEK ret = _read_from_file(_get_dek_kek_pub_key_path(), &pubKey, &pubKeyLen); if(ret != WAE_ERROR_NONE) { WAE_SLOGE("Fail to read APP_DEK_KEK Public Key"); goto error; } ret = encrypt_app_dek(pubKey, pubKeyLen, dek, DEK_LEN, &encrypted_app_dek, &encrypted_app_dek_len); if(ret != WAE_ERROR_NONE) { WAE_SLOGE("Fail to encrypt APP_DEK with APP_DEK_KEK"); goto error; } // write APP_DEK in a file ret = _write_encrypted_app_dek_to_file(pPkgId, encrypted_app_dek, encrypted_app_dek_len); if(ret != WAE_ERROR_NONE) { WAE_SLOGE("Fail to write encrypted APP_DEK. pkgId=%s", pPkgId); goto error; } // store APP_DEK in cache _add_app_dek_to_cache(pPkgId, dek); *ppDek = dek; *dekLen = DEK_LEN; WAE_SLOGI("Success to create preleaded APP_DEK and write it in initail value file. pkgId=%s", pPkgId); error: if(pubKey != NULL) free(pubKey); if(encrypted_app_dek != NULL) free(encrypted_app_dek); if(ret != WAE_ERROR_NONE && dek != NULL) free(dek); return ret; } int _get_app_dek_kek(unsigned char** ppDekKek, size_t* kekLen) { int ret = WAE_ERROR_NONE; ret = _read_from_file(_get_dek_kek_pri_key_path(), ppDekKek, kekLen); if(ret != WAE_ERROR_NONE) { WAE_SLOGE("Fail to read APP_DEK_KEK Private Key"); return ret; } /* char* password = NULL; ckmc_raw_buffer_s *pKekBuffer = NULL; unsigned char* pKek = NULL; char dek_kek_alias[MAX_ALIAS_LEN] = {0, }; _get_dek_kek_alias(dek_kek_alias, sizeof(dek_kek_alias)); ret = _to_wae_error(ckmc_get_data(dek_kek_alias, password, &pKekBuffer)); if(ret != WAE_ERROR_NONE) { WAE_SLOGE("Fail to get APP_DEK_KEK from key-manager. alias=%s, ret=%d", APP_DEK_KEK_ALIAS, ret); goto error; } pKek = (unsigned char*) malloc(pKekBuffer->size); if(pKek == NULL) { WAE_SLOGE("Fail to allocate a memory"); ret = WAE_ERROR_MEMORY; goto error; } memcpy(pKek, pKekBuffer->data, pKekBuffer->size); *ppDekKek = pKek; *kekLen = pKekBuffer->size; WAE_SLOGI("Success to get APP_DEK_KEK from key-manager."); error: if(pKekBuffer != NULL) ckmc_buffer_free(pKekBuffer); if(ret != WAE_ERROR_NONE && pKek != NULL) free(pKek); */ return ret; } int _get_app_deks_loaded() { int ret = WAE_ERROR_NONE; ckmc_raw_buffer_s *pBuffer = NULL; char loading_done_alias[MAX_ALIAS_LEN] = {0, }; _get_dek_loading_done_alias(loading_done_alias, sizeof(loading_done_alias)); ret = _to_wae_error(ckmc_get_data(loading_done_alias, NULL, &pBuffer)); if(ret == WAE_ERROR_NO_KEY) { WAE_SLOGI("APP_DEK_LOADING was not done"); } else if(ret == WAE_ERROR_NONE) { WAE_SLOGI("APP_DEK_LOADING was already done"); } else { WAE_SLOGE("Fail to get information from key-manager about APP_DEK_LOADING_DONE_ALIAS. ret=%d", ret); goto error; } error: if(pBuffer != NULL) ckmc_buffer_free(pBuffer); return ret; } int _set_app_deks_loaded() { int ret = WAE_ERROR_NONE; ckmc_raw_buffer_s buff; ckmc_policy_s policy; unsigned char dummyData[1] = {0}; buff.data = dummyData; buff.size = sizeof(dummyData); policy.password = NULL; policy.extractable = true; char loading_done_alias[MAX_ALIAS_LEN] = {0, }; _get_dek_loading_done_alias(loading_done_alias, sizeof(loading_done_alias)); ret = _to_wae_error(ckmc_save_data(loading_done_alias, buff, policy)); if(ret == WAE_ERROR_KEY_EXISTS) { WAE_SLOGI("APP_DEK_LOADING was already done"); ret = WAE_ERROR_NONE; } else if(ret != WAE_ERROR_NONE) { WAE_SLOGE("Fail to set APP_DEK_LOADING_DONE_ALIAS to key-manager. ret=%d", ret); goto error; } WAE_SLOGI("Success to set APP_DEK_LOADING_DONE_ALIAS to key-manager."); error: return ret; } int _clear_app_deks_loaded() { int ret = WAE_ERROR_NONE; char loading_done_alias[MAX_ALIAS_LEN] = {0, }; _get_dek_loading_done_alias(loading_done_alias, sizeof(loading_done_alias)); ret = _to_wae_error(ckmc_remove_alias(loading_done_alias)); if(ret == WAE_ERROR_NO_KEY) { WAE_SLOGI("APP_DEK_LOADING_DONE_ALIAS was not set to key-manager before."); ret = WAE_ERROR_NONE; }else if(ret != WAE_ERROR_NONE) { WAE_SLOGE("Fail to clear APP_DEK_LOADING_DONE_ALIAS to key-manager. ret=%d", ret); } return ret; } int load_preloaded_app_deks(int reload) { int ret = WAE_ERROR_NONE; char pkgId[MAX_PKGID_LEN] = {0, }; DIR *dir = NULL; struct dirent entry; struct dirent *result; int error; char file_path_buff[MAX_PATH_LEN]; unsigned char* encrypted_app_dek = NULL; size_t encrypted_app_dek_len = 0; unsigned char* app_dek = NULL; size_t app_dek_len = 0; unsigned char* priKey = NULL; size_t priKeyLen = 0; int error_during_loading = 0; if(reload != WAE_TRUE) { // check if all deks were already loaded into key-manager. ret = _get_app_deks_loaded(); if(ret == WAE_ERROR_NONE) { return ret; } } ret = _get_app_dek_kek(&priKey, &priKeyLen); if(ret != WAE_ERROR_NONE) { WAE_SLOGE("Fail to get APP_DEK_KEK Private Key"); return ret; } dir = opendir(_get_dek_store_path()); if(dir == NULL) { WAE_SLOGE("Fail to open dir. dir=%s", _get_dek_store_path()); ret = WAE_ERROR_FILE; goto error; } for(;;) { error = readdir_r(dir, &entry, &result); if( error != 0 ) { ret = WAE_ERROR_FILE; goto error; } // 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) { memset(file_path_buff, 0, sizeof(file_path_buff)); sprintf(file_path_buff, "%s/%s", _get_dek_store_path(), entry.d_name); ret = _extract_pkg_id_from_file_name(entry.d_name, pkgId); if(ret != WAE_ERROR_NONE) { WAE_SLOGW("Fail to extract pkgid from file. It will be ignored. file=%s",file_path_buff); continue; } ret = _read_from_file(file_path_buff, &encrypted_app_dek, &encrypted_app_dek_len); if(ret != WAE_ERROR_NONE || encrypted_app_dek == NULL) { error_during_loading++; WAE_SLOGW("Fail to read file. It will be ignored. file=%s",file_path_buff); continue; } ret = decrypt_app_dek(priKey, priKeyLen, APP_DEK_KEK_PRIKEY_PASSWORD, encrypted_app_dek, encrypted_app_dek_len, &app_dek, &app_dek_len); if(ret != WAE_ERROR_NONE || app_dek == NULL) { error_during_loading++; WAE_SLOGW("Fail to decrypt APP DEK. It will be ignored. file=%s",file_path_buff); continue; } // save app_dek in key_manager ret = _add_dek_to_key_manager(pkgId, app_dek, app_dek_len); // free temp objects free(app_dek); free(encrypted_app_dek); app_dek = NULL; encrypted_app_dek = NULL; if(ret == WAE_ERROR_KEY_EXISTS) { WAE_SLOGI("Key Manager already has APP_DEK. It will be ignored. file=%s",file_path_buff); continue; }else if(ret != WAE_ERROR_NONE) { error_during_loading++; WAE_SLOGW("Fail to add APP DEK to key-manager. file=%s",file_path_buff); continue; } } } ret = _set_app_deks_loaded(); if(ret == WAE_ERROR_NONE) { WAE_SLOGI("Success to load_preloaded_app_deks"); ret = WAE_ERROR_NONE; }else { WAE_SLOGW("Fail to _set_app_deks_loaded to key-manager. ret=%d", ret); } error: if(priKey != NULL) free(priKey); return ret; } int remove_app_dek(const char* pPkgId) { int ret = CKMC_ERROR_NONE; char alias[MAX_ALIAS_LEN] = {0,}; _get_alias(pPkgId, alias,sizeof(alias)); ret = _to_wae_error(ckmc_remove_alias(alias)); if(ret != WAE_ERROR_NONE) { WAE_SLOGE("Fail to remove APP_DEK from key-manager. pkgId=%s, alias=%s, ret=%d", pPkgId, alias, ret); goto error; } _remove_app_dek_from_cache(pPkgId); WAE_SLOGI("Success to remove APP_DEK from key-manager. pkgId=%s", pPkgId); error: return WAE_ERROR_NONE; }