From 1bf0726b3028ddfaae0cdd70e46b416335da39a0 Mon Sep 17 00:00:00 2001 From: Janusz Kozerski Date: Fri, 26 Jun 2015 11:58:59 +0200 Subject: Refactor DB and app_t structure - preparation for OCSP checking. New version of DB is needed to keep separately certificates from each signatrue. Because application can be signed by more than one signature we need to keep all certificates from all signatures in separate lists to make building certificates' chains easier. * Add operators (==, !=, <) for app_t structre * Add operators (==, !=) for event_t structure * Add tests for operators * Remove check_id from app_t structure Change-Id: I966dd81420618325d1afa55bcbc656291ccb4238 --- src/app.cpp | 24 +++++--- src/certs.cpp | 9 ++- src/db/sql_query.cpp | 124 +++++++++++++++++++++++++++++---------- src/include/cchecker/app.h | 18 +++--- src/include/cchecker/sql_query.h | 1 + 5 files changed, 127 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/src/app.cpp b/src/app.cpp index 58a7883..08b79a5 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -22,16 +22,14 @@ #include #include -#include #include #include +#include namespace CCHECKER { app_t::app_t(void): - check_id(-1), // -1 as invalid check_id - assume that in database - // all check_ids will be positive uid((uid_t)-1), // (uid_t)-1 (0xFF) is defined to be invalid uid. According // to chown manual page, you cannot change file group of owner // to (uid_t)-1, so we'll use it as initial, invalid value. @@ -41,19 +39,17 @@ app_t::app_t(void): app_t::app_t(const std::string &app_id, const std::string &pkg_id, uid_t uid, - const std::vector &certificates): - check_id(-1), + const signatures_t &signatures): app_id(app_id), pkg_id(pkg_id), uid(uid), - certificates(certificates), + signatures(signatures), verified(verified_t::UNKNOWN) {} std::ostream & operator<< (std::ostream &out, const app_t &app) { - out << "app: " << app.app_id << ", pkg: " << app.pkg_id << ", uid: " << app.uid << - ", check_id: " << app.check_id; + out << "app: " << app.app_id << ", pkg: " << app.pkg_id << ", uid: " << app.uid; return out; } @@ -64,4 +60,16 @@ std::string app_t::str() const return ss.str(); } +std::string app_t::str_certs(void) const +{ + std::stringstream ss; + + for (const auto &iter : signatures) { + for (const auto iter_cert : iter) { + ss << "\"" << iter_cert << "\", "; + } + } + return ss.str(); +} + } //CCHECKER diff --git a/src/certs.cpp b/src/certs.cpp index 4a69fde..5b69ba0 100644 --- a/src/certs.cpp +++ b/src/certs.cpp @@ -119,7 +119,8 @@ void Certs::find_app_signatures (app_t &app, const std::string &app_path, ocsp_u LogDebug("Number of signature files: " << signature_files.size()); LogDebug("Searching for certificates"); - for (auto iter = signature_files.begin(); iter != signature_files.end(); iter++){ + for (auto iter = signature_files.begin(); iter != signature_files.end(); iter++) { + chain_t chain; LogDebug("Checking signature"); ValidationCore::SignatureData data(app_path + std::string("/") + (*iter).getFileName(), (*iter).getFileNumber()); @@ -131,7 +132,7 @@ void Certs::find_app_signatures (app_t &app, const std::string &app_path, ocsp_u ValidationCore::CertificateList certs = data.getCertList(); for (auto cert_iter = certs.begin(); cert_iter != certs.end(); cert_iter++ ){ std::string app_cert = (*cert_iter)->getBase64(); - app.certificates.push_back(app_cert); + chain.push_back(app_cert); LogDebug("Certificate: " << app_cert << " has been added"); // check OCSP URL @@ -150,6 +151,10 @@ void Certs::find_app_signatures (app_t &app, const std::string &app_path, ocsp_u // Needs to catch parser exceptions LogError("Error occured in ParserSchema: " << exception.DumpToString()); } + if (!chain.empty()) { + app.signatures.push_back(chain); + LogDebug("Certificates chain added to the app"); + } } } diff --git a/src/db/sql_query.cpp b/src/db/sql_query.cpp index 0968717..27eb52e 100644 --- a/src/db/sql_query.cpp +++ b/src/db/sql_query.cpp @@ -36,6 +36,12 @@ namespace { // 107 - check_id // 108 - certificate // 109 - verified + // 110 - chain_id + + // setup + const char *DB_CMD_SETUP = "VACUUM; PRAGMA foregin_keys=ON;"; + + const char *DB_CMD_GET_LAST_INSERTED_ROW = "SELECT last_insert_rowid();"; // urls const char *DB_CMD_GET_URL = @@ -54,17 +60,24 @@ namespace { const char *DB_CMD_GET_CHECK_ID = "SELECT check_id FROM to_check WHERE app_id=?104 AND pkg_id=?105 AND uid=?106;"; + const char *DB_CMD_ADD_CHAIN = + "INSERT INTO chains_to_check(check_id) VALUES(?107);"; + const char *DB_CMD_ADD_CERT = - "INSERT INTO certs_to_check(check_id, certificate) VALUES(?107, ?108);"; + "INSERT INTO certs_to_check(chain_id, certificate) VALUES(?110, ?108);"; + + const char *DB_CMD_GET_CHAINS = + "SELECT chain_id FROM chains_to_check INNER JOIN to_check ON chains_to_check.check_id=to_check.check_id \ +WHERE to_check.app_id=?104 AND to_check.pkg_id=?105 AND to_check.uid=?106;"; const char *DB_CMD_REMOVE_APP = "DELETE FROM to_check WHERE app_id=?104 AND pkg_id=?105 AND uid=?106;"; const char *DB_CMD_GET_APPS = - "SELECT * FROM to_check"; + "SELECT app_id, pkg_id, uid, verified FROM to_check"; const char *DB_CMD_GET_CERTS = - "SELECT certificate FROM certs_to_check WHERE check_id=?107;"; + "SELECT certificate FROM certs_to_check WHERE chain_id=?110;"; const char *DB_CMD_SET_APP_AS_VERIFIED = "UPDATE to_check SET verified=?109 WHERE check_id=?107"; @@ -91,7 +104,7 @@ bool SqlQuery::connect(const std::string& path) Try { m_connection = new SqlConnection(path, SqlConnection::Flag::None, SqlConnection::Flag::Option::CRW); - m_connection->ExecCommand("VACUUM;"); + m_connection->ExecCommand(DB_CMD_SETUP); return true; } Catch(std::bad_alloc) { LogError("Couldn't allocate SqlConnection"); @@ -185,6 +198,25 @@ bool SqlQuery::get_check_id(const app_t &app, int32_t &check_id) return false; } +bool SqlQuery::add_chain_id(const int32_t check_id, int32_t &chain_id) +{ + // Add new chain for an app + SqlConnection::DataCommandAutoPtr addChainCommand = + m_connection->PrepareDataCommand(DB_CMD_ADD_CHAIN); + addChainCommand->BindInt32(107, check_id); + addChainCommand->Step(); + + // get chain_id + SqlConnection::DataCommandAutoPtr getLastInserted = + m_connection->PrepareDataCommand(DB_CMD_GET_LAST_INSERTED_ROW); + if(getLastInserted->Step()) { + chain_id = getLastInserted->GetColumnInt32(0); + LogDebug("Found chain_id: " << chain_id << ", for check_id " << check_id); + return true; + } + return false; +} + bool SqlQuery::add_app_to_check_list(const app_t &app) { //Check if app exists in DB @@ -206,23 +238,35 @@ bool SqlQuery::add_app_to_check_list(const app_t &app) // Get check_id int32_t check_id; - if (get_check_id(app, check_id)) { - // If get check_id succeed we can add certificates to database - for (const auto &iter : app.certificates) { - SqlConnection::DataCommandAutoPtr addCertCommand = - m_connection->PrepareDataCommand(DB_CMD_ADD_CERT); - addCertCommand->BindInt32(107, check_id); - addCertCommand->BindString(108, iter.c_str()); - addCertCommand->Step(); - LogDebug("Certificate for app " << app.app_id << "added"); - } - m_connection->CommitTransaction(); - return true; - } else { // If get check_id failed return false; + if (!get_check_id(app, check_id)) { // If get check_id failed return false; LogDebug("Failed while addind app "<< app.app_id << " to to_check table."); m_connection->RollbackTransaction(); return false; } + + // If get check_id succeed we can add chain to database + int32_t chain_id; + for (const auto &iter : app.signatures) { + // Add chain + if (add_chain_id(check_id, chain_id)) { + // add certificates from chain + for (const auto &iter_cert : iter) { + SqlConnection::DataCommandAutoPtr addCertCommand = + m_connection->PrepareDataCommand(DB_CMD_ADD_CERT); + addCertCommand->BindInt32(110, chain_id); + addCertCommand->BindString(108, iter_cert.c_str()); + addCertCommand->Step(); + LogDebug("Certificate for app " << app.app_id << "added"); + } + } else { + LogDebug("Failed to add certificates chain"); + m_connection->RollbackTransaction(); + return false; + } + + } + m_connection->CommitTransaction(); + return true; } void SqlQuery::remove_app_from_check_list(const app_t &app) @@ -265,12 +309,11 @@ void SqlQuery::get_apps(std::list &apps_buffer) while (getAppsCommand->Step()) { app_t app; - app.check_id = getAppsCommand->GetColumnInt32(0); - app.app_id = getAppsCommand->GetColumnString(1); - app.pkg_id = getAppsCommand->GetColumnString(2); - app.uid = getAppsCommand->GetColumnInt64(3); - app.verified = static_cast(getAppsCommand->GetColumnInt32(4)); - app.certificates = {}; + app.app_id = getAppsCommand->GetColumnString(0); + app.pkg_id = getAppsCommand->GetColumnString(1); + app.uid = getAppsCommand->GetColumnInt64(2); + app.verified = static_cast(getAppsCommand->GetColumnInt32(3)); + app.signatures = {}; LogDebug("App read from DB: app_id: " << app.str() << ", verified: " << static_cast(app.verified)); apps_buffer.push_back(app); } @@ -278,18 +321,37 @@ void SqlQuery::get_apps(std::list &apps_buffer) void SqlQuery::get_app_list(std::list &apps_buffer) { + m_connection->BeginTransaction(); get_apps(apps_buffer); - // Get certificates for apps - for (auto &iter : apps_buffer) { - SqlConnection::DataCommandAutoPtr getCertsCommand = - m_connection->PrepareDataCommand(DB_CMD_GET_CERTS); - getCertsCommand->BindInt32(107, iter.check_id); - - while (getCertsCommand->Step()) { - iter.certificates.push_back(getCertsCommand->GetColumnString(0)); + // Get chain for every application + for (auto &iter_app : apps_buffer) { + SqlConnection::DataCommandAutoPtr getChainsCommand = + m_connection->PrepareDataCommand(DB_CMD_GET_CHAINS); + getChainsCommand->BindString(104, iter_app.app_id.c_str()); + getChainsCommand->BindString(105, iter_app.pkg_id.c_str()); + getChainsCommand->BindInt32(106, iter_app.uid); + + // Get all certs from chain + while (getChainsCommand->Step()) { + chain_t chain; + int32_t chain_id; + chain_id = getChainsCommand->GetColumnInt32(0); + LogDebug("Found chain (" << chain_id << ") for " << iter_app.str()); + + SqlConnection::DataCommandAutoPtr getCertsCommand = + m_connection->PrepareDataCommand(DB_CMD_GET_CERTS); + getCertsCommand->BindInt32(110, chain_id); + + // Add found certs to chain + while (getCertsCommand->Step()) { + chain.push_back(getCertsCommand->GetColumnString(0)); + LogDebug("Found certificate (" << chain.size() << ") in chain no. " << chain_id); + } + iter_app.signatures.push_back(chain); } } + m_connection->CommitTransaction(); } } // DB diff --git a/src/include/cchecker/app.h b/src/include/cchecker/app.h index 3217bdb..46fd9b6 100644 --- a/src/include/cchecker/app.h +++ b/src/include/cchecker/app.h @@ -23,7 +23,6 @@ #define CCHECKER_APP_H #include -#include #include #include @@ -33,6 +32,9 @@ namespace CCHECKER { // Currently in signals from pkgmgr only information about pkg_id is included const char *const TEMP_APP_ID = "temp#app_id"; +typedef std::list chain_t; +typedef std::list signatures_t; + struct app_t { enum class verified_t : int32_t { NO = 0, @@ -40,19 +42,19 @@ struct app_t { UNKNOWN = 2 }; - int32_t check_id; - std::string app_id; - std::string pkg_id; - uid_t uid; - std::vector certificates; //TODO: add typedef - verified_t verified; + std::string app_id; + std::string pkg_id; + uid_t uid; + signatures_t signatures; + verified_t verified; app_t(void); app_t(const std::string &app_id, const std::string &pkg_id, uid_t uid, - const std::vector &certificates); + const signatures_t &signatures); std::string str(void) const; + std::string str_certs(void) const; }; struct url_t { diff --git a/src/include/cchecker/sql_query.h b/src/include/cchecker/sql_query.h index 5a22740..e4cc582 100644 --- a/src/include/cchecker/sql_query.h +++ b/src/include/cchecker/sql_query.h @@ -69,6 +69,7 @@ class SqlQuery { void get_apps(std::list &apps_buffer); bool check_if_app_exists(const app_t &app); bool get_check_id(const app_t &app, int32_t &check_id); + bool add_chain_id(const int32_t check_id, int32_t &chain_id); int verified_enum_to_int(const app_t::verified_t &verified); app_t::verified_t verified_int_to_enum(const int &verified); }; -- cgit v1.2.3