diff options
author | Janusz Kozerski <j.kozerski@samsung.com> | 2015-07-03 14:26:44 +0200 |
---|---|---|
committer | Janusz Kozerski <j.kozerski@samsung.com> | 2015-07-17 14:33:45 +0200 |
commit | ecacacfce9dc0f97fc67ba032726583b8881ed97 (patch) | |
tree | b8710bbd27d939524bf26bb802056d6736c85f8a /src | |
parent | 1bf0726b3028ddfaae0cdd70e46b416335da39a0 (diff) | |
download | cert-checker-ecacacfce9dc0f97fc67ba032726583b8881ed97.tar.gz cert-checker-ecacacfce9dc0f97fc67ba032726583b8881ed97.tar.bz2 cert-checker-ecacacfce9dc0f97fc67ba032726583b8881ed97.zip |
Add OCSP verification (CKM API is used)
* Add tests for certificates
* Remove unnecessary methods in Logic class
* Add missing include
* Use new cert-checker-vcore API
Change-Id: Idfa777d1f1ba6f7142ea78e29bf1bc63415b128e
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/certs.cpp | 178 | ||||
-rw-r--r-- | src/include/cchecker/certs.h | 31 | ||||
-rw-r--r-- | src/include/cchecker/logic.h | 6 | ||||
-rw-r--r-- | src/logic.cpp | 69 |
5 files changed, 237 insertions, 48 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bd75eb5..d5a56eb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,6 +8,7 @@ PKG_CHECK_MODULES(CERT_CHECKER_DEP gio-2.0 icu-i18n notification + key-manager libsystemd-journal libtzplatform-config sqlite3 diff --git a/src/certs.cpp b/src/certs.cpp index 5b69ba0..277546d 100644 --- a/src/certs.cpp +++ b/src/certs.cpp @@ -18,7 +18,7 @@ * @author Janusz Kozerski (j.kozerski@samsung.com) * @version 1.0 * @brief This file is the implementation of certificates logic - * Getting out findinf app signature, getting certificates out of + * Getting out app signature, getting certificates out of * signature. Checking OCSP */ #include <sys/types.h> @@ -26,13 +26,15 @@ #include <list> #include <memory> #include <string> -#include <set> #include <vector> -#include <vcore/Certificate.h> +#include <vcore/CertificateCollection.h> #include <vcore/SignatureReader.h> #include <vcore/SignatureFinder.h> #include <vcore/WrtSignatureValidator.h> #include <vcore/VCore.h> +#include <ckm/ckm-type.h> +#include <ckm/ckm-raw-buffer.h> +#include <tzplatform_config.h> #include <cchecker/certs.h> #include <cchecker/log.h> @@ -47,6 +49,7 @@ namespace CCHECKER { Certs::Certs() { ValidationCore::VCoreInit(); + m_ckm = CKM::Manager::create(); } Certs::~Certs() @@ -136,10 +139,9 @@ void Certs::find_app_signatures (app_t &app, const std::string &app_path, ocsp_u LogDebug("Certificate: " << app_cert << " has been added"); // check OCSP URL - std::string ocsp_url = DPL::ToUTF8String((*cert_iter)->getOCSPURL()); + std::string ocsp_url = (*cert_iter)->getOCSPURL(); if (ocsp_url != std::string("")) { - std::string issuer = DPL::ToUTF8String( - (*cert_iter)->getCommonName(ValidationCore::Certificate::FIELD_ISSUER)); + std::string issuer = (*cert_iter)->getCommonName(ValidationCore::Certificate::FIELD_ISSUER); int64_t time = (*cert_iter)->getNotBefore(); url_t url(issuer, ocsp_url, time); ocsp_urls.push_back(url); @@ -158,4 +160,168 @@ void Certs::find_app_signatures (app_t &app, const std::string &app_path, ocsp_u } } +bool Certs::ocsp_create_list (const chain_t &chain, ValidationCore::CertificateList &certs_list) +{ + ValidationCore::CertificateCollection collection; + ValidationCore::CertificateList list; + + LogDebug("Chain size: " << chain.size()); + for (auto &iter : chain) { + try { + ValidationCore::CertificatePtr p_cert( + new ValidationCore::Certificate(iter, ValidationCore::Certificate::FORM_BASE64)); + list.push_back(p_cert); + } catch (const ValidationCore::Certificate::Exception::Base& exception) { + LogError("Error while creating certificate from BASE64: " << exception.DumpToString()); + return false; + } + LogDebug("Load certificate to list: " << list.size()); + } + + // Function collection.load which takes certificate in std::string BASE64 fails for some reason, + // so load(const CertificateList &certList) is used. + collection.load(list); + LogDebug("Load certificate to CertificateCollection: " << collection.size()); + + if (!collection.sort()) { + LogError("Cannot make chain of certificates"); + // What to do if chain cannot be build? + return false; + } + + if (collection.isChain()) { + LogDebug("Build chain succeed, size: " << collection.size()); + } else { + LogError("Building chain failed"); + return false; + } + + certs_list = collection.getCertificateList(); + + return true; +} + +bool Certs::ocsp_build_chain (const ValidationCore::CertificateList &certs_list, CKM::CertificateShPtrVector &vect_ckm_chain) +{ + CKM::CertificateShPtrVector vect_untrusted; + + bool first = true; + CKM::CertificateShPtr cert_end_entity; + LogDebug("Size of certs_list: " << certs_list.size()); + for (auto &iter : certs_list) { + std::string cert_cp(iter->getBase64()); + CKM::RawBuffer buff(cert_cp.begin(), cert_cp.end()); + CKM::CertificateShPtr cert = CKM::Certificate::create(buff, CKM::DataFormat::FORM_DER_BASE64); + + if (!cert) { + LogDebug("CKM failed to create certificate"); + return false; + } + else if (first) { + cert_end_entity = cert; + first = false; + LogDebug("Found end entity certificate"); + } + else { + vect_untrusted.push_back(cert); + LogDebug("Found untrusted certificate"); + } + } + + int ret = m_ckm->getCertificateChain( + cert_end_entity, + vect_untrusted, + CKM::CertificateShPtrVector(), + true, // useTrustedSystemCertificates + vect_ckm_chain); + if (ret != CKM_API_SUCCESS) { + LogError("CKM getCertificateChain returned: " << ret); + // TODO: Add handling for different errors codes? + return false; + } + + return true; +} + +Certs::ocsp_response_t Certs::check_ocsp_chain (const chain_t &chain) +{ + ValidationCore::CertificateList certs_list; + if (!ocsp_create_list(chain, certs_list)) { + LogError("Error while build list of certificates"); + return Certs::ocsp_response_t::OCSP_CERT_ERROR; + } + + CKM::CertificateShPtrVector vect_ckm_chain; + + if (!ocsp_build_chain(certs_list, vect_ckm_chain)) { + LogError("Error while build chain of certificates"); + return Certs::ocsp_response_t::OCSP_CERT_ERROR; + } + + int status; + int ret = m_ckm->ocspCheck(vect_ckm_chain, status); + if (ret != CKM_API_SUCCESS) { + LogError("CKM ckeck OCSP returned " << ret); + // Add handling for different errors codes + // For these we can try to check ocsp again later: + switch (ret) { + case CKM_API_ERROR_SOCKET: + case CKM_API_ERROR_BAD_REQUEST: + case CKM_API_ERROR_BAD_RESPONSE: + case CKM_API_ERROR_SEND_FAILED: + case CKM_API_ERROR_RECV_FAILED: + case CKM_API_ERROR_SERVER_ERROR: + case CKM_API_ERROR_OUT_OF_MEMORY: + return Certs::ocsp_response_t::OCSP_CHECK_AGAIN; + // Any other error should be recurrent - checking the same app again + // should give the same result. + default: + return Certs::ocsp_response_t::OCSP_CERT_ERROR; + } + } + + LogDebug("OCSP status: " << status); + switch (status) { + // Remove app from "to-check" list: + case CKM_API_OCSP_STATUS_GOOD: + return Certs::ocsp_response_t::OCSP_APP_OK; + case CKM_API_OCSP_STATUS_UNSUPPORTED: + case CKM_API_OCSP_STATUS_UNKNOWN: + case CKM_API_OCSP_STATUS_INVALID_URL: + return Certs::ocsp_response_t::OCSP_CERT_ERROR; + + //Show popup to user and remove app from "to-check" list + case CKM_API_OCSP_STATUS_REVOKED: + return Certs::ocsp_response_t::OCSP_APP_REVOKED; + + //Keep app for checking it again later: + case CKM_API_OCSP_STATUS_NET_ERROR: + case CKM_API_OCSP_STATUS_INVALID_RESPONSE: + case CKM_API_OCSP_STATUS_REMOTE_ERROR: + case CKM_API_OCSP_STATUS_INTERNAL_ERROR: + return Certs::ocsp_response_t::OCSP_CHECK_AGAIN; + + default: + // This should never happen + return Certs::ocsp_response_t::OCSP_CERT_ERROR; + } +} + +Certs::ocsp_response_t Certs::check_ocsp (const app_t &app) +{ + bool check_again = false; + + for (auto &iter : app.signatures) { + Certs::ocsp_response_t resp = check_ocsp_chain(iter); + if (resp == Certs::ocsp_response_t::OCSP_APP_REVOKED) + return Certs::ocsp_response_t::OCSP_APP_REVOKED; + if (resp == Certs::ocsp_response_t::OCSP_CHECK_AGAIN) + check_again = true; + } + + if (check_again) + return Certs::ocsp_response_t::OCSP_CHECK_AGAIN; + return Certs::ocsp_response_t::OCSP_APP_OK; +} + } // CCHECKER diff --git a/src/include/cchecker/certs.h b/src/include/cchecker/certs.h index ed8efe0..7da95e6 100644 --- a/src/include/cchecker/certs.h +++ b/src/include/cchecker/certs.h @@ -25,19 +25,36 @@ #ifndef CCHECKER_CERTS_H #define CCHECKER_CERTS_H +#include <ckm/ckm-certificate.h> +#include <vcore/Certificate.h> + #include <cchecker/app.h> +#include <ckm/ckm-manager.h> namespace CCHECKER { class Certs { public: - Certs(); - virtual ~Certs(); - void get_certificates (app_t &app, ocsp_urls_t &ocsp_urls); - private: - void find_app_signatures (app_t &app, const std::string &app_path, ocsp_urls_t &ocsp_urls); - void search_app (app_t &app, ocsp_urls_t &ocsp_urls); - + enum class ocsp_response_t { + OCSP_APP_OK, + OCSP_APP_REVOKED, + OCSP_CHECK_AGAIN, + OCSP_CERT_ERROR + }; + Certs(); + virtual ~Certs(); + void get_certificates (app_t &app, ocsp_urls_t &ocsp_urls); + ocsp_response_t check_ocsp (const app_t &app); // TODO: add custom url support + protected: // Needed for tests + ocsp_response_t check_ocsp_chain (const chain_t &chain); + void find_app_signatures (app_t &app, const std::string &app_path, ocsp_urls_t &ocsp_urls); + void search_app (app_t &app, ocsp_urls_t &ocsp_urls); + bool ocsp_create_list(const chain_t &chain, ValidationCore::CertificateList &certs_list); + bool ocsp_build_chain (const ValidationCore::CertificateList &certs_list, + CKM::CertificateShPtrVector &vect_ckm_chain); + + //private: + CKM::ManagerShPtr m_ckm; }; } // CCHECKER diff --git a/src/include/cchecker/logic.h b/src/include/cchecker/logic.h index d698437..8627c1d 100644 --- a/src/include/cchecker/logic.h +++ b/src/include/cchecker/logic.h @@ -80,13 +80,9 @@ class Logic { error_t setup_db(); void load_database_to_buffer(); - void check_ocsp(app_t &app); void add_ocsp_url(const std::string &issuer, const std::string &url, int64_t date); - void pkgmanager_uninstall(const app_t &app); - void get_certs_from_signature(const std::string &signature, std::vector<std::string> &cert); - void add_app_to_buffer_and_database(const app_t &app); - void remove_app_from_buffer(const app_t &app); + void remove_app_from_buffer_and_database(const app_t &app); void pkgmgr_callback_internal(GVariant *parameters, pkgmgr_event_t event); error_t register_dbus_signal_handler(GDBusProxy *proxy, diff --git a/src/logic.cpp b/src/logic.cpp index 445c266..e919e5f 100644 --- a/src/logic.cpp +++ b/src/logic.cpp @@ -317,27 +317,11 @@ void Logic::connman_callback(GDBusProxy */*proxy*/, } } -void Logic::check_ocsp(app_t &app) -{ - (void)app; -} - void Logic::add_ocsp_url(const string &issuer, const string &url, int64_t date) { m_sqlquery->set_url(issuer, url, date); } -void Logic::pkgmanager_uninstall(const app_t &app) -{ - (void)app; -} - -void Logic::get_certs_from_signature(const string &signature, vector<string> &cert) -{ - (void)signature; - (void)cert; -} - void Logic::load_database_to_buffer() { LogDebug("Loading database to the buffer"); @@ -357,8 +341,32 @@ void Logic::process_queue(void) error_t Logic::process_buffer(void) { - for(auto iter = m_buffer.begin(); iter != m_buffer.end(); iter++) { - // TODO: Implement checking OCSP + for (auto iter = m_buffer.begin(); iter != m_buffer.end();) { + // If OCSP checking fails we should remove application from buffer and database + Certs::ocsp_response_t ret; + ret = m_certs.check_ocsp(*iter); + if (ret == Certs::ocsp_response_t::OCSP_APP_OK || + ret == Certs::ocsp_response_t::OCSP_CERT_ERROR) { + LogDebug(iter->str() << " OCSP verified (or not available for app's chains)"); + app_t app_cpy = *iter; + iter++; + remove_app_from_buffer_and_database(app_cpy); + } + else if (ret == Certs::ocsp_response_t::OCSP_APP_REVOKED) { + LogDebug(iter->str() << " certificate has been revoked. Popup should be shown"); + app_t app_cpy = *iter; + iter++; + // TODO: Do not remove app here - just waits for user answer from popup + // Temporary solution because popup doesn't work + remove_app_from_buffer_and_database(app_cpy); + + } + else { + LogDebug(iter->str() << " should be checked again later"); + // If check_ocsp returns Certs::ocsp_response_t::OCSP_CHECK_AGAIN + // app should be checked again later + iter++; + } } return NO_ERROR; } @@ -409,8 +417,7 @@ void Logic::process_event(const event_t &event) } } else if (event.event_type == event_t::event_type_t::APP_UNINSTALL) { - remove_app_from_buffer(event.app); - m_sqlquery->remove_app_from_check_list(event.app); + remove_app_from_buffer_and_database(event.app); } else LogError("Unknown event type"); @@ -428,21 +435,23 @@ void Logic::add_app_to_buffer_and_database(const app_t &app) m_buffer.push_back(app); } -void Logic::remove_app_from_buffer(const app_t &app) +// Notice that this operator doesn't compare list of certificate, because it isn't needed here. +// This operator is implemented only for using in m_buffer.remove() method; +// Operator which compares certificates is implemented in tests. +bool operator ==(const app_t &app1, const app_t &app2) +{ + return app1.app_id == app2.app_id && + app1.pkg_id == app2.pkg_id && + app1.uid == app2.uid; +} + +void Logic::remove_app_from_buffer_and_database(const app_t &app) { // First remove app from DB m_sqlquery->remove_app_from_check_list(app); // Then remove app from buffer - for (auto iter = m_buffer.begin(); iter != m_buffer.end(); ++iter) { - if (iter->app_id == app.app_id && - iter->pkg_id == app.pkg_id && - iter->uid == app.uid) { - LogDebug(iter->str() << " found in buffer - will be removed"); - m_buffer.erase(iter); - break; - } - } + m_buffer.remove(app); } bool Logic::get_should_exit(void) const |