From: Zofia Abramowska Date: Mon, 9 Jun 2014 15:42:32 +0000 (+0200) Subject: Add encrypted database support layer X-Git-Tag: accepted/tizen/common/20140925.172038~153 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9c994291161627d7e84ef2b0ee02a682b451739b;p=platform%2Fcore%2Fsecurity%2Fkey-manager.git Add encrypted database support layer Adding DBCrypto class, which supports creating/inserting/querying the encrypted database. Remove DBRow struct definition from Module header. Change-Id: I10f502b58b6912bdd1eff6563853f9d183ef59ed --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6985e81..5325033 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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}) diff --git a/src/manager/CMakeLists.txt b/src/manager/CMakeLists.txt index 67bda87..5cdba64 100644 --- a/src/manager/CMakeLists.txt +++ b/src/manager/CMakeLists.txt @@ -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 index 0000000..c4e1bc5 --- /dev/null +++ b/src/manager/common/db-crypto.cpp @@ -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 +#include +#include + +#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(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(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(type)); + selectCommand->BindInteger(2, static_cast(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 index 0000000..b6e86be --- /dev/null +++ b/src/manager/common/db-crypto.h @@ -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 +#include +#include +#include +#include + +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 diff --git a/src/manager/common/protocols.h b/src/manager/common/protocols.h index 369a743..eb62dbd 100644 --- a/src/manager/common/protocols.h +++ b/src/manager/common/protocols.h @@ -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); diff --git a/src/manager/service/DBCryptoModule.cpp b/src/manager/service/DBCryptoModule.cpp index 6a2e059..60ace08 100644 --- a/src/manager/service/DBCryptoModule.cpp +++ b/src/manager/service/DBCryptoModule.cpp @@ -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; diff --git a/src/manager/service/DBCryptoModule.h b/src/manager/service/DBCryptoModule.h index b0f714d..33147d1 100644 --- a/src/manager/service/DBCryptoModule.h +++ b/src/manager/service/DBCryptoModule.h @@ -2,28 +2,13 @@ #include #include +#include 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 m_keyMap;