Add encrypted database support layer
authorZofia Abramowska <z.abramowska@samsung.com>
Mon, 9 Jun 2014 15:42:32 +0000 (17:42 +0200)
committerBartlomiej Grzelewski <b.grzelewski@samsung.com>
Fri, 12 Sep 2014 12:57:15 +0000 (14:57 +0200)
Adding DBCrypto class, which supports creating/inserting/querying
the encrypted database. Remove DBRow struct definition from Module
 header.

Change-Id: I10f502b58b6912bdd1eff6563853f9d183ef59ed

src/CMakeLists.txt
src/manager/CMakeLists.txt
src/manager/common/db-crypto.cpp [new file with mode: 0644]
src/manager/common/db-crypto.h [new file with mode: 0644]
src/manager/common/protocols.h
src/manager/service/DBCryptoModule.cpp
src/manager/service/DBCryptoModule.h

index 6985e81..5325033 100644 (file)
@@ -38,8 +38,10 @@ INCLUDE_DIRECTORIES(
     ${KEY_MANAGER_PATH}/main
     ${KEY_MANAGER_PATH}/common
     ${KEY_MANAGER_PATH}/service
+    ${KEY_MANAGER_PATH}/sqlcipher
     ${KEY_MANAGER_PATH}/dpl/core/include
     ${KEY_MANAGER_PATH}/dpl/log/include
+    ${KEY_MANAGER_PATH}/dpl/db/include
     )
 
 ADD_EXECUTABLE(${TARGET_KEY_MANAGER} ${KEY_MANAGER_SOURCES})
index 67bda87..5cdba64 100644 (file)
@@ -21,6 +21,7 @@ SET(COMMON_SOURCES
     ${COMMON_PATH}/common/smack-check.cpp
     ${COMMON_PATH}/common/certificate-impl.cpp
     ${COMMON_PATH}/common/key-impl.cpp
+    ${COMMON_PATH}/common/db-crypto.cpp
     ${COMMON_PATH}/dpl/log/src/abstract_log_provider.cpp
     ${COMMON_PATH}/dpl/log/src/dlog_log_provider.cpp
     ${COMMON_PATH}/dpl/log/src/log.cpp
diff --git a/src/manager/common/db-crypto.cpp b/src/manager/common/db-crypto.cpp
new file mode 100644 (file)
index 0000000..c4e1bc5
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2014 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        db-crypto.cpp
+ * @author      Zofia Abramowska (z.abramowska@samsung.com)
+ * @version     1.0
+ * @brief       Implementation of encrypted db access layer
+ */
+
+#include <db-crypto.h>
+#include <dpl/db/sql_connection.h>
+#include <dpl/log/log.h>
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic warning "-Wdeprecated-declarations"
+
+namespace {
+    const char *main_table = "CKM_TABLE";
+
+    const char *db_create_cmd =
+            "CREATE TABLE CKM_TABLE("
+            "   alias TEXT PRIMARY KEY,"
+            "   label TEXT NOT NULL,"
+            "   restricted INTEGER NOT NULL,"
+            "   exportable INTEGER NOT NULL,"
+            "   dataType INTEGER NOT NULL,"
+            "   algorithmType INTEGER NOT NULL,"
+            "   encryptionScheme INTEGER NOT NULL,"
+            "   iv BLOB NOT NULL,"
+            "   dataSize INTEGER NOT NULL,"
+            "   date BLOB NOT NULL"
+            ");";
+
+    const char *insert_cmd =
+            "INSERT INTO CKM_TABLE("
+            //      1   2       3           4
+            "   alias, label, restricted, exportable,"
+            //      5           6           7
+            "   dataType, algorithmType, encryptionScheme,"
+            //  8       9       10
+            "   iv, dataSize, date) "
+            "VALUES("
+            "   ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";
+
+    const char *select_alias_cmd =
+            //                                   1
+            "SELECT * FROM CKM_TABLE WHERE alias=?;";
+
+    const char *select_type_cmd =
+            //                                          1
+            "SELECT alias FROM CKM_TABLE WHERE dataType=? AND restricted=0 "
+            "UNION ALL "
+            //                                          2                            3
+            "SELECT alias FROM CKM_TABLE WHERE dataType=? AND restricted=1 AND label=?;";
+}
+
+namespace CKM {
+using namespace DB;
+    DBCrypto::DBCrypto(const std::string& path,
+                         const RawBuffer &rawPass) {
+        m_connection = NULL;
+        m_init = false;
+        Try {
+            m_connection = new SqlConnection(path, SqlConnection::Flag::Option::CRW);
+            m_connection->SetKey(rawPass);
+            m_init = true;
+            if(!(m_connection->CheckTableExist(main_table)))
+                initDatabase();
+        } Catch(SqlConnection::Exception::ConnectionBroken) {
+            LogError("Couldn't connect to database: " << path);
+        } Catch(SqlConnection::Exception::InvalidArguments) {
+            LogError("Couldn't set the key for database");
+        }
+    }
+
+    DBCrypto::DBCrypto(DBCrypto &&other) :
+            m_connection(other.m_connection),
+            m_init(other.m_init) {
+        other.m_connection = NULL;
+        other.m_init = false;
+    }
+
+    DBCrypto& DBCrypto::operator=(DBCrypto&& other) {
+        if (this == &other)
+            return *this;
+        delete m_connection;
+
+        m_connection = other.m_connection;
+        other.m_connection = NULL;
+
+        m_init = other.m_init;
+        other.m_init = false;
+
+        return *this;
+    }
+
+    void DBCrypto::initDatabase() {
+        Try {
+            m_connection->ExecCommand(db_create_cmd);
+            m_init = true;
+        } Catch(SqlConnection::Exception::SyntaxError) {
+            LogError("Couldn't create the main table!");
+            m_init = false;
+        }
+    }
+
+    DBCryptoReturn DBCrypto::saveDBRow(const DBRow &row){
+        if(!m_init)
+            return DBCryptoReturn::DBCRYPTO_ERROR_INTERNAL;
+        Try {
+            SqlConnection::DataCommandAutoPtr insertCommand =
+                    m_connection->PrepareDataCommand(insert_cmd);
+            insertCommand->BindString(1, row.alias.c_str());
+            insertCommand->BindString(2, row.smackLabel.c_str());
+            insertCommand->BindInteger(3, row.restricted);
+            insertCommand->BindInteger(4, row.exportable);
+            insertCommand->BindInteger(5, static_cast<int>(row.dataType));
+            insertCommand->BindInteger(6, row.algorithmType);
+            insertCommand->BindInteger(7, row.encryptionScheme);
+            insertCommand->BindBlob(8, row.iv);
+            insertCommand->BindInteger(9, row.dataSize);
+            insertCommand->BindBlob(10, row.data);
+
+            AssertMsg(insertCommand->Step() == false,
+                    "Insert statement should not return any row");
+        } Catch(SqlConnection::Exception::SyntaxError) {
+            LogError("Couldn't prepare insert statement");
+            return DBCryptoReturn::DBCRYPTO_ERROR_INTERNAL;
+        } Catch(SqlConnection::Exception::InternalError) {
+            LogError("Couldn't execute insert statement");
+            return DBCryptoReturn::DBCRYPTO_ERROR_INTERNAL;
+        }
+
+        return DBCryptoReturn::DBCRYPTO_SUCCESS;
+    }
+
+    DBCryptoReturn DBCrypto::getDBRow(const Alias &alias,
+                                                   DBRow &row) {
+
+        if(!m_init)
+            return DBCryptoReturn::DBCRYPTO_ERROR_INTERNAL;
+        Try {
+        SqlConnection::DataCommandAutoPtr selectCommand =
+                m_connection->PrepareDataCommand(select_alias_cmd);
+        selectCommand->BindString(1, alias.c_str());
+
+        if(selectCommand->Step()) {
+            row.alias = selectCommand->GetColumnString(1);
+            row.smackLabel = selectCommand->GetColumnString(2);
+            row.restricted = selectCommand->GetColumnInteger(3);
+            row.exportable = selectCommand->GetColumnInteger(4);
+            row.dataType = static_cast<DBDataType>(selectCommand->GetColumnInteger(5));
+            row.algorithmType = selectCommand->GetColumnInteger(6);
+            row.encryptionScheme = selectCommand->GetColumnInteger(7);
+            row.iv = selectCommand->GetColumnBlob(8);
+            row.dataSize = selectCommand->GetColumnInteger(9);
+            row.data = selectCommand->GetColumnBlob(10);
+        } else {
+            return DBCryptoReturn::DBCRYPTO_ERROR_NO_ROW;
+        }
+
+        AssertMsg(!selectCommand->Step(),
+                "Select returned multiple rows for unique column.");
+        } Catch (SqlConnection::Exception::InvalidColumn) {
+            LogError("Select statement invalid column error");
+            return DBCryptoReturn::DBCRYPTO_ERROR_INTERNAL;
+        } Catch (SqlConnection::Exception::SyntaxError) {
+            LogError("Couldn't prepare select statement");
+            return DBCryptoReturn::DBCRYPTO_ERROR_INTERNAL;
+        } Catch (SqlConnection::Exception::InternalError) {
+            LogError("Couldn't execute select statement");
+            return DBCryptoReturn::DBCRYPTO_ERROR_INTERNAL;
+        }
+        return DBCryptoReturn::DBCRYPTO_SUCCESS;
+    }
+
+    DBCryptoReturn DBCrypto::getSingleType(DBDataType type, const std::string& label,
+            AliasVector& aliases) {
+        Try{
+            SqlConnection::DataCommandAutoPtr selectCommand =
+                            m_connection->PrepareDataCommand(select_type_cmd);
+            selectCommand->BindInteger(1, static_cast<int>(type));
+            selectCommand->BindInteger(2, static_cast<int>(type));
+            selectCommand->BindString(3, label.c_str());
+
+            while(selectCommand->Step()) {
+                Alias alias;
+                alias = selectCommand->GetColumnString(1);
+                aliases.push_back(alias);
+            }
+        } Catch (SqlConnection::Exception::InvalidColumn) {
+            LogError("Select statement invalid column error");
+            return DBCryptoReturn::DBCRYPTO_ERROR_INTERNAL;
+        } Catch (SqlConnection::Exception::SyntaxError) {
+            LogError("Couldn't prepare select statement");
+            return DBCryptoReturn::DBCRYPTO_ERROR_INTERNAL;
+        } Catch (SqlConnection::Exception::InternalError) {
+            LogError("Couldn't execute select statement");
+            return DBCryptoReturn::DBCRYPTO_ERROR_INTERNAL;
+        }
+        return DBCryptoReturn::DBCRYPTO_SUCCESS;
+    }
+
+    DBCryptoReturn DBCrypto::getAliases(DBQueryType type, const std::string& label,
+            AliasVector& aliases) {
+
+        if(!m_init)
+            return DBCryptoReturn::DBCRYPTO_ERROR_INTERNAL;
+        DBCryptoReturn ret;
+        switch(type) {
+        case DBQueryType::KEY_QUERY:
+            ret = getSingleType(DBDataType::KEY_AES, label, aliases);
+            if(ret != DBCryptoReturn::DBCRYPTO_SUCCESS)
+                return ret;
+            ret = getSingleType(DBDataType::KEY_ECDSA_PRIVATE, label, aliases);
+            if(ret != DBCryptoReturn::DBCRYPTO_SUCCESS)
+                return ret;
+            ret = getSingleType(DBDataType::KEY_ECDSA_PUBLIC, label, aliases);
+            if(ret != DBCryptoReturn::DBCRYPTO_SUCCESS)
+                return ret;
+            ret = getSingleType(DBDataType::KEY_RSA_PRIVATE, label, aliases);
+            if(ret != DBCryptoReturn::DBCRYPTO_SUCCESS)
+                return ret;
+            return(getSingleType(DBDataType::KEY_RSA_PUBLIC, label, aliases));
+        case DBQueryType::CERTIFICATE_QUERY:
+            return getSingleType(DBDataType::CERTIFICATE, label, aliases);
+        case DBQueryType::BINARY_DATA_QUERY:
+            return getSingleType(DBDataType::BINARY_DATA, label, aliases);
+        }
+        return DBCryptoReturn::DBCRYPTO_SUCCESS;
+    }
+
+} // CKM
+
+#pragma GCC diagnostic pop
diff --git a/src/manager/common/db-crypto.h b/src/manager/common/db-crypto.h
new file mode 100644 (file)
index 0000000..b6e86be
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2014 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        db-crypto.h
+ * @author      Zofia Abramowska (z.abramowska@samsung.com)
+ * @version     1.0
+ * @brief       Header of encrypted db access layer
+ */
+
+#ifndef DB_CRYPTO_H
+#define DB_CRYPTO_H
+
+#include <vector>
+#include <string>
+#include <ckm/ckm-type.h>
+#include <dpl/db/sql_connection.h>
+#include <protocols.h>
+
+namespace CKM {
+    struct DBRow {
+        std::string alias;
+        std::string smackLabel;
+        int restricted;
+        int exportable;
+        DBDataType dataType;        // cert/key/data
+        int algorithmType;          // AES mode ?
+        int encryptionScheme;       // for example: (ENCR_BASE64 | ENCR_PASSWORD)
+        RawBuffer iv;               // encoded in base64
+        int dataSize;               // size of information without hash and padding
+        RawBuffer data;
+    };
+    enum class DBCryptoReturn : int {
+        DBCRYPTO_SUCCESS = 0,
+        DBCRYPTO_ERROR_NO_ROW,
+        DBCRYPTO_ERROR_INTERNAL,
+        DBCRYPTO_ERROR_INVALID_ARGUMENTS
+    };
+    class DBCrypto {
+         public:
+            DBCrypto() : m_connection(NULL), m_init(false) {};
+            //user name instead of path?
+            DBCrypto(const std::string &path,
+                                const RawBuffer &rawPass);
+            DBCrypto(const DBCrypto &other) = delete;
+            DBCrypto(DBCrypto &&other);
+
+            DBCrypto& operator=(const DBCrypto& ) = delete;
+            DBCrypto& operator=(DBCrypto&& other);
+
+            ~DBCrypto();
+
+            DBCryptoReturn saveDBRow(const DBRow &row);
+            DBCryptoReturn getDBRow(const Alias &alias, DBRow& row);
+            DBCryptoReturn getAliases(DBQueryType dataType, const std::string &label,
+                    AliasVector &aliases);
+
+         private:
+            DB::SqlConnection* m_connection;
+            bool m_init;
+
+            void initDatabase();
+            bool checkTableExist(const std::string& table);
+            DBCryptoReturn getSingleType(DBDataType type, const std::string& label,
+                    AliasVector& aliases);
+
+   };
+}
+#endif //DB_CRYPTO_H
index 369a743..eb62dbd 100644 (file)
@@ -59,6 +59,12 @@ enum class DBDataType : int {
     BINARY_DATA
 };
 
+enum class DBQueryType : int {
+    KEY_QUERY,
+    CERTIFICATE_QUERY,
+    BINARY_DATA_QUERY
+};
+
 DBDataType toDBDataType(KeyType key);
 KeyType toKeyType(DBDataType dbDataType);
 
index 6a2e059..60ace08 100644 (file)
@@ -102,19 +102,19 @@ int DBCryptoModule::encryptRow(const RawBuffer &password, DBRow &row)
     ret = cryptAES(crow.data, crow.dataSize + dlen, appkey, emptyiv);
     if (ret != 0)
         return ret;
-    crow.encryptionScheme |= DBRow::ENCR_APPKEY;
+    crow.encryptionScheme |= ENCR_APPKEY;
     if (password.size() > 0) {
         if ((ret = generateKeysFromPassword(password, userkey, crow.iv)))
             return ret;
         ret = cryptAES(crow.data, 0, userkey, crow.iv);
         if (ret != 0)
             return ret;
-        crow.encryptionScheme |= DBRow::ENCR_PASSWORD;
+        crow.encryptionScheme |= ENCR_PASSWORD;
     }
     ret = encBase64(crow.data);
     if (ret != 0)
         return ret;
-    crow.encryptionScheme |= DBRow::ENCR_BASE64;
+    crow.encryptionScheme |= ENCR_BASE64;
     ret = encBase64(crow.iv);
     if (ret != 0)
         return ret;
@@ -138,7 +138,7 @@ int DBCryptoModule::decryptRow(const RawBuffer &password, DBRow &row)
         return ret;
     if (row.dataSize <= 0)
         return ret;
-    if (row.encryptionScheme && DBRow::ENCR_PASSWORD)
+    if (row.encryptionScheme && ENCR_PASSWORD)
         if (password.size() == 0)
             return ret;
     if (!haveKey(row.smackLabel))
@@ -148,19 +148,19 @@ int DBCryptoModule::decryptRow(const RawBuffer &password, DBRow &row)
     ret = decBase64(crow.iv);
     if (ret)
         return ret;
-    if (crow.encryptionScheme && DBRow::ENCR_BASE64) {
+    if (crow.encryptionScheme && ENCR_BASE64) {
         ret = decBase64(crow.data);
         if (ret)
             return ret;
     }
-    if (crow.encryptionScheme && DBRow::ENCR_PASSWORD) {
+    if (crow.encryptionScheme && ENCR_PASSWORD) {
         if ((ret = generateKeysFromPassword(password, userkey, dropiv)))
             return ret;
         ret = decryptAES(crow.data, 0, userkey, crow.iv);
         if (ret)
             return ret;
     }
-    if (crow.encryptionScheme && DBRow::ENCR_APPKEY) {
+    if (crow.encryptionScheme && ENCR_APPKEY) {
         ret = decryptAES(crow.data, 0, appkey, emptyiv);
         if (ret)
             return ret;
index b0f714d..33147d1 100644 (file)
@@ -2,28 +2,13 @@
 
 #include <map>
 #include <ckm/ckm-type.h>
+#include <db-crypto.h>
 
 namespace CKM {
 
-struct DBRow {
-       static const int ENCR_BASE64 =   1 << 0;
-       static const int ENCR_APPKEY =   1 << 1;
-       static const int ENCR_PASSWORD = 1 << 2;
-
-       std::string user;
-       std::string smackLabel;
-       int dataType;                       // cert/key/data
-       int algorithmType;                  // AES mode ?
-       int encryptionScheme;               // for example: (ENCR_BASE64 | ENCR_PASSWORD)
-       RawBuffer iv;                       // encoded in base64
-       int dataSize;                       // size of information without hash and padding
-       RawBuffer data;
-};
-
-
 class DBCryptoModule {
 public:
-       DBCryptoModule(RawBuffer &domainKEK);
+    DBCryptoModule(RawBuffer &domainKEK);
 
        int decryptRow(const RawBuffer &password, DBRow &row);
        int encryptRow(const RawBuffer &password, DBRow &row);
@@ -32,6 +17,10 @@ public:
        int pushKey(const std::string &smackLabel, const RawBuffer &applicationKey);
 
 private:
+       static const int ENCR_BASE64 =   1 << 0;
+       static const int ENCR_APPKEY =   1 << 1;
+       static const int ENCR_PASSWORD = 1 << 2;
+       
        RawBuffer m_domainKEK;
        std::map<std::string, RawBuffer> m_keyMap;