Add transaction during password change.
authorBartlomiej Grzelewski <b.grzelewski@samsung.com>
Wed, 17 Dec 2014 09:10:26 +0000 (10:10 +0100)
committerMaciej J. Karpiuk <m.karpiuk2@samsung.com>
Tue, 17 Feb 2015 10:59:24 +0000 (11:59 +0100)
Change-Id: Ic236a84959d339ddc19b2f3e8078766cd97545a7

src/manager/service/ckm-logic.cpp
src/manager/service/ckm-logic.h
src/manager/service/ckm-service.cpp
src/manager/service/file-system.cpp
src/manager/service/file-system.h

index 649815b..ca6d1f8 100644 (file)
@@ -61,7 +61,62 @@ CKMLogic::CKMLogic()
 
 CKMLogic::~CKMLogic(){}
 
-RawBuffer CKMLogic::unlockUserKey(uid_t user, const Password &password) {
+void CKMLogic::loadDKEKFile(uid_t user, const Password &password, bool apiReq) {
+    auto &handle = m_userDataMap[user];
+
+    FileSystem fs(user);
+
+    auto wrappedDKEKMain = fs.getDKEK();
+    auto wrappedDKEKBackup = fs.getDKEKBackup();
+
+    if (wrappedDKEKMain.empty() && wrappedDKEKBackup.empty()) {
+        wrappedDKEKMain = KeyProvider::generateDomainKEK(std::to_string(user), password);
+        fs.saveDKEK(wrappedDKEKMain);
+    }
+
+    chooseDKEKFile(handle, password, wrappedDKEKMain, wrappedDKEKBackup);
+
+    if (!password.empty() || apiReq) {
+        handle.isDKEKConfirmed = true;
+
+        if (true == handle.isMainDKEK)
+            fs.removeDKEKBackup();
+        else
+            fs.restoreDKEK();
+    }
+}
+
+void CKMLogic::chooseDKEKFile(
+    UserData &handle,
+    const Password &password,
+    const RawBuffer &first,
+    const RawBuffer &second)
+{
+    try {
+        handle.keyProvider = KeyProvider(first, password);
+        handle.isMainDKEK = true;
+    } catch (const KeyProvider::Exception::Base &e) {
+        if (second.empty())
+            throw;
+        handle.keyProvider = KeyProvider(second, password);
+        handle.isMainDKEK = false;
+    }
+}
+
+void CKMLogic::saveDKEKFile(uid_t user, const Password &password) {
+    auto &handle = m_userDataMap[user];
+
+    FileSystem fs(user);
+    if (handle.isMainDKEK)
+        fs.saveDKEKBackup(fs.getDKEK());
+
+    fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password));
+
+    handle.isMainDKEK = true;
+    handle.isDKEKConfirmed = false;
+}
+
+RawBuffer CKMLogic::unlockUserKey(uid_t user, const Password &password, bool apiRequest) {
     // TODO try catch for all errors that should be supported by error code
     int retCode = CKM_API_SUCCESS;
 
@@ -69,14 +124,8 @@ RawBuffer CKMLogic::unlockUserKey(uid_t user, const Password &password) {
         if (0 == m_userDataMap.count(user) || !(m_userDataMap[user].keyProvider.isInitialized())) {
             auto &handle = m_userDataMap[user];
             FileSystem fs(user);
-            auto wrappedDomainKEK = fs.getDKEK();
 
-            if (wrappedDomainKEK.empty()) {
-                wrappedDomainKEK = KeyProvider::generateDomainKEK(std::to_string(user), password);
-                fs.saveDKEK(wrappedDomainKEK);
-            }
-
-            handle.keyProvider = KeyProvider(wrappedDomainKEK, password);
+            loadDKEKFile(user, password, apiRequest);
 
             auto wrappedDatabaseDEK = fs.getDBDEK();
 
@@ -94,6 +143,9 @@ RawBuffer CKMLogic::unlockUserKey(uid_t user, const Password &password) {
             for(auto& appSmackLabel : removedApps) {
                 handle.database.deleteKey(appSmackLabel);
             }
+        } else if (apiRequest == true && m_userDataMap[user].isDKEKConfirmed == false) {
+            // now we will try to choose the DKEK key and remove old one
+            loadDKEKFile(user, password, apiRequest);
         }
     } catch (const KeyProvider::Exception::PassWordError &e) {
         LogError("Incorrect Password " << e.GetMessage());
@@ -150,14 +202,8 @@ RawBuffer CKMLogic::changeUserPassword(
 {
     int retCode = CKM_API_SUCCESS;
     try {
-        FileSystem fs(user);
-        auto wrappedDomainKEK = fs.getDKEK();
-        if (wrappedDomainKEK.empty()) {
-            retCode = CKM_API_ERROR_BAD_REQUEST;
-        } else {
-            wrappedDomainKEK = KeyProvider::reencrypt(wrappedDomainKEK, oldPassword, newPassword);
-            fs.saveDKEK(wrappedDomainKEK);
-        }
+        loadDKEKFile(user, oldPassword, true);
+        saveDKEKFile(user, newPassword);
     } catch (const KeyProvider::Exception::PassWordError &e) {
         LogError("Incorrect Password " << e.GetMessage());
         retCode = CKM_API_ERROR_AUTHENTICATION_FAILED;
@@ -181,9 +227,7 @@ RawBuffer CKMLogic::resetUserPassword(
     if (0 == m_userDataMap.count(user)) {
         retCode = CKM_API_ERROR_BAD_REQUEST;
     } else {
-        auto &handler = m_userDataMap[user];
-        FileSystem fs(user);
-        fs.saveDKEK(handler.keyProvider.getWrappedDomainKEK(newPassword));
+        saveDKEKFile(user, newPassword);
     }
 
     return MessageBuffer::Serialize(retCode).Pop();
index 853be0e..32eb889 100644 (file)
 namespace CKM {
 
 struct UserData {
+    UserData()
+      : isMainDKEK(false)
+      , isDKEKConfirmed(false)
+    {}
+
     KeyProvider    keyProvider;
     DBCrypto       database;
     CryptoLogic    crypto;
+    bool           isMainDKEK;
+    bool           isDKEKConfirmed;
 };
 
 class CKMLogic {
@@ -52,7 +59,7 @@ public:
     CKMLogic& operator=(CKMLogic &&) = delete;
     virtual ~CKMLogic();
 
-    RawBuffer unlockUserKey(uid_t user, const Password &password);
+    RawBuffer unlockUserKey(uid_t user, const Password &password, bool apiRequest = true);
 
     RawBuffer lockUserKey(uid_t user);
 
@@ -171,6 +178,21 @@ public:
 
 private:
 
+    void loadDKEKFile(
+        uid_t user,
+        const Password &password,
+        bool apiReq);
+
+    void chooseDKEKFile(
+        UserData &handle,
+        const Password &password,
+        const RawBuffer &first,
+        const RawBuffer &second);
+
+    void saveDKEKFile(
+        uid_t user,
+        const Password &password);
+
     int verifyBinaryData(
         DBDataType dataType,
         const RawBuffer &input_data) const;
index 722f6ab..2313dfa 100644 (file)
@@ -184,7 +184,7 @@ RawBuffer CKMService::processStorage(Credentials &cred, MessageBuffer &buffer)
     // So, to unlock user data when lock type is None, key-manager always try to unlock user data with null password.
     // Even if the result is fail, it will be ignored.
     Password nullPassword("");
-    m_logic->unlockUserKey(cred.uid, nullPassword);
+    m_logic->unlockUserKey(cred.uid, nullPassword, false);
 
     LogDebug("Process storage. Command: " << command);
 
index cefea59..084372b 100644 (file)
@@ -20,6 +20,7 @@
  * @brief       Sample service implementation.
  */
 #include <string.h>
+#include <stdio.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -42,6 +43,7 @@ namespace {
 
 const std::string CKM_DATA_PATH = "/opt/data/ckm/";
 const std::string CKM_KEY_PREFIX = "key-";
+const std::string CKM_KEY_BACKUP_PREFIX = "key-backup-";
 const std::string CKM_DB_KEY_PREFIX = "db-key-";
 const std::string CKM_DB_PREFIX = "db-";
 const std::string CKM_REMOVED_APP_PREFIX = "removed-app-";
@@ -68,6 +70,12 @@ std::string FileSystem::getDKEKPath() const {
     return ss.str();
 }
 
+std::string FileSystem::getDKEKBackupPath() const {
+    std::stringstream ss;
+    ss << CKM_DATA_PATH << CKM_KEY_BACKUP_PREFIX << m_uid;
+    return ss.str();
+}
+
 std::string FileSystem::getDBDEKPath() const {
     std::stringstream ss;
     ss << CKM_DATA_PATH << CKM_DB_KEY_PREFIX << m_uid;
@@ -99,6 +107,11 @@ RawBuffer FileSystem::getDKEK() const
     return loadFile(getDKEKPath());
 }
 
+RawBuffer FileSystem::getDKEKBackup() const
+{
+    return loadFile(getDKEKBackupPath());
+}
+
 RawBuffer FileSystem::getDBDEK() const
 {
     return loadFile(getDBDEKPath());
@@ -121,6 +134,26 @@ bool FileSystem::saveDKEK(const RawBuffer &buffer) const {
     return saveFile(getDKEKPath(), buffer);
 }
 
+bool FileSystem::saveDKEKBackup(const RawBuffer &buffer) const {
+    return saveFile(getDKEKBackupPath(), buffer);
+}
+
+bool FileSystem::restoreDKEK() const {
+    if (0 == ::rename(getDKEKBackupPath().c_str(), getDKEKPath().c_str()))
+        return true;
+    int err = errno;
+    LogError("Error in rename file DKEKBackup to DKEK: " << GetErrnoString(err));
+    return false;
+}
+
+bool FileSystem::removeDKEKBackup() const {
+    if (0 == unlink(getDKEKBackupPath().c_str()))
+        return true;
+    int err = errno;
+    LogError("Error in unlink file DKEKBackup: " << GetErrnoString(err));
+    return false;
+}
+
 bool FileSystem::saveDBDEK(const RawBuffer &buffer) const {
     return saveFile(getDBDEKPath(), buffer);
 }
@@ -227,6 +260,13 @@ int FileSystem::removeUserData() const {
             << "Errno: " << errno << " " << GetErrnoString(err));
     }
 
+    if (unlink(getDKEKBackupPath().c_str())) {
+        retCode = -1;
+        err = errno;
+        LogError("Error in unlink user backup DKEK: " << getDKEKBackupPath()
+            << "Errno: " << errno << " " << GetErrnoString(err));
+    }
+
     if (unlink(getDBDEKPath().c_str())) {
         retCode = -1;
         err = errno;
index 694ccde..4bc44ad 100644 (file)
@@ -38,8 +38,14 @@ public:
 
     // Domain Key Encryption Key
     RawBuffer getDKEK() const;
+    RawBuffer getDKEKBackup() const;
     bool saveDKEK(const RawBuffer &buffer) const;
 
+    // Functions required in "password change transaction"
+    bool saveDKEKBackup(const RawBuffer &buffer) const;
+    bool restoreDKEK() const; // delete DKEK and move DKEKBackup -> DKEK
+    bool removeDKEKBackup() const;  // delete DKEKBackup
+
     // Database Data Encryption Key
     RawBuffer getDBDEK() const;
     bool saveDBDEK(const RawBuffer &buffer) const;
@@ -57,6 +63,7 @@ public:
     virtual ~FileSystem(){}
 protected:
     std::string getDKEKPath() const;
+    std::string getDKEKBackupPath() const;
     std::string getDBDEKPath() const;
     RawBuffer loadFile(const std::string &path) const;
     bool saveFile(const std::string &path, const RawBuffer &buffer) const;
@@ -65,5 +72,5 @@ protected:
     uid_t m_uid;
 };
 
-}
+} // namespace CKM