diff options
Diffstat (limited to 'srcs/key_manager.c')
-rw-r--r-- | srcs/key_manager.c | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/srcs/key_manager.c b/srcs/key_manager.c new file mode 100644 index 0000000..4ef5b8a --- /dev/null +++ b/srcs/key_manager.c @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2016 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_manager.c + * @author Kyungwook Tak + * @version 1.0 + * @brief Serialize/deserialize crypto element and save/get to key-manager + */ +#include "key_manager.h" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <ckmc/ckmc-manager.h> + +#include "wae_log.h" + +#define MAX_ALIAS_LEN 256 +#define APP_DEK_ALIAS_PFX "APP_DEK_" +#define APP_DEK_LOADING_DONE_ALIAS "APP_DEKS_LOADING_FINISHED" +#define APP_DEK_KEK_ALIAS "WAE_APP_DEK_KEK" + +static int _to_wae_error(int key_manager_error) +{ + switch (key_manager_error) { + case CKMC_ERROR_NONE: + return WAE_ERROR_NONE; + + case CKMC_ERROR_INVALID_PARAMETER: + return WAE_ERROR_INVALID_PARAMETER; + + case CKMC_ERROR_PERMISSION_DENIED: + return WAE_ERROR_PERMISSION_DENIED; + + case CKMC_ERROR_DB_ALIAS_UNKNOWN: + return WAE_ERROR_NO_KEY; + + case CKMC_ERROR_DB_ALIAS_EXISTS: + return WAE_ERROR_KEY_EXISTS; + + case CKMC_ERROR_OUT_OF_MEMORY: + return WAE_ERROR_MEMORY; + + default: + return WAE_ERROR_KEY_MANAGER; + } +} + +static int _serialize(const crypto_element_s *ce, ckmc_raw_buffer_s **pbuf) +{ + if (!is_crypto_element_valid(ce) || pbuf == NULL) + return WAE_ERROR_INVALID_PARAMETER; + + size_t total_len = sizeof(size_t) * 3 + ce->dek->size + ce->iv->size + sizeof(bool); + + WAE_SLOGD("(serialization) total(%d) dek(%d) iv(%d) is_migrated(%d)", + total_len, ce->dek->size, ce->iv->size, ce->is_migrated_app); + + unsigned char *_buf = (unsigned char *)malloc(total_len); + if (_buf == NULL) + return WAE_ERROR_MEMORY; + + ckmc_raw_buffer_s *buf = NULL; + int ret = _to_wae_error(ckmc_buffer_new(_buf, total_len, &buf)); + + free(_buf); + + if (ret != WAE_ERROR_NONE) + return ret; + + size_t pos = 0; + memcpy(buf->data, &total_len, sizeof(size_t)); + pos += sizeof(size_t); + memcpy(buf->data + pos, &ce->dek->size, sizeof(size_t)); + pos += sizeof(size_t); + memcpy(buf->data + pos, ce->dek->buf, ce->dek->size); + pos += ce->dek->size; + memcpy(buf->data + pos, &ce->iv->size, sizeof(size_t)); + pos += sizeof(size_t); + memcpy(buf->data + pos, ce->iv->buf, ce->iv->size); + pos += ce->iv->size; + memcpy(buf->data + pos, &ce->is_migrated_app, sizeof(bool)); + pos += sizeof(bool); + + if (total_len != pos) { + WAE_SLOGE("(serialization) total len(%d) and actualy written byte(%d) " + "isn't matched!", total_len, pos); + ckmc_buffer_free(buf); + return WAE_ERROR_UNKNOWN; + } + + *pbuf = buf; + + WAE_SLOGD("(serialization) success!"); + + return WAE_ERROR_NONE; +} + +static int _deserialize(const ckmc_raw_buffer_s *buf, crypto_element_s **pce) +{ + if (buf == NULL || buf->data == NULL || buf->size == 0 || pce == NULL) + return WAE_ERROR_INVALID_PARAMETER; + + size_t dek_size = 0; + size_t iv_size = 0; + bool is_migrated_app = false; + size_t pos = 0; + size_t total_len = 0; + crypto_element_s *ce = NULL; + + memcpy(&total_len, buf->data, sizeof(size_t)); + pos += sizeof(size_t); + + if (buf->size != total_len) { + WAE_SLOGE("(deserialization) total len(%d) and actualy written byte(%d) " + "isn't matched!", total_len, buf->size); + return WAE_ERROR_UNKNOWN; + } + + // deserialize dek size + memcpy(&dek_size, buf->data + pos, sizeof(size_t)); + pos += sizeof(size_t); + + raw_buffer_s *dek = buffer_create(dek_size); + if (dek == NULL) + return WAE_ERROR_MEMORY; + + // deserialize dek + memcpy(dek->buf, buf->data + pos, dek->size); + pos += dek->size; + + // deserialize iv size + memcpy(&iv_size, buf->data + pos, sizeof(size_t)); + pos += sizeof(size_t); + + raw_buffer_s *iv = buffer_create(iv_size); + int ret = WAE_ERROR_NONE; + if (iv == NULL) { + ret = WAE_ERROR_MEMORY; + goto error; + } + + // deserialize iv + memcpy(iv->buf, buf->data + pos, iv->size); + pos += iv->size; + + // deserialize is_migrated_app + memcpy(&is_migrated_app, buf->data + pos, sizeof(bool)); + pos += sizeof(bool); + + WAE_SLOGD("(deserialization) total(%d) dek(%d) iv(%d) is_migrated(%d)", + total_len, dek_size, iv_size, is_migrated_app); + + if (pos != buf->size) { + WAE_SLOGE("(deserialization) raw buffer remained after deserializatation done!"); + ret = WAE_ERROR_UNKNOWN; + goto error; + } + + ce = crypto_element_create(dek, iv); + if (ce == NULL) { + ret = WAE_ERROR_MEMORY; + goto error; + } + + ce->is_migrated_app = is_migrated_app; + + *pce = ce; + + WAE_SLOGD("(deserialization) success!"); + + return WAE_ERROR_NONE; + +error: + buffer_destroy(dek); + buffer_destroy(iv); + + return ret; +} + +static void _get_alias(const char *pkg_id, wae_app_type_e type, bool forSave, + char *alias, size_t buff_len) +{ + if (type == WAE_DOWNLOADED_NORMAL_APP) { + if (forSave) { + snprintf(alias, buff_len, "%s%s", + APP_DEK_ALIAS_PFX, + pkg_id); + } else { + snprintf(alias, buff_len, "%c%s%s%s%s", + '/', INSTALLER_LABEL, + ckmc_owner_id_separator, + APP_DEK_ALIAS_PFX, + pkg_id); + } + } else { // system alias + snprintf(alias, buff_len, "%s%s%s%s", + ckmc_owner_id_system, + ckmc_owner_id_separator, + APP_DEK_ALIAS_PFX, + pkg_id); + } +} + +static void _get_dek_loading_done_alias(char *alias, size_t buff_len) +{ + snprintf(alias, buff_len, "%s%s%s", + ckmc_owner_id_system, + ckmc_owner_id_separator, + APP_DEK_LOADING_DONE_ALIAS); +} + +bool is_app_deks_loaded_in_key_manager() +{ + char alias[MAX_ALIAS_LEN] = {0, }; + + _get_dek_loading_done_alias(alias, sizeof(alias)); + + ckmc_raw_buffer_s *buf = NULL; + int ret = _to_wae_error(ckmc_get_data(alias, NULL, &buf)); + + ckmc_buffer_free(buf); + + switch (ret) { + case WAE_ERROR_NONE: + return true; + case WAE_ERROR_NO_KEY: + WAE_SLOGI("app dek loading isn't done yet"); + return false; + default: + WAE_SLOGE("Failed to get dek loading flag data from key-manager. ret(%d)", ret); + return false; + } +} + +int set_app_deks_loaded_to_key_manager() +{ + unsigned char dummy_data[1] = {0}; + ckmc_raw_buffer_s buf; + buf.data = dummy_data; + buf.size = sizeof(dummy_data); + + ckmc_policy_s policy; + policy.password = NULL; + policy.extractable = true; + + char alias[MAX_ALIAS_LEN] = {0, }; + _get_dek_loading_done_alias(alias, sizeof(alias)); + + int ret = _to_wae_error(ckmc_save_data(alias, buf, policy)); + if (ret == WAE_ERROR_KEY_EXISTS) + ret = WAE_ERROR_NONE; + + return ret; +} + +int clear_app_deks_loaded_from_key_manager() +{ + char alias[MAX_ALIAS_LEN] = {0, }; + _get_dek_loading_done_alias(alias, sizeof(alias)); + + return _to_wae_error(ckmc_remove_alias(alias)); +} + +int save_to_key_manager(const char *pkg_id, wae_app_type_e type, const crypto_element_s *ce) +{ + char alias[MAX_ALIAS_LEN] = {0, }; + + _get_alias(pkg_id, type, true, alias, sizeof(alias)); + + ckmc_raw_buffer_s *buf = NULL; + int ret = _serialize(ce, &buf); + if (ret != WAE_ERROR_NONE) { + WAE_SLOGE("Failed to serialize crypto element of pkg_id: %s", pkg_id); + return ret; + } + + ckmc_policy_s policy; + policy.password = NULL; + policy.extractable = true; + + ret = _to_wae_error(ckmc_save_data(alias, *buf, policy)); + + ckmc_buffer_free(buf); + + if (ret != WAE_ERROR_NONE) { + WAE_SLOGE("Failed to add crypto element to ckm: pkg_id(%s) alias(%s) ret(%d)", + pkg_id, alias, ret); + return ret; + } + + ret = _to_wae_error(ckmc_set_permission(alias, pkg_id, CKMC_PERMISSION_READ)); + if (ret != WAE_ERROR_NONE) { + WAE_SLOGE("Failed to set perm of crypto element: pkg_id(%s) alias(%s) ret(%d)", + pkg_id, alias, ret); + + ckmc_remove_alias(alias); // rollback + return ret; + } + + WAE_SLOGI("Success to save crypto element to key-manager. pkg_id(%s)", pkg_id); + + return WAE_ERROR_NONE; +} + +int get_from_key_manager(const char *pkg_id, wae_app_type_e type, crypto_element_s **pce) +{ + if (pkg_id == NULL || pce == NULL) + return WAE_ERROR_INVALID_PARAMETER; + + char alias[MAX_ALIAS_LEN] = {0, }; + + _get_alias(pkg_id, type, false, alias, sizeof(alias)); + + ckmc_raw_buffer_s *buf = NULL; + int ret = _to_wae_error(ckmc_get_data(alias, NULL, &buf)); + if (ret != WAE_ERROR_NONE) + return ret; + + ret = _deserialize(buf, pce); + + ckmc_buffer_free(buf); + + return ret; +} + +int remove_from_key_manager(const char *pkg_id, wae_app_type_e type) +{ + char alias[MAX_ALIAS_LEN] = {0, }; + + _get_alias(pkg_id, type, true, alias, sizeof(alias)); + + return _to_wae_error(ckmc_remove_alias(alias)); +} + +static void _get_dek_kek_alias(char *alias, size_t buff_len) +{ + snprintf(alias, buff_len, "%s%s%s", + ckmc_owner_id_system, + ckmc_owner_id_separator, + APP_DEK_KEK_ALIAS); +} + +int get_dek_kek_from_key_manager(raw_buffer_s **pdek_kek) +{ + if (pdek_kek == NULL) + return WAE_ERROR_INVALID_PARAMETER; + + ckmc_raw_buffer_s *buf = NULL; + + char alias[MAX_ALIAS_LEN] = {0, }; + _get_dek_kek_alias(alias, sizeof(alias)); + + int ret = _to_wae_error(ckmc_get_data(alias, NULL, &buf)); + if (ret != WAE_ERROR_NONE) { + WAE_SLOGE("Failed to get dek kek from key-manager. alias(%s) ret(%d)", + alias, ret); + return ret; + } + + raw_buffer_s *dek_kek = buffer_create(buf->size); + if (dek_kek == NULL) { + ret = WAE_ERROR_MEMORY; + goto error; + } + memcpy(dek_kek->buf, buf->data, dek_kek->size); + + *pdek_kek = dek_kek; + + WAE_SLOGI("Success to get dek kek from key-manager."); + +error: + ckmc_buffer_free(buf); + + if (ret != WAE_ERROR_NONE) + buffer_destroy(dek_kek); + + return ret; +} |