summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJanusz Kozerski <j.kozerski@samsung.com>2015-07-03 14:26:44 +0200
committerJanusz Kozerski <j.kozerski@samsung.com>2015-07-17 14:33:45 +0200
commitecacacfce9dc0f97fc67ba032726583b8881ed97 (patch)
treeb8710bbd27d939524bf26bb802056d6736c85f8a /src
parent1bf0726b3028ddfaae0cdd70e46b416335da39a0 (diff)
downloadcert-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.txt1
-rw-r--r--src/certs.cpp178
-rw-r--r--src/include/cchecker/certs.h31
-rw-r--r--src/include/cchecker/logic.h6
-rw-r--r--src/logic.cpp69
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