diff options
Diffstat (limited to 'src/manager/service')
-rw-r--r-- | src/manager/service/ckm-logic.cpp | 41 | ||||
-rw-r--r-- | src/manager/service/ckm-logic.h | 6 | ||||
-rw-r--r-- | src/manager/service/ckm-service.cpp | 5 | ||||
-rw-r--r-- | src/manager/service/ss-crypto.cpp | 134 | ||||
-rw-r--r-- | src/manager/service/ss-crypto.h | 33 | ||||
-rw-r--r-- | src/manager/service/ss-migrate.cpp | 127 | ||||
-rw-r--r-- | src/manager/service/ss-migrate.h | 10 |
7 files changed, 231 insertions, 125 deletions
diff --git a/src/manager/service/ckm-logic.cpp b/src/manager/service/ckm-logic.cpp index 2f1a2280..7d322289 100644 --- a/src/manager/service/ckm-logic.cpp +++ b/src/manager/service/ckm-logic.cpp @@ -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) { diff --git a/src/manager/service/ckm-logic.h b/src/manager/service/ckm-logic.h index a1182028..b1ab091f 100644 --- a/src/manager/service/ckm-logic.h +++ b/src/manager/service/ckm-logic.h @@ -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; diff --git a/src/manager/service/ckm-service.cpp b/src/manager/service/ckm-service.cpp index c7e8f746..5b39632e 100644 --- a/src/manager/service/ckm-service.cpp +++ b/src/manager/service/ckm-service.cpp @@ -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 index 00000000..1da144ac --- /dev/null +++ b/src/manager/service/ss-crypto.cpp @@ -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 index 00000000..b02c164f --- /dev/null +++ b/src/manager/service/ss-crypto.h @@ -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); + +} +} diff --git a/src/manager/service/ss-migrate.cpp b/src/manager/service/ss-migrate.cpp index 5bf01792..efadd2fa 100644 --- a/src/manager/service/ss-migrate.cpp +++ b/src/manager/service/ss-migrate.cpp @@ -23,43 +23,21 @@ #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 diff --git a/src/manager/service/ss-migrate.h b/src/manager/service/ss-migrate.h index 5740aad4..e56b18e1 100644 --- a/src/manager/service/ss-migrate.h +++ b/src/manager/service/ss-migrate.h @@ -28,11 +28,13 @@ #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 &); } +} |