Add CryptsetupEngine 38/128838/21
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Thu, 11 May 2017 12:58:41 +0000 (14:58 +0200)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Mon, 29 May 2017 14:53:21 +0000 (16:53 +0200)
Add wrapper class for libcryptsetup

Change-Id: I57e36fe667e1089f75c20b766faf81766a85e166

packaging/ode.spec
server/CMakeLists.txt
server/engine/encryption/cryptsetup-engine.cpp [new file with mode: 0644]
server/engine/encryption/cryptsetup-engine.h [new file with mode: 0644]

index ca2e272..261b33f 100755 (executable)
@@ -18,6 +18,7 @@ BuildRequires: pkgconfig(key-manager)
 BuildRequires: pkgconfig(cynara-client)
 BuildRequires: pkgconfig(cynara-session)
 BuildRequires: pkgconfig(openssl)
+BuildRequires: pkgconfig(libcryptsetup)
 
 %description
 The ode package provides a daemon which is responsible for encrypting/decryption storages and secure erasing.
index 72a882b..b4b0209 100644 (file)
@@ -28,6 +28,7 @@ SET(SERVER_SRCS       main.cpp
                                engine/encryption/ext4-engine.cpp
                                engine/encryption/dmcrypt-engine.cpp
                                engine/encryption/ecryptfs-engine.cpp
+                               engine/encryption/cryptsetup-engine.cpp
                                engine/erase/mmc-engine.cpp
                                key-manager/key-store.cpp
                                key-manager/key-manager.cpp
@@ -44,6 +45,7 @@ SET(DEPENDENCY        klay
                                cynara-client
                                cynara-session
                                openssl
+                               libcryptsetup
 )
 
 SET(SERVER_NAME ${PROJECT_NAME}d)
diff --git a/server/engine/encryption/cryptsetup-engine.cpp b/server/engine/encryption/cryptsetup-engine.cpp
new file mode 100644 (file)
index 0000000..d013d2f
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ *  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 "cryptsetup-engine.h"
+#include "../../file-footer.h"
+
+#include <cctype>
+#include <algorithm>
+
+#include <libcryptsetup.h>
+
+#include <klay/exception.h>
+#include <klay/audit/logger.h>
+
+namespace ode {
+
+namespace {
+
+const char* DEFAULT_LUKS_CIPHER_NAME = "aes";
+const char* DEFAULT_LUKS_CIPHER_MODE = "xts-plain64";
+const char* DEFAULT_LUKS_HASH = "sha1";
+const size_t DEFAULT_LUKS_ALIGNMENT = 0;
+
+#ifndef NDEBUG
+// log callback
+void log(int level, const char *msg, void*)
+{
+       std::string msgStr("[NULL]");
+       if (msg) {
+               msgStr = msg;
+
+               // trim it
+               auto it = find_if_not(msgStr.rbegin(),
+                                                         msgStr.rend(),
+                                                         [](char c){ return isspace(c); }).base();
+               msgStr.erase(it, msgStr.end());
+       }
+
+       switch (level)
+       {
+       case CRYPT_LOG_ERROR:
+               ERROR("[libcryptsetup] " + msgStr);
+               break;
+       case CRYPT_LOG_VERBOSE:
+               INFO("[libcryptsetup] " + msgStr);
+               break;
+       case CRYPT_LOG_DEBUG:
+       case CRYPT_LOG_NORMAL:
+               DEBUG("[libcryptsetup] " + msgStr);
+               break;
+       default:
+               ERROR("[libcryptsetup] Unsupported log level. Msg: " + msgStr);
+       }
+}
+#endif
+
+class Device
+{
+public:
+       enum class InitMethod
+       {
+               BY_DEV_PATH, // requires device path as first ctor argument
+               BY_MAP_NAME, // requires mapping name as first ctor argument
+       };
+
+       explicit Device(const std::string &str, InitMethod method = InitMethod::BY_DEV_PATH)
+       {
+               int ret;
+               if (str.empty())
+                       throw runtime::Exception("Empty argument");
+
+               switch (method) {
+               case InitMethod::BY_DEV_PATH:
+                       ret = crypt_init(&device, str.c_str());
+                       if (ret != 0)
+                               throw runtime::Exception("crypt_init() failed for " + str + ": "
+                                                                                + std::to_string(ret));
+                       break;
+               case InitMethod::BY_MAP_NAME:
+                       ret = crypt_init_by_name(&device, str.c_str());
+                       if (ret != 0)
+                               throw runtime::Exception("crypt_init_by_name() failed for " +
+                                                                                str + ": " + std::to_string(ret));
+                       break;
+               default:
+                       throw runtime::Exception("Unsupported init method " +
+                                                                        std::to_string(static_cast<int>(method)));
+               }
+
+#ifndef NDEBUG
+               /*
+                * This option causes debug logs to be printed to STDOUT. TODO execute it
+                * once for all engines?
+                */
+               crypt_set_debug_level(CRYPT_DEBUG_ALL);
+               crypt_set_log_callback(device, &log, NULL);
+#endif
+
+               // Needs root
+               if (1 != crypt_memory_lock(device, 1))
+                       throw runtime::Exception("Failed to lock memory");
+       }
+
+       Device(const Device&) = delete;
+       Device& operator=(const Device&) = delete;
+
+       ~Device()
+       {
+               if (0 != crypt_memory_lock(device, 0))
+               ERROR("Failed to unlock memory");
+
+               crypt_free(device);
+       }
+
+       crypt_device* get() noexcept { return device; }
+
+private:
+       crypt_device *device;
+};
+
+std::string mappingPath(const std::string& name)
+{
+       static std::string mappings_dir = std::string(crypt_get_dir()) + '/';
+       return mappings_dir + name;
+}
+
+} // anonymous namespace
+
+
+CryptsetupEngine::CryptsetupEngine(const std::string &devicePath) :
+       devPath(devicePath)
+{
+}
+
+CryptsetupEngine::~CryptsetupEngine()
+{
+}
+
+void CryptsetupEngine::format(DeviceType type, const data &key)
+{
+       switch (type) {
+       case DeviceType::LUKS:
+               {
+                       Device d(devPath);
+
+                       // TODO support other formats? support other ciphers?
+                       crypt_params_luks1 params = {
+                                       .hash = DEFAULT_LUKS_HASH,
+                                       .data_alignment = DEFAULT_LUKS_ALIGNMENT,
+                                       .data_device = NULL,
+                       };
+
+                       int ret = crypt_format(d.get(),
+                                                                  CRYPT_LUKS1,
+                                                                  DEFAULT_LUKS_CIPHER_NAME,
+                                                                  DEFAULT_LUKS_CIPHER_MODE,
+                                                                  NULL,        // NULL uid
+                                                                  reinterpret_cast<const char*>(key.data()),
+                                                                  key.size(),
+                                                                  &params);
+                       if (ret != 0)
+                               throw runtime::Exception("crypt_format() failed: " + std::to_string(ret));
+                       break;
+               }
+       case DeviceType::PLAIN:
+               // TODO
+       default:
+               throw runtime::Exception("Unsupported device type " +
+                                                                std::to_string(static_cast<int>(type)));
+       }
+}
+
+std::string CryptsetupEngine::open(DeviceType type, const std::string &name, const data &key)
+{
+       // create new mapping
+       switch (type) {
+       case DeviceType::LUKS:
+       {
+               Device d(devPath);
+               int ret = crypt_load(d.get(), CRYPT_LUKS1, NULL);
+               if (ret != 0)
+                       throw runtime::Exception("crypt_load() failed: " + std::to_string(ret));
+
+               // TODO possible support for activation flags
+               ret = crypt_activate_by_volume_key(d.get(),
+                                                                                  name.c_str(),
+                                                                                  reinterpret_cast<const char*>(key.data()),
+                                                                                  key.size(),
+                                                                                  0);
+               if (ret != 0)
+                       throw runtime::Exception("crypt_activate_by_volume_key() failed: " +
+                                                                        std::to_string(ret));
+               break;
+       }
+
+       case DeviceType::PLAIN:
+               // TODO
+       default:
+               throw runtime::Exception("Unsupported device type " +
+                                                                std::to_string(static_cast<int>(type)));
+       }
+       return mappingPath(name);
+}
+
+void CryptsetupEngine::close(const std::string &name)
+{
+       Device d(name, Device::InitMethod::BY_MAP_NAME);
+
+       int ret = crypt_deactivate(d.get(), name.c_str());
+       if (ret != 0)
+               throw runtime::Exception("crypt_deactivate() failed for " + name +
+                                                                ": " + std::to_string(ret));
+}
+
+bool CryptsetupEngine::isKeyMetaSet()
+{
+       return FileFooter::exist(devPath);
+}
+
+const CryptsetupEngine::data CryptsetupEngine::getKeyMeta()
+{
+       return FileFooter::read(devPath);
+}
+
+void CryptsetupEngine::setKeyMeta(const data &meta)
+{
+       FileFooter::write(devPath, meta);
+}
+
+void CryptsetupEngine::clearKeyMeta()
+{
+       FileFooter::clear(devPath);
+}
+
+} // namespace ode
diff --git a/server/engine/encryption/cryptsetup-engine.h b/server/engine/encryption/cryptsetup-engine.h
new file mode 100644 (file)
index 0000000..55c4658
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ *  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
+ */
+
+#ifndef __CRYPTSETUP_ENGINE_H__
+#define __CRYPTSETUP_ENGINE_H__
+
+#include <string>
+#include <vector>
+
+namespace ode {
+
+class CryptsetupEngine final {
+public:
+       enum class DeviceType {
+               PLAIN,
+               LUKS,
+       };
+
+       CryptsetupEngine(const std::string &devicePath);
+       CryptsetupEngine(const CryptsetupEngine &) = delete;
+       CryptsetupEngine(CryptsetupEngine &&) = delete;
+       ~CryptsetupEngine();
+
+       CryptsetupEngine &operator=(const CryptsetupEngine &) = delete;
+       CryptsetupEngine &operator=(CryptsetupEngine &&) = delete;
+
+       // TODO make it common among engines
+       typedef std::vector<unsigned char> data;
+
+       void format(DeviceType type, const data &key);
+
+       // create new mapping, returns mapping path
+       std::string open(DeviceType type, const std::string &name, const data &key);
+
+       static void close(const std::string &name);
+
+       bool isKeyMetaSet();
+       const data getKeyMeta();
+       void setKeyMeta(const data &data);
+       void clearKeyMeta();
+
+private:
+       std::string devPath;
+};
+
+} // namespace ode
+#endif // __CRYPTSETUP_ENGINE_H__