Implement certificate verification inside agent 06/129706/7
authorBartlomiej Grzelewski <b.grzelewski@samsung.com>
Wed, 17 May 2017 16:23:17 +0000 (18:23 +0200)
committerBartlomiej Grzelewski <b.grzelewski@samsung.com>
Tue, 30 May 2017 10:48:43 +0000 (12:48 +0200)
* Read certificate in PEM and DER format

Change-Id: Iccfa3778a8e8c3d07a258622c4985fea67a6095a

packaging/security-manager.spec
src/license-manager/agent/CMakeLists.txt
src/license-manager/agent/agent_logic.cpp
src/license-manager/agent/main.cpp

index 5263bdd..69edaf0 100644 (file)
@@ -32,6 +32,7 @@ BuildRequires: pkgconfig(db-util)
 BuildRequires: pkgconfig(cynara-admin)
 BuildRequires: pkgconfig(cynara-client-async)
 BuildRequires: pkgconfig(security-privilege-manager)
+BuildRequires: pkgconfig(openssl)
 BuildRequires: boost-devel
 %{?systemd_requires}
 
index 3368bc9..660f719 100644 (file)
@@ -23,6 +23,7 @@ PKG_CHECK_MODULES(AGENT_DEP
     REQUIRED
     cynara-agent
     libsystemd
+    openssl
     )
 
 SET(AGENT_SOURCES
index 18988c6..eb96d32 100644 (file)
  * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
  * @brief       This is the place where verification should take place
  */
+#include <fstream>
 #include <sstream>
 #include <string>
+#include <memory>
 
 #include <alog.h>
 
 #include <agent_logic.h>
 #include <app-runtime.h>
 
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/pem.h>
+
 namespace LicenseManager {
 
-std::string AgentLogic::process(const std::string &data) {
-    std::stringstream ss(data);
-    std::string smack, privilege;
-    int uid;
-    ss >> smack >> uid >> privilege;
-    char *pkgId = nullptr, *appId = nullptr, *licensePath = nullptr;
+typedef std::unique_ptr<char, decltype(free)*> CString;
+typedef std::unique_ptr<X509, decltype(X509_free)*> CertPtr;
+typedef std::unique_ptr<X509_STORE, decltype(X509_STORE_free)*> StorePtr;
+typedef std::unique_ptr<X509_STORE_CTX, decltype(X509_STORE_CTX_free)*> StoreCtxPtr;
+
+CertPtr readCertificate(const char *path) {
+    std::ifstream input(path);
+    std::stringstream ss;
+    ss << input.rdbuf();
+    auto data = ss.str();
+    auto ptr = reinterpret_cast<const unsigned char *>(data.data());
+    auto size = static_cast<int>(data.size());
+    X509 *cert = d2i_X509(nullptr, &ptr, size);
+    if (cert)
+        return CertPtr(cert, X509_free);
 
-    security_manager_get_app_defined_privilege_provider(
+    FILE *file = NULL;
+    file = fopen(path, "r");
+    if (file) {
+        cert = PEM_read_X509(file, NULL, NULL, NULL);
+        fclose(file);
+    }
+    return CertPtr(cert, X509_free);
+}
+
+int verify(const std::string &smack, int uid, const std::string &privilege) {
+    char *providerPkgId = nullptr, *providerAppId = nullptr;
+    char *clientAppId = nullptr, *clientPkgId = nullptr;
+    char *providerLicensePath = nullptr;
+    char *clientLicensePath = nullptr;
+    int status = -1; // error
+
+    if (SECURITY_MANAGER_SUCCESS != security_manager_get_app_defined_privilege_provider(
             privilege.c_str(),
             uid,
-            &pkgId,
-            &appId);
+            &providerPkgId,
+            &providerAppId))
+    {
+        ALOGD("Error in security_manager_get_app_defined_privilege_provider");
+        return -1;
+    }
+    CString pPI(providerPkgId, free);
+    CString pAI(providerAppId, free);
+
+    if (SECURITY_MANAGER_SUCCESS != security_manager_get_app_defined_privilege_license(
+            privilege.c_str(),
+            uid,
+            &providerLicensePath))
+    {
+        ALOGD("Error in security_manager_get_app_defined_privilege_license");
+        return -1;
+    }
+    CString pLP(providerLicensePath, free);
+
+    if (SECURITY_MANAGER_SUCCESS != security_manager_identify_app_from_cynara_client(
+            smack.c_str(),
+            &clientPkgId,
+            &clientAppId))
+    {
+        ALOGD("Error in security_manager_identify_app_from_cynara_client");
+        return -1;
+    }
+    CString cAI(clientAppId, free);
+    CString cPI(clientPkgId, free);
 
-    security_manager_get_app_defined_privilege_license(
+    if (SECURITY_MANAGER_SUCCESS != security_manager_get_client_privilege_license(
             privilege.c_str(),
+            clientAppId,
             uid,
-            &licensePath);
+            &clientLicensePath))
+    {
+        ALOGD("Error in security_manager_get_client_privilege_license");
+        return -1;
+    }
+    CString cLP(clientLicensePath, free);
+
+    auto providerCert = readCertificate(providerLicensePath);
+    auto clientCert = readCertificate(clientLicensePath);
+
+    if (!providerCert) {
+        ALOGD("Error reading provider certificate");
+        return -1;
+    }
+
+    if (!clientCert) {
+        ALOGD("Error reading client certificates!");
+        return -1;
+    }
+
+    StorePtr store(X509_STORE_new(), X509_STORE_free);
+    StoreCtxPtr storeCtx(X509_STORE_CTX_new(), X509_STORE_CTX_free);
+
+    if (1 != X509_STORE_add_cert(store.get(), providerCert.get())) {
+        ALOGD("X509_STORE_add_cert failed");
+    } else if (0 == X509_STORE_CTX_init(storeCtx.get(), store.get(), clientCert.get(), nullptr)) { // check this nullptr
+        ALOGD("X509_STORE_CTX_init failed");
+    } else {
+        X509_VERIFY_PARAM_set_flags(storeCtx->param, X509_V_FLAG_X509_STRICT);
+        status = X509_verify_cert(storeCtx.get()); // 1 == ok; 0 == fail; -1 == error
+    }
+
+    ALOGD("App: %s Uid: %d Privilege: %s", smack.c_str(), uid, privilege.c_str());
+    ALOGD("Privilege: %s is Provided by: %s/%s", privilege.c_str(), providerAppId, providerPkgId);
+    ALOGD("Certificate paths client: %s provider: %s", clientLicensePath, providerLicensePath);
+    ALOGD("Verification status (1 means good, 0 means fail, -1 means error): %d", status);
+    return status;
+}
+
+std::string AgentLogic::process(const std::string &data) {
+    std::stringstream ss(data);
+    std::string smack, privilege;
+    int uid;
+    ss >> smack >> uid >> privilege;
 
-    ALOGD("App: %s Uid: %d Priv: %s", smack.c_str(), uid, privilege.c_str());
-    ALOGD("Privilege: %s is Provided by: %s/%s", privilege.c_str(), appId, pkgId);
-    free(pkgId);
-    free(appId);
-    free(licensePath);
+    int status = verify(smack, uid, privilege);
+    status = (status == 1) ? 1 : 0;
 
     std::stringstream out;
-    out << 1;
+    out << status;
     return out.str();
 }
 
index cea01d8..73d7a50 100644 (file)
 #include <exception>
 
 #include <systemd/sd-daemon.h>
+#include <openssl/evp.h>
+#include <openssl/ssl.h>
+#include <openssl/conf.h>
+#include <openssl/err.h>
 
 #include <alog.h>
 #include <agent_logic.h>
@@ -51,7 +55,13 @@ int main(int, char **) {
         return EXIT_FAILURE;
     }
 
+    OpenSSL_add_all_algorithms();
+    SSL_library_init();
+    OPENSSL_config(NULL);
+    SSL_load_error_strings();
+
     try {
+
         LicenseManager::AgentLogic *logic = new LicenseManager::AgentLogic;
         LicenseManager::Agent agent;
         if (!agent.initialize(logic)) {
@@ -72,6 +82,11 @@ int main(int, char **) {
         ALOGE("Exception: %s", error.c_str());
     }
 
+    CONF_modules_free();
+    EVP_cleanup();
+    ERR_free_strings();
+    CRYPTO_cleanup_all_ex_data();
+
     return 0;
 }