Migrate ss data to both of system/admin user db 95/81095/2
authorKyungwook Tak <k.tak@samsung.com>
Fri, 22 Jul 2016 04:29:17 +0000 (13:29 +0900)
committerKyungwook Tak <k.tak@samsung.com>
Tue, 26 Jul 2016 02:42:45 +0000 (11:42 +0900)
Some services changed from system to user and they should handle
migrated data and newly saved data differently by changing owner
label because user service cannot save to system db

To use key-manager uniformly by client who is in the case above,
migrated data is going to saved on both of system and admin user
(owner : 5001) db with owner "/User" because user service's smack label
is "User"

Change-Id: Ic3f3b2d02945a12ba2dd12cf9b303a640421afd2
Signed-off-by: Kyungwook Tak <k.tak@samsung.com>
12 files changed:
src/CMakeLists.txt
src/manager/common/protocols.cpp
src/manager/common/protocols.h
src/manager/service/ckm-logic.cpp
src/manager/service/ckm-logic.h
src/manager/service/ckm-service.cpp
src/manager/service/ss-crypto.cpp [new file with mode: 0644]
src/manager/service/ss-crypto.h [new file with mode: 0644]
src/manager/service/ss-migrate.cpp
src/manager/service/ss-migrate.h
tests/secure-storage-old-data/README
tools/ckm_db_tool/CMakeLists.txt

index 66bdb43..23a55e2 100644 (file)
@@ -57,6 +57,7 @@ SET(KEY_MANAGER_SOURCES
     ${KEY_MANAGER_PATH}/service/ocsp-logic.cpp
     ${KEY_MANAGER_PATH}/service/ocsp-service.cpp
     ${KEY_MANAGER_PATH}/service/ss-migrate.cpp
+    ${KEY_MANAGER_PATH}/service/ss-crypto.cpp
     ${KEY_MANAGER_PATH}/initial-values/parser.cpp
     ${KEY_MANAGER_PATH}/initial-values/BufferHandler.cpp
     ${KEY_MANAGER_PATH}/initial-values/CertHandler.cpp
index 27dbb5f..a42d75d 100644 (file)
@@ -40,6 +40,7 @@ char const *const SERVICE_SOCKET_ENCRYPTION =
        "/tmp/.central-key-manager-api-encryption.sock";
 char const *const LABEL_NAME_SEPARATOR = " ";
 char const *const OWNER_ID_SYSTEM = "/System";
+char const *const OWNER_ID_ADMIN_USER = "/User";
 
 PKCS12Serializable::PKCS12Serializable()
 {
index 3294ef2..6141a84 100644 (file)
@@ -76,6 +76,7 @@ enum class EncryptionCommand : int {
 // (client side) Alias = (service side) Label::Name
 COMMON_API extern char const *const LABEL_NAME_SEPARATOR;
 COMMON_API extern char const *const OWNER_ID_SYSTEM;
+COMMON_API extern char const *const OWNER_ID_ADMIN_USER;
 
 typedef std::string Name;
 typedef std::vector<std::pair<Label, Name>> LabelNameVector;
index 2f1a228..7d32228 100644 (file)
@@ -61,6 +61,7 @@ bool isNameValid(const CKM::Name &name)
 namespace CKM {
 
 const uid_t CKMLogic::SYSTEM_DB_UID = 0;
+const uid_t CKMLogic::ADMIN_USER_DB_UID = 5001;
 
 CKMLogic::CKMLogic()
 {
@@ -95,6 +96,26 @@ void CKMLogic::saveDKEKFile(uid_t user, const Password &password)
        fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password));
 }
 
+void CKMLogic::migrateSecureStorageData(bool isAdminUser)
+{
+       SsMigration::migrate(isAdminUser, [this](const std::string &name,
+                                                                                        const Crypto::Data &data,
+                                                                                        bool adminUserFlag) {
+               LogInfo("Migrate data called with  name: " << name);
+               auto ownerId = adminUserFlag ? OWNER_ID_ADMIN_USER : OWNER_ID_SYSTEM;
+               auto uid = adminUserFlag ? ADMIN_USER_DB_UID : SYSTEM_DB_UID;
+
+               int ret = verifyAndSaveDataHelper(Credentials(uid, ownerId), name, ownerId, data,
+                                                                                 PolicySerializable());
+
+               if (ret == CKM_API_ERROR_DB_ALIAS_EXISTS)
+                       LogWarning("Alias already exist for migrated name: " << name);
+               else if (ret != CKM_API_SUCCESS)
+                       LogError("Failed to migrate secure-storage data. name: " << name <<
+                                        " ret: " << ret);
+       });
+}
+
 int CKMLogic::unlockDatabase(uid_t user, const Password &password)
 {
        if (0 < m_userDataMap.count(user) &&
@@ -131,22 +152,10 @@ int CKMLogic::unlockDatabase(uid_t user, const Password &password)
                        }
                }
 
-               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);
-                       });
-               }
+               if (user == SYSTEM_DB_UID && SsMigration::hasData())
+                       migrateSecureStorageData(false);
+               else if (user == ADMIN_USER_DB_UID && SsMigration::hasData())
+                       migrateSecureStorageData(true);
        } catch (const Exc::Exception &e) {
                retCode = e.error();
        } catch (const CKM::Exception &e) {
index a118202..b1ab091 100644 (file)
@@ -50,6 +50,7 @@ struct UserData {
 class CKMLogic {
 public:
        static const uid_t SYSTEM_DB_UID;
+       static const uid_t ADMIN_USER_DB_UID;
 
        CKMLogic();
        CKMLogic(const CKMLogic &) = delete;
@@ -211,7 +212,6 @@ public:
                const Crypto::DataEncryption &enc,
                const Policy &policy);
 
-protected:
        int unlockSystemDB();
 
 private:
@@ -220,7 +220,7 @@ private:
        UserData &selectDatabase(const Credentials &incoming_cred,
                                                         const Label       &incoming_label);
 
-       int unlockDatabase(uid_t            user,
+       int unlockDatabase(uid_t user,
                                           const Password &password);
 
        void loadDKEKFile(
@@ -394,6 +394,8 @@ private:
 
        int loadAppKey(UserData &handle, const Label &appLabel);
 
+       void migrateSecureStorageData(bool isAdminUser);
+
        AccessControl m_accessControl;
        Crypto::Decider m_decider;
        //FileLock m_lock;
index c7e8f74..5b39632 100644 (file)
@@ -49,6 +49,11 @@ CKMService::~CKMService()
 
 void CKMService::Start()
 {
+       // unlock system db at first to migrate old ss data earlier than user db unlocked.
+       // Because data should be migrated to both of system db and user(default owner) db
+       // and old data resource will be removed after migrated to user db
+       m_logic->unlockSystemDB();
+
        Create();
 }
 
diff --git a/src/manager/service/ss-crypto.cpp b/src/manager/service/ss-crypto.cpp
new file mode 100644 (file)
index 0000000..1da144a
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ *  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-crypto.cpp
+ * @author      Kyungwook Tak (k.tak@samsung.com)
+ * @version     1.0
+ * @brief       Decrypt old secure-storage data for migration
+ */
+#include <ss-crypto.h>
+
+#include <memory>
+#include <cstring>
+
+#include <openssl/sha.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+
+#include <dpl/log/log.h>
+
+namespace CKM {
+
+namespace {
+
+const int SALT_SIZE = 32;
+const int KEY_SIZE = 16;
+
+RawBuffer _get_key(const std::string &id)
+{
+       unsigned char salt[SALT_SIZE];
+
+       ::memset(salt, 0xFF, SALT_SIZE);
+
+       RawBuffer duk(KEY_SIZE);
+
+       if (::PKCS5_PBKDF2_HMAC_SHA1(id.c_str(), id.length(), salt, SALT_SIZE, 1, duk.size(),
+                       duk.data()) != 1) {
+               LogError("Failed to pkcs5_pkbdf_hmac_sha1.");
+               return RawBuffer();
+       }
+
+       return duk;
+}
+
+RawBuffer _get_iv(const RawBuffer &src)
+{
+       RawBuffer iv(KEY_SIZE);
+       size_t ivlen = iv.size();
+
+       if (::EVP_Digest(src.data(), src.size(), iv.data(), &ivlen, ::EVP_sha1(), nullptr)
+                       != 1) {
+               LogError("Failed to get iv");
+               return RawBuffer();
+       }
+
+       return iv;
+}
+
+RawBuffer _decrypt(const RawBuffer &key, const RawBuffer &iv, const RawBuffer &ciphertext)
+{
+       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, key.data(), iv.data(), 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;
+}
+
+} // namespace anonymous
+
+namespace SsMigration {
+
+RawBuffer decrypt(const std::string &seed, const RawBuffer &ciphertext)
+{
+       auto key = _get_key(seed);
+       auto iv = _get_iv(key);
+
+       return _decrypt(key, iv, ciphertext);
+}
+
+} // namespace SsMigration
+
+} // namespace CKM
diff --git a/src/manager/service/ss-crypto.h b/src/manager/service/ss-crypto.h
new file mode 100644 (file)
index 0000000..b02c164
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ *  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-crypto.h
+ * @author      Kyungwook Tak (k.tak@samsung.com)
+ * @version     1.0
+ * @brief       Decrypt old secure-storage data for migration
+ */
+#pragma once
+
+#include <string>
+#include <ckm/ckm-raw-buffer.h>
+
+namespace CKM {
+namespace SsMigration {
+
+RawBuffer decrypt(const std::string &seed, const RawBuffer &ciphertext);
+
+}
+}
index 5bf0179..efadd2f 100644 (file)
 
 #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>
+#include <ss-crypto.h>
 
 namespace CKM {
+namespace SsMigration {
 
 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)
 {
@@ -87,73 +65,24 @@ RawBuffer read_data(const std::string &filepath, const std::string &seed)
                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;
+       return SsMigration::decrypt(seed, ciphertext);
 }
 
-inline void remove_path(const std::string &path)
+inline void remove_path(const std::string &path, bool isAdminUser)
 {
+       if (!isAdminUser)
+               return;
+
        if (::remove(path.c_str()) == -1)
                LogError("Failed to remove path: " << path << " with errno: " << errno);
+
+       LogInfo("File removed: " << path);
 }
 
 // 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)
+                          const Saver &saver, bool isAdminUser)
 {
        if (depth > 1) {
                LogError("Invalid depth in secure-storage subdir... dirpath: " << dirpath);
@@ -174,7 +103,7 @@ void visit_dir(const std::string &dirpath, struct dirent *buf, size_t depth,
                                         " with errno: " << errno);
                        break;
                } else if (result == nullptr) {
-                       remove_path(dirpath);
+                       remove_path(dirpath, isAdminUser);
                        break;
                }
 
@@ -190,16 +119,15 @@ void visit_dir(const std::string &dirpath, struct dirent *buf, size_t depth,
                                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);
+                               visit_dir(subdir, buf, depth + 1, saver, isAdminUser);
+                               continue;
                        }
                } 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.");
@@ -210,32 +138,24 @@ void visit_dir(const std::string &dirpath, struct dirent *buf, size_t depth,
                                data.type = DataType::BINARY_DATA;
                                data.data = read_data(path, storage_name);
 
-                               if (data.data.empty()) {
+                               if (data.data.empty())
                                        LogError("Failed to read data from file: " << path);
-                               } else if (storage_name == "secure-storage") {
+                               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
+                                       saver(name, data, isAdminUser);
                        }
                } else {
                        LogError("Invalid type(" << result->d_type << ") of file(" << path << ") ");
-                       remove_path(path);
                }
+
+               remove_path(path, isAdminUser);
        }
 }
 
 } // namespace anonymous
 
-bool hasMigratableData(void)
+bool hasData(void)
 {
        if (::access(OLD_SS_DIR.c_str(), R_OK | X_OK) == -1) {
                const int err = errno;
@@ -249,7 +169,7 @@ bool hasMigratableData(void)
        }
 }
 
-void migrateData(const Saver &saver)
+void migrate(bool isAdminUser, const Saver &saver)
 {
        if (saver == nullptr) {
                LogError("saver cannot be null");
@@ -263,7 +183,8 @@ void migrateData(const Saver &saver)
        if (bufptr == nullptr)
                throw std::bad_alloc();
 
-       visit_dir(OLD_SS_DIR, bufptr.get(), 0, saver);
+       visit_dir(OLD_SS_DIR, bufptr.get(), 0, saver, isAdminUser);
 }
 
-}
+} // namespace SsMigration
+} // namespace CKM
index 5740aad..e56b18e 100644 (file)
 #include <generic-backend/gstore.h>
 
 namespace CKM {
+namespace SsMigration {
 
-using Saver = std::function<void(const std::string &owner, const std::string &name,
-                                                                const Crypto::Data &data)>;
+using Saver = std::function<void(const std::string &name, const Crypto::Data &data,
+                                                                bool isAdminUser)>;
 
-bool hasMigratableData(void);
-void migrateData(const Saver &);
+bool hasData(void);
+void migrate(bool isAdminUser, const Saver &);
 
 }
+}
index 8c33a2a..a6c9ca0 100644 (file)
@@ -1,12 +1,17 @@
 Resources for testing secure-storage data migration to key-manager.
 
+Secure storage data is migrated to system db and admin user db.
+Data migrated to admin user db also because there's some services which was system service
+but user service from 3.0. (e.g., email-service). They should handle migrated data from newly
+added data differently because user service cannot save data to system db.
+
 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
+3) [Target] Restart key-manager service
 
 Description:
 secure-storage module is removed since Tizen platform version 3.0.
@@ -15,12 +20,18 @@ 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.
+Data has been grouped by <storage name> in secure-storage but no more grouping in key-manager.
+All data is saved in both of
+1) system db              with "/System" owner which is smack label(=owner name) of system services
+2) admin user db("owner") with "/User" owner which is smack label(=owner name) of user services.
+
+<storage name> is only used for migratable data re-encryption.
 
-examples) Client with...
+system db with owner label = "/System" and name = "<data name>"
+admin user(owner) db with owner label = "/User" and name = "<data name>"
+
+storage name extraction 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>"
index 7ac64da..6fdce57 100644 (file)
@@ -70,6 +70,7 @@ SET(CKM_DB_TOOL_SOURCES
     ${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}/service/ss-crypto.cpp
     ${KEY_MANAGER_PATH}/sqlcipher/sqlcipher.c
     )