summaryrefslogtreecommitdiff
path: root/srcs/key_manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'srcs/key_manager.c')
-rw-r--r--srcs/key_manager.c393
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;
+}