Migrate secure-storage data 22/79422/5
authorKyungwook Tak <k.tak@samsung.com>
Mon, 11 Jul 2016 09:30:51 +0000 (18:30 +0900)
committerkyungwook tak <k.tak@samsung.com>
Tue, 19 Jul 2016 01:01:20 +0000 (18:01 -0700)
Change-Id: Ifa89e9086a40f8dcbd82bdbc26fe14a7dcc1c8c1
Signed-off-by: Kyungwook Tak <k.tak@samsung.com>
17 files changed:
data/scripts/233.key-manager-move-ss-migratable-data.patch.sh.in [new file with mode: 0755]
data/scripts/CMakeLists.txt
packaging/key-manager.spec
src/CMakeLists.txt
src/manager/service/ckm-logic.cpp
src/manager/service/ss-migrate.cpp [new file with mode: 0644]
src/manager/service/ss-migrate.h [new file with mode: 0644]
tests/secure-storage-old-data/README [new file with mode: 0644]
tests/secure-storage-old-data/push-data.sh [new file with mode: 0644]
tests/secure-storage-old-data/secure-storage/salt [new file with mode: 0644]
tests/secure-storage-old-data/secure-storage::test1/test-data-1 [new file with mode: 0644]
tests/secure-storage-old-data/secure-storage::test1/test-data-2 [new file with mode: 0644]
tests/secure-storage-old-data/secure-storage::test1/test-data-3 [new file with mode: 0644]
tests/secure-storage-old-data/secure-storage::test2/test-data-1 [new file with mode: 0644]
tests/secure-storage-old-data/secure-storage::test2/test-data-2 [new file with mode: 0644]
tests/secure-storage-old-data/secure-storage::test2/test-data-3 [new file with mode: 0644]
tools/ckm_db_tool/CMakeLists.txt

diff --git a/data/scripts/233.key-manager-move-ss-migratable-data.patch.sh.in b/data/scripts/233.key-manager-move-ss-migratable-data.patch.sh.in
new file mode 100755 (executable)
index 0000000..c0f3fcc
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/bash
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+
+# 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        233.key-manager-move-ss-migratable-data.patch.sh.in
+# @author      Kyungwook Tak (k.tak@samsung.com)
+# @brief       Moves old secure-storage data to key-manager dir to be
+#              readable/writable/removable
+
+OLD_SS_PATH="/opt/share/secure-storage"
+MIGRATED_SS_PATH="@RW_DATA_DIR@/secure-storage"
+
+mv ${OLD_SS_PATH} ${MIGRATED_SS_PATH}
+
+for d in `ls ${MIGRATED_SS_PATH}`
+do
+       chsmack -a "@SMACK_DOMAIN_NAME@" "${MIGRATED_SS_PATH}/${d}"
+       chmod 770 ${MIGRATED_SS_PATH}/${d}
+
+       for f in `ls ${MIGRATED_SS_PATH}/${d}`
+       do
+               chsmack -a "@SMACK_DOMAIN_NAME@" "${MIGRATED_SS_PATH}/${d}/${f}"
+       done
+done
+
+chown -R @USER_NAME@:@GROUP_NAME@ ${MIGRATED_SS_PATH}
+chmod 770 ${MIGRATED_SS_PATH}
index f709fa0..57316f2 100644 (file)
@@ -29,10 +29,15 @@ CONFIGURE_FILE(232.key-manager-change-user.patch.sh.in
                232.key-manager-change-user.patch.sh
                @ONLY)
 
+CONFIGURE_FILE(233.key-manager-move-ss-migratable-data.patch.sh.in
+               233.key-manager-move-ss-migratable-data.patch.sh
+               @ONLY)
+
 INSTALL(FILES
         230.key-manager-change-data-dir.patch.sh
         231.key-manager-migrate-dkek.patch.sh
         232.key-manager-change-user.patch.sh
+        233.key-manager-move-ss-migratable-data.patch.sh
     DESTINATION ${RO_ETC_DIR}/opt/upgrade
     PERMISSIONS
         OWNER_READ
index 23e8703..b6b02b6 100644 (file)
@@ -248,6 +248,7 @@ fi
 %{ro_etc_dir}/opt/upgrade/230.key-manager-change-data-dir.patch.sh
 %{ro_etc_dir}/opt/upgrade/231.key-manager-migrate-dkek.patch.sh
 %{ro_etc_dir}/opt/upgrade/232.key-manager-change-user.patch.sh
+%{ro_etc_dir}/opt/upgrade/233.key-manager-move-ss-migratable-data.patch.sh
 %{ro_etc_dir}/gumd/userdel.d/10_key-manager.post
 %{bin_dir}/ckm_tool
 
index 574b249..66bdb43 100644 (file)
@@ -56,6 +56,7 @@ SET(KEY_MANAGER_SOURCES
     ${KEY_MANAGER_PATH}/service/ocsp.cpp
     ${KEY_MANAGER_PATH}/service/ocsp-logic.cpp
     ${KEY_MANAGER_PATH}/service/ocsp-service.cpp
+    ${KEY_MANAGER_PATH}/service/ss-migrate.cpp
     ${KEY_MANAGER_PATH}/initial-values/parser.cpp
     ${KEY_MANAGER_PATH}/initial-values/BufferHandler.cpp
     ${KEY_MANAGER_PATH}/initial-values/CertHandler.cpp
index 167f013..2f1a228 100644 (file)
@@ -33,6 +33,7 @@
 #include <algorithm>
 #include <sw-backend/store.h>
 #include <generic-backend/exception.h>
+#include <ss-migrate.h>
 
 namespace {
 const char *const CERT_SYSTEM_DIR          = CA_CERTS_DIR;
@@ -129,6 +130,23 @@ int CKMLogic::unlockDatabase(uid_t user, const Password &password)
                                handle.database.deleteKey(appSmackLabel);
                        }
                }
+
+               if (user == SYSTEM_DB_UID && hasMigratableData()) {
+                       migrateData([this](const std::string &owner,
+                                                          const std::string &name,
+                                                          const Crypto::Data &data) {
+                               LogInfo("Saver called with owner: " << owner << " name: " << name);
+
+                               Credentials cred(0, OWNER_ID_SYSTEM);
+
+                               int ret = this->verifyAndSaveDataHelper(
+                                               Credentials(0, OWNER_ID_SYSTEM), (owner + "-" + name),
+                                               OWNER_ID_SYSTEM, data, PolicySerializable());
+                               if (ret != CKM_API_SUCCESS)
+                                       LogError("Failed to migrate secure-storage data. owner: " << owner <<
+                                                        " name: " << name << " ret: " << ret);
+                       });
+               }
        } catch (const Exc::Exception &e) {
                retCode = e.error();
        } catch (const CKM::Exception &e) {
diff --git a/src/manager/service/ss-migrate.cpp b/src/manager/service/ss-migrate.cpp
new file mode 100644 (file)
index 0000000..5bf0179
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ *  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        ss-migrate.cpp
+ * @author      Kyungwook Tak (k.tak@samsung.com)
+ * @version     1.0
+ * @brief       Deprecated secure-storage data migration
+ */
+#include <ss-migrate.h>
+
+#include <fstream>
+#include <memory>
+#include <cstring>
+#include <cerrno>
+#include <cstddef>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/stat.h>
+
+#include <openssl/sha.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+
+#include <dpl/log/log.h>
+
+namespace CKM {
+
+namespace {
+
+const std::string OLD_SS_DIR = RW_DATA_DIR "/secure-storage";
+const std::string OLD_SS_GROUP_PREFIX = "secure-storage::";
+const int SALT_SIZE = 32;
+const int KEY_SIZE = 16;
+
+std::unique_ptr<char[]> get_key(const std::string &id, size_t len)
+{
+       unsigned char salt[SALT_SIZE];
+
+       ::memset(salt, 0xFF, SALT_SIZE);
+
+       std::unique_ptr<char[]> duk(new char[len + 1]);
+
+       ::PKCS5_PBKDF2_HMAC_SHA1(id.c_str(), id.length(), salt, SALT_SIZE, 1,
+                       len, reinterpret_cast<unsigned char *>(duk.get()));
+
+       duk[len] = '\0';
+
+       return duk;
+}
+
+RawBuffer read_data(const std::string &filepath, const std::string &seed)
+{
+       std::ifstream f(filepath.c_str(), std::ios::binary);
+
+       if (!f.is_open()) {
+               LogError("Failed to open file: " << filepath);
+               return RawBuffer();
+       }
+
+       f.seekg(0, f.end);
+       auto ciphertext_len = f.tellg();
+       if (ciphertext_len == -1) {
+               LogError("Failed to get file length: " << filepath);
+               return RawBuffer();
+       }
+
+       f.seekg(0, f.beg);
+
+       RawBuffer ciphertext(ciphertext_len, 0);
+
+       f.read(reinterpret_cast<char *>(ciphertext.data()), ciphertext.size());
+       if (!f) {
+               LogError("Failed to read file: " << filepath);
+               return RawBuffer();
+       }
+
+       auto key = get_key(seed, KEY_SIZE);
+       std::unique_ptr<char[]> iv(new char[KEY_SIZE]);
+       size_t ivlen = 0;
+       if (::EVP_Digest(key.get(), KEY_SIZE, reinterpret_cast<unsigned char *>(iv.get()),
+                               &ivlen, ::EVP_sha1(), nullptr) != 1) {
+               LogError("Failed to get iv");
+               return RawBuffer();
+       }
+
+       // start decrypt data with key and iv
+       auto algo = ::EVP_aes_128_cbc();
+       int tmp_len = (ciphertext.size() / algo->block_size + 1) * algo->block_size;
+       RawBuffer plaintext(tmp_len, 0);
+
+       std::unique_ptr<EVP_CIPHER_CTX, void(*)(EVP_CIPHER_CTX *)> ctxptr(
+                       ::EVP_CIPHER_CTX_new(), ::EVP_CIPHER_CTX_free);
+
+       if (ctxptr == nullptr)
+               throw std::bad_alloc();
+
+       auto ctx = ctxptr.get();
+
+       int ec = ::EVP_CIPHER_CTX_set_padding(ctx, 1);
+       if (ec != 1) {
+               LogError("Failed to evp ctx set padding. ec: " << ec);
+               return RawBuffer();
+       }
+
+       ec = ::EVP_CipherInit(ctx, algo, reinterpret_cast<unsigned char *>(key.get()),
+                       reinterpret_cast<unsigned char *>(iv.get()), 0 /* decrypt flag */);
+       if (ec != 1) {
+               LogError("Failed to evp cipher init. ec: " << ec);
+               return RawBuffer();
+       }
+
+       int plaintext_len = 0;
+       ec = ::EVP_CipherUpdate(ctx, plaintext.data(), &plaintext_len,
+                       ciphertext.data(), ciphertext.size());
+       if (ec != 1) {
+               LogError("Failed to evp cipher update. ec: " << ec);
+               return RawBuffer();
+       }
+
+       int final_len = 0;
+       ec = EVP_CipherFinal(ctx, plaintext.data() + plaintext_len, &final_len);
+       if (ec != 1) {
+               LogError("Failed to evp cipher final. ec: " << ec);
+               return RawBuffer();
+       }
+
+       plaintext_len += final_len;
+
+       plaintext.resize(plaintext_len);
+
+       return plaintext;
+}
+
+inline void remove_path(const std::string &path)
+{
+       if (::remove(path.c_str()) == -1)
+               LogError("Failed to remove path: " << path << " with errno: " << errno);
+}
+
+// depth 0 -> OLD_SS_DIR
+//       1 -> group dir in OLD_SS_DIR
+void visit_dir(const std::string &dirpath, struct dirent *buf, size_t depth,
+                         const Saver &saver)
+{
+       if (depth > 1) {
+               LogError("Invalid depth in secure-storage subdir... dirpath: " << dirpath);
+               return;
+       }
+
+       std::unique_ptr<DIR, int(*)(DIR *)> dirptr(::opendir(dirpath.c_str()), ::closedir);
+       if (dirptr == nullptr) {
+               LogError("Failed to open dir: " << dirpath << " with errno: " << errno);
+               return;
+       }
+
+       while (true) {
+               struct dirent *result = nullptr;
+               auto ret = ::readdir_r(dirptr.get(), buf, &result);
+               if (ret != 0) {
+                       LogError("readdir_r error on secure-storage dir: " << dirpath <<
+                                        " with errno: " << errno);
+                       break;
+               } else if (result == nullptr) {
+                       remove_path(dirpath);
+                       break;
+               }
+
+               const auto &name = result->d_name;
+               auto name_size = ::strlen(name);
+
+               std::string path = dirpath + "/" + name;
+               if (result->d_type == DT_DIR) {
+                       if ((name_size == 1 && name[0] == '.') ||
+                               (name_size == 2 && name[0] == '.' && name[1] == '.')) {
+                               continue;
+                       } else if (depth == 1) {
+                               LogError("Invalid hierarchy of secure-storage dir... "
+                                                "Directory(" << name << ") cannot be in "
+                                                "group storage: " << dirpath);
+                               remove_path(path);
+                       } else {
+                               std::string subdir = dirpath + "/" + name;
+                               visit_dir(subdir, buf, depth + 1, saver);
+                       }
+               } else if (result->d_type == DT_REG) {
+                       if (depth == 0) {
+                               LogError("Invalid hierarchy of secure-storage dir... "
+                                                "File(" << name << ") cannot be in secure-storage top dir");
+                               remove_path(path);
+                       } else {
+                               LogInfo("Meet file(" << path << ") in secure-storage! "
+                                               "Let's save it into key-manager.");
+
+                               auto storage_name = dirpath.substr(OLD_SS_DIR.length() + 1);
+
+                               Crypto::Data data;
+                               data.type = DataType::BINARY_DATA;
+                               data.data = read_data(path, storage_name);
+
+                               if (data.data.empty()) {
+                                       LogError("Failed to read data from file: " << path);
+                               } else if (storage_name == "secure-storage") {
+                                       LogInfo("Meet secure-storage storage which contains SALT! skip it!");
+                               } else if (storage_name.rfind(OLD_SS_GROUP_PREFIX) == std::string::npos) {
+                                       LogInfo("data file(" << path << ") is not in group! "
+                                                       "smack-label is used as storage name");
+                                       saver(storage_name, name, data);
+                               } else {
+                                       LogInfo("data file(" << path << ") is in group! "
+                                                       "group id is extracted from dir path");
+                                       saver(storage_name.substr(OLD_SS_GROUP_PREFIX.length()), name, data);
+                               }
+
+                               remove_path(path);
+                       }
+               } else {
+                       LogError("Invalid type(" << result->d_type << ") of file(" << path << ") ");
+                       remove_path(path);
+               }
+       }
+}
+
+} // namespace anonymous
+
+bool hasMigratableData(void)
+{
+       if (::access(OLD_SS_DIR.c_str(), R_OK | X_OK) == -1) {
+               const int err = errno;
+
+               if (err != ENOENT)
+                       LogError("Failed to access old secure-storage dir. errno: " << err);
+
+               return false;
+       } else {
+               return true;
+       }
+}
+
+void migrateData(const Saver &saver)
+{
+       if (saver == nullptr) {
+               LogError("saver cannot be null");
+               return;
+       }
+
+       std::unique_ptr<struct dirent, void(*)(void *)> bufptr(
+                       static_cast<struct dirent *>(::malloc(
+                                       offsetof(struct dirent, d_name) + NAME_MAX + 1)), ::free);
+
+       if (bufptr == nullptr)
+               throw std::bad_alloc();
+
+       visit_dir(OLD_SS_DIR, bufptr.get(), 0, saver);
+}
+
+}
diff --git a/src/manager/service/ss-migrate.h b/src/manager/service/ss-migrate.h
new file mode 100644 (file)
index 0000000..5740aad
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *  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        ss-migrate.h
+ * @author      Kyungwook Tak (k.tak@samsung.com)
+ * @version     1.0
+ * @brief       Deprecated secure-storage data migration
+ */
+#pragma once
+
+#include <string>
+#include <vector>
+#include <functional>
+
+#include <generic-backend/gstore.h>
+
+namespace CKM {
+
+using Saver = std::function<void(const std::string &owner, const std::string &name,
+                                                                const Crypto::Data &data)>;
+
+bool hasMigratableData(void);
+void migrateData(const Saver &);
+
+}
diff --git a/tests/secure-storage-old-data/README b/tests/secure-storage-old-data/README
new file mode 100644 (file)
index 0000000..8c33a2a
--- /dev/null
@@ -0,0 +1,26 @@
+Resources for testing secure-storage data migration to key-manager.
+
+How to use:
+1) [Host]   Push resources to target by running script:
+            # sh ./push-data.sh
+2) [Target] Move from secure-storage directory to key-manager data directory
+            by running upgrade script in target:
+            # sh /etc/opt/upgrade/233.key-manager-move-ss-migratable-data.patch.sh
+3) [Target] Restart key-manager service and run any operation which unlocks system db
+
+Description:
+secure-storage module is removed since Tizen platform version 3.0.
+secure-storage data is migrated like the form below.
+Exception: ""optional password used data cannot be migrated.""
+
+Key factors of secure-storage data are <data name> and <storage name>
+<storage name> is group id if given else smack label of client.
+
+examples) Client with...
+Case1:: <smack label> = "client.service.label", <data name> = "data", <group id> = "secure-storage::client"
+-> key factors: <data name> = "data", <storage name> = "client"
+Case2:: <smack label> = "client.service.label", <data name> = "data", <group id> = null
+-> key factors: <data name> = "data", <storage name> = "client.service.label"
+
+Secure-storage data with <data name> and <storage name> will be migrated to key-manager system db
+with name = "<storage name>-<data name>"
diff --git a/tests/secure-storage-old-data/push-data.sh b/tests/secure-storage-old-data/push-data.sh
new file mode 100644 (file)
index 0000000..5d514b1
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+SS_BASE_PATH="/opt/share/secure-storage"
+
+sdb root on
+
+sdb shell rm -rf ${SS_BASE_PATH}
+
+sdb shell mkdir -p ${SS_BASE_PATH}
+
+sdb shell mkdir -p ${SS_BASE_PATH}/secure-storage
+sdb shell mkdir -p ${SS_BASE_PATH}/secure-storage\:\:test1
+sdb shell mkdir -p ${SS_BASE_PATH}/secure-storage\:\:test2
+
+sdb push ./secure-storage/salt ${SS_BASE_PATH}/secure-storage/
+sdb push ./secure-storage\:\:test1/test-data-1 ${SS_BASE_PATH}/secure-storage\:\:test1/
+sdb push ./secure-storage\:\:test1/test-data-2 ${SS_BASE_PATH}/secure-storage\:\:test1/
+sdb push ./secure-storage\:\:test1/test-data-3 ${SS_BASE_PATH}/secure-storage\:\:test1/
+sdb push ./secure-storage\:\:test2/test-data-1 ${SS_BASE_PATH}/secure-storage\:\:test2/
+sdb push ./secure-storage\:\:test2/test-data-2 ${SS_BASE_PATH}/secure-storage\:\:test2/
+sdb push ./secure-storage\:\:test2/test-data-3 ${SS_BASE_PATH}/secure-storage\:\:test2/
diff --git a/tests/secure-storage-old-data/secure-storage/salt b/tests/secure-storage-old-data/secure-storage/salt
new file mode 100644 (file)
index 0000000..90f6a8d
Binary files /dev/null and b/tests/secure-storage-old-data/secure-storage/salt differ
diff --git a/tests/secure-storage-old-data/secure-storage::test1/test-data-1 b/tests/secure-storage-old-data/secure-storage::test1/test-data-1
new file mode 100644 (file)
index 0000000..c62509b
Binary files /dev/null and b/tests/secure-storage-old-data/secure-storage::test1/test-data-1 differ
diff --git a/tests/secure-storage-old-data/secure-storage::test1/test-data-2 b/tests/secure-storage-old-data/secure-storage::test1/test-data-2
new file mode 100644 (file)
index 0000000..c62509b
Binary files /dev/null and b/tests/secure-storage-old-data/secure-storage::test1/test-data-2 differ
diff --git a/tests/secure-storage-old-data/secure-storage::test1/test-data-3 b/tests/secure-storage-old-data/secure-storage::test1/test-data-3
new file mode 100644 (file)
index 0000000..c62509b
Binary files /dev/null and b/tests/secure-storage-old-data/secure-storage::test1/test-data-3 differ
diff --git a/tests/secure-storage-old-data/secure-storage::test2/test-data-1 b/tests/secure-storage-old-data/secure-storage::test2/test-data-1
new file mode 100644 (file)
index 0000000..dc9a0fc
--- /dev/null
@@ -0,0 +1 @@
+­Ï³\86VòåCÒ§¡ÏÂq\1f\80l\rÛÜr}¼Ò\9b{,\8dèQéB
\ No newline at end of file
diff --git a/tests/secure-storage-old-data/secure-storage::test2/test-data-2 b/tests/secure-storage-old-data/secure-storage::test2/test-data-2
new file mode 100644 (file)
index 0000000..dc9a0fc
--- /dev/null
@@ -0,0 +1 @@
+­Ï³\86VòåCÒ§¡ÏÂq\1f\80l\rÛÜr}¼Ò\9b{,\8dèQéB
\ No newline at end of file
diff --git a/tests/secure-storage-old-data/secure-storage::test2/test-data-3 b/tests/secure-storage-old-data/secure-storage::test2/test-data-3
new file mode 100644 (file)
index 0000000..dc9a0fc
--- /dev/null
@@ -0,0 +1 @@
+­Ï³\86VòåCÒ§¡ÏÂq\1f\80l\rÛÜr}¼Ò\9b{,\8dèQéB
\ No newline at end of file
index ad413b5..7ac64da 100644 (file)
@@ -69,6 +69,7 @@ SET(CKM_DB_TOOL_SOURCES
     ${KEY_MANAGER_PATH}/service/file-system.cpp
     ${KEY_MANAGER_PATH}/service/for-each-file.cpp
     ${KEY_MANAGER_PATH}/service/key-provider.cpp
+    ${KEY_MANAGER_PATH}/service/ss-migrate.cpp
     ${KEY_MANAGER_PATH}/sqlcipher/sqlcipher.c
     )