--- /dev/null
+/*
+ * Copyright (c) 2017 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
+ */
+
+#include "upgrade-support.h"
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+
+#include <string>
+#include <algorithm>
+#include <vector>
+#include <memory>
+#include <mutex>
+
+#include <klay/filesystem.h>
+#include <klay/exception.h>
+
+namespace ode {
+
+namespace {
+
+extern "C" {
+typedef int(*KeyStoragePluginStoreFn)(const unsigned char*, size_t,
+ unsigned char**, size_t*);
+typedef int(*KeyStoragePluginLoadFn)(const unsigned char*, size_t,
+ unsigned char**, size_t*);
+typedef int(*KeyStoragePluginRemoveFn)(const unsigned char*, size_t);
+}
+
+std::mutex opGuard;
+
+// not thread-safe because of static member
+class KeyStoragePlugin {
+public:
+ explicit KeyStoragePlugin();
+
+ KeyStoragePlugin(KeyStoragePlugin&&) = default;
+
+ KeyStoragePlugin(const KeyStoragePlugin&) = delete;
+ KeyStoragePlugin& operator=(const KeyStoragePlugin&) = delete;
+
+ ~KeyStoragePlugin();
+
+ static KeyStoragePlugin& Instance();
+
+ typedef std::vector<unsigned char> Data;
+
+ Data store(const Data& key);
+ Data load(const Data& token);
+ void remove(const Data& token);
+
+private:
+ void* so;
+ KeyStoragePluginStoreFn storeFn;
+ KeyStoragePluginLoadFn loadFn;
+ KeyStoragePluginRemoveFn removeFn;
+
+ static std::unique_ptr<KeyStoragePlugin> plugin;
+};
+
+std::unique_ptr<KeyStoragePlugin> KeyStoragePlugin::plugin;
+
+KeyStoragePlugin& KeyStoragePlugin::Instance()
+{
+ if (!plugin)
+ plugin.reset(new KeyStoragePlugin());
+
+ return *plugin;
+}
+
+KeyStoragePlugin::KeyStoragePlugin() : so(NULL)
+{
+ std::string path = std::string(KEY_STORAGE_PLUGIN_DIR) + "/" + KEY_STORAGE_PLUGIN_LIB;
+
+ so = ::dlopen(path.c_str(), RTLD_LAZY);
+ if (so == NULL)
+ throw runtime::Exception(std::string("Failed to load library: ") +
+ path + ". Error: " + ::dlerror());
+
+ storeFn = reinterpret_cast<KeyStoragePluginStoreFn>(::dlsym(so, "ode_ksp_store"));
+ if (storeFn == NULL)
+ throw runtime::Exception(
+ std::string("ode_ksp_store() symbol not found. Error: ") + ::dlerror());
+
+ loadFn = reinterpret_cast<KeyStoragePluginLoadFn>(::dlsym(so, "ode_ksp_load"));
+ if (loadFn == NULL)
+ throw runtime::Exception(
+ std::string("ode_ksp_load() symbol not found. Error: ") + ::dlerror());
+
+ removeFn = reinterpret_cast<KeyStoragePluginRemoveFn>(::dlsym(so, "ode_ksp_remove"));
+ if (removeFn == NULL)
+ throw runtime::Exception(
+ std::string("ode_ksp_remove() symbol not found. Error: ") + ::dlerror());
+}
+
+KeyStoragePlugin::~KeyStoragePlugin()
+{
+ ::dlclose(so);
+}
+
+KeyStoragePlugin::Data KeyStoragePlugin::store(const KeyStoragePlugin::Data& key)
+{
+ unsigned char* token = NULL;
+ size_t token_len = 0;
+ int ret = storeFn(key.data(), key.size(), &token, &token_len);
+ if (ret != 0)
+ throw runtime::Exception(std::string("Storing the key failed with ") +
+ std::to_string(ret));
+
+ Data tokenVector(token, token + token_len);
+ free(token);
+ return tokenVector;
+}
+
+KeyStoragePlugin::Data KeyStoragePlugin::load(const KeyStoragePlugin::Data& token)
+{
+ unsigned char* key = NULL;
+ size_t key_len = 0;
+ int ret = loadFn(token.data(), token.size(), &key, &key_len);
+ if (ret != 0)
+ throw runtime::Exception(std::string("Loading the key failed with ") +
+ std::to_string(ret));
+
+ Data keyVector(key, key + key_len);
+ free(key);
+ return keyVector;
+}
+
+void KeyStoragePlugin::remove(const KeyStoragePlugin::Data& token)
+{
+ int ret = removeFn(token.data(), token.size());
+ if (ret != 0)
+ throw runtime::Exception(std::string("Removing the key failed with ") +
+ std::to_string(ret));
+}
+
+std::string getTokenFileName(const std::string &device)
+{
+ std::string filename(device);
+ std::replace(filename.begin(), filename.end(), '/', '_');
+
+ return std::string("/opt/etc/.ode_token") + filename;
+}
+
+void readToken(runtime::File &file, KeyStoragePlugin::Data& token)
+{
+ size_t tokenSize;
+
+ file.open(O_RDONLY);
+
+ file.read(&tokenSize, sizeof(tokenSize));
+ token.resize(tokenSize);
+ file.read(token.data(), tokenSize);
+
+ file.close();
+}
+
+void writeToken(runtime::File &file, const KeyStoragePlugin::Data& token)
+{
+ size_t tokenSize(token.size());
+
+ file.create(0600);
+
+ file.write(&tokenSize, sizeof(tokenSize));
+ file.write(token.data(), token.size());
+
+ file.close();
+}
+
+} // anonymous namespace
+
+namespace UpgradeSupport {
+
+void storeMasterKey(const std::string &device, const KeyStoragePlugin::Data& key)
+{
+ std::lock_guard<std::mutex> lock(opGuard);
+
+ auto& up = KeyStoragePlugin::Instance();
+ auto token = up.store(key);
+
+ runtime::File file(getTokenFileName(device));
+
+ writeToken(file, token);
+}
+
+KeyStoragePlugin::Data loadMasterKey(const std::string &device)
+{
+ KeyStoragePlugin::Data token;
+
+ std::lock_guard<std::mutex> lock(opGuard);
+
+ runtime::File file(getTokenFileName(device));
+ readToken(file, token);
+
+ auto& up = KeyStoragePlugin::Instance();
+ return up.load(token);
+}
+
+void removeMasterKey(const std::string &device)
+{
+ KeyStoragePlugin::Data token;
+
+ std::lock_guard<std::mutex> lock(opGuard);
+
+ runtime::File file(getTokenFileName(device));
+ readToken(file, token);
+
+ auto& up = KeyStoragePlugin::Instance();
+ up.remove(token);
+
+ file.remove();
+}
+
+} // namespace UpgradeSupport
+
+} // namespace ode