Add encryption API (partial implementation) 23/114923/17
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Wed, 15 Feb 2017 12:46:17 +0000 (13:46 +0100)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Mon, 6 Mar 2017 15:46:36 +0000 (16:46 +0100)
Change-Id: I16fbee17659fd536618e61b49a10ac0e9a2b6119

src/client/client-security-manager.cpp
src/common/include/protocols.h
src/common/include/service_impl.h
src/common/service_impl.cpp
src/include/CMakeLists.txt
src/include/app-encryption.h [new file with mode: 0644]
src/include/security-manager-types.h
src/include/security-manager.h
src/server/service/include/service.h
src/server/service/service.cpp

index 6799c8a974a27ed2e63bff7d1ea49691c633bd6a..3bbd6c2409a9aea173a7378119030373a295d32d 100644 (file)
@@ -1573,19 +1573,25 @@ int security_manager_shm_open(const char *name, int oflag, mode_t mode, const ch
     });
 }
 
-__attribute__ ((unused)) static int security_manager_save_fek(
-        const std::string &appName,
-        const std::string &password,
-        const std::vector<char> &fek)
+static int security_manager_get_sensitive_dirs(const std::string &appName,
+                                               std::vector<std::string>& paths)
 {
-    ClientRequest request(SecurityModuleCall::APP_SAVE_FEK);
-    return request.send(appName, password, fek).getStatus();
+    using namespace SecurityManager;
+    if (appName.empty())
+        return SECURITY_MANAGER_ERROR_INPUT_PARAM;
+    return try_catch([&]() -> int {
+        ClientRequest request(SecurityModuleCall::PATHS_GET_SENSITIVE);
+        if (request.send(appName).failed())
+            return request.getStatus();
+
+        request.recv(paths);
+        return SECURITY_MANAGER_SUCCESS;
+    });
 }
 
-__attribute__ ((unused)) static int security_manager_get_fek(
-        const std::string &appName,
-        const std::string &password,
-        std::vector<char> &fek)
+static int security_manager_get_fek(const std::string &appName,
+                                    const std::string &password,
+                                    std::vector<char> &fek)
 {
     ClientRequest request(SecurityModuleCall::APP_GET_FEK);
     if (request.send(appName, password).failed())
@@ -1595,9 +1601,84 @@ __attribute__ ((unused)) static int security_manager_get_fek(
     return SECURITY_MANAGER_SUCCESS;
 }
 
-__attribute__ ((unused)) static int security_manager_remove_fek(
-        const std::string &appName)
+SECURITY_MANAGER_API
+int security_manager_app_change_password(const char *app_id,
+                                         const char *old_pw,
+                                         const char *new_pw)
 {
-    ClientRequest request(SecurityModuleCall::APP_REMOVE_FEK);
-    return request.send(appName).getStatus();
+    if (app_id == NULL)
+        return SECURITY_MANAGER_ERROR_INPUT_PARAM;
+
+    if (old_pw == NULL && new_pw == NULL)
+        return SECURITY_MANAGER_ERROR_INPUT_PARAM;
+
+    std::string oldPw, newPw, appName;
+
+    if (old_pw != NULL)
+        oldPw.assign(old_pw);
+    if (new_pw != NULL)
+        newPw.assign(new_pw);
+    appName.assign(app_id);
+
+    return try_catch([&]() -> int {
+        ClientRequest request(SecurityModuleCall::APP_CHANGE_PW);
+        return request.send(appName, oldPw, newPw).getStatus();
+    });
+}
+
+SECURITY_MANAGER_API
+int security_manager_app_get_encryption_status(const char *app_id,
+                                               app_encryption_status *status)
+{
+    if (app_id == NULL || status == NULL)
+        return SECURITY_MANAGER_ERROR_INPUT_PARAM;
+
+    return try_catch([&]() -> int {
+        int tmp_status = SM_APP_ENCR_NONE;
+        std::vector<std::string> paths;
+        int ret = security_manager_get_sensitive_dirs(app_id, paths);
+        if (ret != SECURITY_MANAGER_SUCCESS)
+            return ret;
+
+        if (!paths.empty())
+            tmp_status |= SM_APP_ENCR_HAS_SENSITIVE_DIRS;
+
+        std::vector<char> fek;
+
+        // get FEK from key manager using wrong password
+        ret = security_manager_get_fek(app_id, "", fek);
+        if (ret == SECURITY_MANAGER_ERROR_AUTHENTICATION_FAILED) {
+            tmp_status |= SM_APP_ENCR_HAS_PASSWORD;
+        } else if (ret == SECURITY_MANAGER_ERROR_NO_SUCH_OBJECT) {
+            // status is unchanged
+        } else {
+            return ret;
+        }
+
+        *status = static_cast<app_encryption_status>(tmp_status);
+        return SECURITY_MANAGER_SUCCESS;
+    });
+}
+
+SECURITY_MANAGER_API
+int security_manager_app_unlock(const char *app_id, const char *password)
+{
+    if (app_id == NULL)
+        return SECURITY_MANAGER_ERROR_INPUT_PARAM;
+
+    if (password == NULL)
+        return SECURITY_MANAGER_SUCCESS; // no password, no key, no encryption
+
+    return try_catch([&]() -> int {
+        std::vector<char> fek;
+
+        // get key from key manager
+        int ret = security_manager_get_fek(app_id, password, fek);
+        if (ret != SECURITY_MANAGER_SUCCESS)
+            return ret;
+
+        // TODO insert it into process keyring
+
+        return SECURITY_MANAGER_SUCCESS;
+    });
 }
index 30da7d936fcbfa397c9f71e0928d8925fdd708f9..0d3fb0cc36737972d6a06cdacf3f7613ed5111c3 100644 (file)
@@ -92,6 +92,7 @@ enum class SecurityModuleCall
     APP_SAVE_FEK,
     APP_GET_FEK,
     APP_REMOVE_FEK,
+    APP_CHANGE_PW,
     NOOP = 0x90,
 };
 
index 3566527bdea06eb5cd87c9458873b1340b038047..c5434ca05e7638e47162415b83d2122640b89f2f 100644 (file)
@@ -261,6 +261,21 @@ public:
     int getSensitiveDirs(const Credentials &creds,
                          const std::string &appName,
                          std::vector<std::string> &paths);
+
+    /*
+     * Change application's password
+     *
+     * @param[in] creds    credentials of the requesting process
+     * @param[in] appName  application identifier
+     * @param[in] oldPw    old password (can be empty)
+     * @param[in] newPw    new password (can be empty)
+     *
+     * @return API return code, as defined in protocols.h
+     */
+    int appChangePassword(const Credentials &creds,
+                          const std::string &appName,
+                          const std::string &oldPw,
+                          const std::string &newPw);
 private:
     bool authenticate(const Credentials &creds, const std::string &privilege);
 
index f93c0fddfe5a5f5441724173b9c11abd3b3c95d4..268e5bd64a68e2caac05d3bd1cf288c401072a24 100644 (file)
@@ -105,6 +105,7 @@ ServiceImpl::ServiceImpl()
 
 ServiceImpl::~ServiceImpl()
 {
+    // TODO cleanup yaca if necessary
 }
 
 int ServiceImpl::validatePolicy(const Credentials &creds, policy_entry &policyEntry, CynaraAdminPolicy &cyap)
@@ -1771,4 +1772,107 @@ int ServiceImpl::getSensitiveDirs(const Credentials &creds,
     }
 }
 
+int ServiceImpl::appChangePassword(const Credentials &creds,
+                                   const std::string &appName,
+                                   const std::string &oldPw,
+                                   const std::string &newPw)
+{
+    if (appName.empty()) {
+        LogError("Application id is empty");
+        return SECURITY_MANAGER_ERROR_INPUT_PARAM;
+    }
+
+    if (oldPw.empty() && newPw.empty()) {
+        LogError("Both passwords are empty");
+        return SECURITY_MANAGER_ERROR_INPUT_PARAM;
+    }
+
+    std::vector<std::string> paths;
+    int ret;
+    ret = getSensitiveDirs(creds, appName, paths);
+    if (ret != SECURITY_MANAGER_SUCCESS)
+        return ret;
+
+    try {
+        if (!EncryptionAccess::IsAllowed(creds.label)) {
+            LogError("Request from uid=" << creds.uid << ", Smack=" << creds.label <<
+                            " for list of sensitive directories denied");
+            return SECURITY_MANAGER_ERROR_AUTHENTICATION_FAILED;
+        }
+
+        if (oldPw.empty()) {
+            // enable encryption
+
+            // generate FEK
+            std::vector<char> fek(64, 0);
+
+            // TODO initialize yaca (on demand)
+
+            // TODO randomize FEK
+
+            // TODO insert FEK into keyring
+
+            for (const auto& p : paths) {
+                (void)p;
+                // TODO set policy for path
+            }
+
+            // TODO remove FEK from keyring
+
+            // store FEK protected with password
+            return FEKmanager::saveFEK(creds.uid, creds.label, appName, newPw, fek);
+        } else if (newPw.empty()) {
+            // disable encryption
+
+            std::vector<char> fek;
+
+            // get FEK from key manager
+            int ret = FEKmanager::getFEK(creds.uid, creds. label, appName, oldPw, fek);
+            if (ret != SECURITY_MANAGER_SUCCESS)
+                return ret;
+
+            // insert FEK into keyring to decrypt existing data
+
+            for (const auto& p : paths) {
+                (void)p;
+                // TODO remove/decrypt directory
+            }
+
+            // TODO remove FEK from keyring
+
+            // remove FEK from key manager
+            return FEKmanager::removeFEK(creds.uid, creds.label, appName);
+        } else {
+            // change password
+
+            std::vector<char> fek;
+
+            // get FEK from key manager
+            int ret = FEKmanager::getFEK(creds.uid, creds.label, appName, oldPw, fek);
+            if (ret != SECURITY_MANAGER_SUCCESS)
+                return ret;
+
+            // remove FEK from key manager
+            ret = FEKmanager::removeFEK(creds.uid, creds.label, appName);
+            if (ret != SECURITY_MANAGER_SUCCESS)
+                 return ret;
+
+            // store FEK with new password
+            return FEKmanager::saveFEK(creds.uid, creds.label, appName, newPw, fek);
+        }
+    } catch (const PrivilegeDb::Exception::Base &e) {
+        LogError("Error while querying db for sensitive directories: " << e.DumpToString());
+        return SECURITY_MANAGER_ERROR_SERVER_ERROR;
+    } catch (const std::bad_alloc &e) {
+        LogError("Memory allocation failed: " << e.what());
+        return SECURITY_MANAGER_ERROR_MEMORY;
+    } catch (const std::exception &e) {
+        LogError("Some exception thrown: " << e.what());
+        return SECURITY_MANAGER_ERROR_UNKNOWN;
+    } catch (...) {
+        LogError("Unknown exception thrown");
+        return SECURITY_MANAGER_ERROR_UNKNOWN;
+    }
+}
+
 } /* namespace SecurityManager */
index f1d42643a5d10fbb44f9056de66768954954ac39..8ed60d801e425c1888f0cf43ae37879bb5ab0b0d 100644 (file)
@@ -7,5 +7,6 @@ INSTALL(FILES
     ${INCLUDE_PATH}/label-monitor.h
     ${INCLUDE_PATH}/user-manager.h
     ${INCLUDE_PATH}/policy-manager.h
+    ${INCLUDE_PATH}/app-encryption.h
     DESTINATION ${INCLUDE_INSTALL_DIR}/security-manager
     )
diff --git a/src/include/app-encryption.h b/src/include/app-encryption.h
new file mode 100644 (file)
index 0000000..93dc6de
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ *  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
+ */
+/*
+ * @file       app-encryption.h
+ * @author     Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
+ * @version    1.0
+ */
+
+#pragma once
+
+#include "security-manager-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Function responsible for modification of application key. To enable or
+ * disable sensitive directory encryption the old or new password should be set
+ * to NULL respectively. TODO For now it is assumed that the application is not
+ * running.
+ *
+ * \param[in] app_id  Application identifier
+ * \param[in] old_pw  Old application password
+ * \param[in] new_pw  New application password
+ *
+ * \return API return code or error code
+ */
+int security_manager_app_change_password(const char* app_id,
+                                         const char* old_pw,
+                                         const char* new_pw);
+
+/**
+ * Checks application's encryption status.
+ *
+ * \param[in]  app_id  Application identifier
+ * \param[out] status  Application encryption status
+ * \return API return code or error code
+ */
+int security_manager_app_get_encryption_status(const char* app_id,
+                                               app_encryption_status* status);
+
+/**
+ * Function responsible for inserting an application key into current process
+ * keyring allowing sensitive directories to be accessed (decrypted). It should
+ * be called before security_manager_prepare_app().
+ *
+ * \param[in] app_id    Application identifier
+ * \param[in] password  Application password
+ * \return API return code or error code
+ */
+int security_manager_app_unlock(const char* app_id, const char* password);
+
+#ifdef __cplusplus
+}
+#endif
+
index aea3deae454bfd62549d7380439f55c718cdc8e3..7f882631ed630ced5cc71637b3ce36f9857c099d 100644 (file)
@@ -97,6 +97,13 @@ enum security_manager_user_type {
 };
 typedef enum security_manager_user_type security_manager_user_type;
 
+enum app_encryption_status {
+    SM_APP_ENCR_NONE =               0,      /*<-0*/
+    SM_APP_ENCR_HAS_SENSITIVE_DIRS = 1 << 0, /*<-1 - application has sensitive dirs*/
+    SM_APP_ENCR_HAS_PASSWORD =       1 << 1, /*<-2 - application has encryption password set*/
+};
+typedef enum app_encryption_status app_encryption_status;
+
 /*! \brief data structure responsible for handling informations
  * required to install / uninstall application */
 struct app_inst_req;
index 466270cbed8b71d98e1a9912a003df737fb87a1d..31a7c27b9151e65137adb81601eb91fbe9ac7e40 100644 (file)
@@ -34,6 +34,7 @@
 #include "label-monitor.h"
 #include "user-manager.h"
 #include "policy-manager.h"
+#include "app-encryption.h"
 
 #ifdef __cplusplus
 extern "C" {
index 4d9a848e4791c94dfb9719c8b34db2e1b4f0cbb4..704aaf304ad6241fb9e6f96fa313b66d11addc70 100644 (file)
@@ -215,6 +215,8 @@ private:
     void processSaveFEK(MessageBuffer &recv, MessageBuffer &send, const Credentials &creds);
     void processGetFEK(MessageBuffer &recv, MessageBuffer &send, const Credentials &creds);
     void processRemoveFEK(MessageBuffer &recv, MessageBuffer &send, const Credentials &creds);
+
+    void processChangePassword(MessageBuffer &recv, MessageBuffer &send, const Credentials &creds);
 };
 
 } // namespace SecurityManager
index 36db509ff9f4e901816a30b95dd94c00336d322d..3b7440cda2094474210864f02df7f2a26dfa4d61 100644 (file)
@@ -163,6 +163,9 @@ bool Service::processOne(const ConnectionID &conn, MessageBuffer &buffer,
                 case SecurityModuleCall::APP_REMOVE_FEK:
                     processRemoveFEK(buffer, send, creds);
                     break;
+                case SecurityModuleCall::APP_CHANGE_PW:
+                    processChangePassword(buffer, send, creds);
+                    break;
                 default:
                     LogError("Invalid call: " << call_type_int);
                     Throw(ServiceException::InvalidAction);
@@ -472,4 +475,14 @@ void Service::processRemoveFEK(MessageBuffer &recv, MessageBuffer &send, const C
     Serialization::Serialize(send, ret);
 }
 
+void Service::processChangePassword(MessageBuffer &recv, MessageBuffer &send, const Credentials &creds)
+{
+    std::string appName, oldPw, newPw;
+    Deserialization::Deserialize(recv, appName, oldPw, newPw);
+
+    int ret = serviceImpl.appChangePassword(creds, appName, oldPw, newPw);
+
+    Serialization::Serialize(send, ret);
+}
+
 } // namespace SecurityManager