Implement task to check "tizen:setting"
authorJihoon Chung <jihoon.chung@samsaung.com>
Sun, 14 Jul 2013 11:15:14 +0000 (20:15 +0900)
committerJihoon Chung <jihoon.chung@samsaung.com>
Sun, 21 Jul 2013 09:45:24 +0000 (18:45 +0900)
[Issue#] N/A
[Problem] Current wrt-installer only checks "tizen:privilege" level,
even manifest received many requirement of sensitive "tizen:setting"
[Cause] N/A
[Solution] Implement task "task_certify_level"
To avoid sensitive manifest setting is used by untrust application,
installer needs to check privilege level of application. This commit
doesn't use global, static and member value intentionally
to reduce attack.
[SCMRequest] N/A

Change-Id: Icb63c2ad3b02a57c90d39f729db159a84576f348

configuration/widgets.tizen.xsd
src/CMakeLists.txt
src/jobs/widget_install/job_widget_install.cpp
src/jobs/widget_install/task_certify_level.cpp [new file with mode: 0644]
src/jobs/widget_install/task_certify_level.h [new file with mode: 0644]
src/jobs/widget_install/widget_install_context.h

index 0d8233a..5a99dc3 100644 (file)
         </xs:restriction>
     </xs:simpleType>
 
+    <xs:simpleType name="soundmodeType">
+        <xs:restriction base="xs:token">
+            <xs:enumeration value="shared"/>
+            <xs:enumeration value="exclusive"/>
+        </xs:restriction>
+    </xs:simpleType>
+
     <xs:simpleType name="appWidgetIdType">
         <xs:restriction base="xs:string">
             <xs:pattern value="[0-9a-zA-Z]{10}.[0-9a-zA-Z]{1,52}.[0-9a-zA-Z]{1,}"/>
@@ -78,6 +85,7 @@
             <xs:attribute name="backbutton-persence" type="tizen:data.boolean" use="optional"/>
             <xs:attribute name="user-agent" use="optional"/>
             <xs:attribute name="hwkey-event" type="tizen:activationType" use="optional"/> <!-- default: true -->
+            <xs:attribute name="sound-mode" type="tizen:soundmodeType" use="optional"/> <!-- default: shared -->
         </xs:complexType>
     </xs:element>
 
index d842af9..93a2431 100644 (file)
@@ -70,6 +70,7 @@ SET(INSTALLER_SOURCES
     ${INSTALLER_JOBS}/widget_install/task_ace_check.cpp
     ${INSTALLER_JOBS}/widget_install/task_manifest_file.cpp
     ${INSTALLER_JOBS}/widget_install/task_certify.cpp
+    ${INSTALLER_JOBS}/widget_install/task_certify_level.cpp
     ${INSTALLER_JOBS}/widget_install/task_prepare_files.cpp
     ${INSTALLER_JOBS}/widget_install/task_recovery.cpp
     ${INSTALLER_JOBS}/widget_install/task_install_ospsvc.cpp
index 3b45ff2..12a7d7a 100644 (file)
@@ -55,6 +55,7 @@
 #include "parser_runner.h"
 #include <widget_install/job_widget_install.h>
 #include <widget_install/task_certify.h>
+#include <widget_install/task_certify_level.h>
 #include <widget_install/task_widget_config.h>
 #include <widget_install/task_file_manipulation.h>
 #include <widget_install/task_ace_check.h>
@@ -190,7 +191,7 @@ JobWidgetInstall::JobWidgetInstall(
         if (m_needEncryption) {
             AddTask(new TaskEncryptResource(m_installerContext));
         }
-
+        AddTask(new TaskCertifyLevel(m_installerContext));
         AddTask(new TaskFileManipulation(m_installerContext));
         AddTask(new TaskManifestFile(m_installerContext));
         if (m_installerContext.widgetConfig.packagingType ==
@@ -225,7 +226,7 @@ JobWidgetInstall::JobWidgetInstall(
         if (m_needEncryption) {
             AddTask(new TaskEncryptResource(m_installerContext));
         }
-
+        AddTask(new TaskCertifyLevel(m_installerContext));
         if (m_installerContext.mode.extension !=
                 InstallMode::ExtensionType::DIR) {
             AddTask(new TaskUpdateFiles(m_installerContext));
diff --git a/src/jobs/widget_install/task_certify_level.cpp b/src/jobs/widget_install/task_certify_level.cpp
new file mode 100644 (file)
index 0000000..6c77ccf
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2013 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    task_certify.cpp
+ * @author  Jihoon Chung (jihoon.chung@samgsung.com)
+ * @version
+ * @brief
+ */
+
+//SYSTEM INCLUDES
+#include <string>
+#include <map>
+#include <unistd.h>
+
+//WRT INCLUDES
+#include <widget_install/task_certify_level.h>
+#include <widget_install/job_widget_install.h>
+#include <widget_install/widget_install_errors.h>
+#include <widget_install/widget_install_context.h>
+#include <dpl/assert.h>
+#include <dpl/log/log.h>
+#include <dpl/exception.h>
+#include <dpl/string.h>
+#include <dpl/foreach.h>
+#include <dpl/wrt-dao-ro/global_config.h>
+
+#include <vcore/CertStoreType.h>
+#include <vcore/SignatureReader.h>
+#include <vcore/SignatureFinder.h>
+#include <vcore/WrtSignatureValidator.h>
+#include <dpl/utils/wrt_global_settings.h>
+#include <dpl/wrt-dao-ro/global_dao_read_only.h>
+
+using namespace ValidationCore;
+using namespace WrtDB;
+
+namespace Jobs {
+namespace WidgetInstall {
+TaskCertifyLevel::TaskCertifyLevel(InstallerContext &inCont) :
+    DPL::TaskDecl<TaskCertifyLevel>(this),
+    m_contextData(inCont)
+{
+    AddStep(&TaskCertifyLevel::stepCertifyLevel);
+}
+
+void TaskCertifyLevel::stepCertifyLevel()
+{
+    LogDebug("================ Step: <<Certify Level>> ENTER ===============");
+    if (!checkSettingLevel(getCertifyLevel())) {
+        ThrowMsg(Exceptions::PrivilegeLevelViolation, "setting level violate");
+    }
+    LogDebug("================ Step: <<Certify Level>> DONE ================");
+
+    m_contextData.job->UpdateProgress(
+        InstallerContext::INSTALL_CERTIFY_LEVEL_CHECK,
+        "Application Certificate level check Finished");
+}
+
+void TaskCertifyLevel::getSignatureFiles(const std::string& path,
+                                         SignatureFileInfoSet& file)
+{
+    SignatureFileInfoSet signatureFiles;
+    SignatureFinder signatureFinder(path);
+    if (SignatureFinder::NO_ERROR != signatureFinder.find(file)) {
+        LogError("Error in Signature Finder : " << path);
+        ThrowMsg(Exceptions::SignatureNotFound, "Signature not found");
+    }
+}
+
+TaskCertifyLevel::Level TaskCertifyLevel::getCertifyLevel()
+{
+    std::string widgetPath;
+    widgetPath = m_contextData.locations->getTemporaryPackageDir() + "/";
+
+    if (m_contextData.mode.command == InstallMode::Command::REINSTALL) {
+        widgetPath =
+            m_contextData.locations->getPackageInstallationDir() + "/";
+    }
+
+    SignatureFileInfoSet signatureFiles;
+
+    Try {
+        getSignatureFiles(widgetPath, signatureFiles);
+
+        if (signatureFiles.size() <= 0) {
+            widgetPath += std::string(WrtDB::GlobalConfig::GetWidgetSrcPath())
+                + "/";
+            if (0 == access(widgetPath.c_str(), F_OK)) {
+                getSignatureFiles(widgetPath, signatureFiles);
+            }
+        }
+    } Catch(Exceptions::SignatureNotFound) {
+        ReThrowMsg(Exceptions::SignatureNotFound, widgetPath);
+    }
+
+    SignatureFileInfoSet::reverse_iterator iter = signatureFiles.rbegin();
+    LogDebug("Number of signatures: " << signatureFiles.size());
+
+    Level level = Level::UNKNOWN;
+    for (; iter != signatureFiles.rend(); ++iter) {
+        LogDebug("Checking signature with id=" << iter->getFileNumber());
+        SignatureData data(widgetPath + iter->getFileName(),
+                           iter->getFileNumber());
+
+        Try {
+            SignatureReader xml;
+            xml.initialize(data, GlobalConfig::GetSignatureXmlSchema());
+            xml.read(data);
+
+            WrtSignatureValidator validator(
+                    WrtSignatureValidator::TIZEN,
+                    !GlobalSettings::
+                    OCSPTestModeEnabled(),
+                    !GlobalSettings::
+                    CrlTestModeEnabled(),
+                    false);
+
+            WrtSignatureValidator::Result result =
+                validator.check(data, widgetPath);
+
+            if (m_contextData.mode.installTime
+                ==  InstallMode::InstallTime::PRELOAD)
+            {
+                result = WrtSignatureValidator::SIGNATURE_VERIFIED;
+            }
+
+            if (result == WrtSignatureValidator::SIGNATURE_REVOKED) {
+                ThrowMsg(Exceptions::CertificateExpired,
+                         "Certificate is REVOKED");
+            }
+
+            if (result == WrtSignatureValidator::SIGNATURE_INVALID &&
+                    iter->getFileNumber() <= 1)
+            {
+                ThrowMsg(Exceptions::SignatureInvalid, "Invalid Package");
+            }
+
+            if (data.isAuthorSignature()) {
+                LogDebug("Skip author signature");
+            } else {
+                Level currentCertLevel =
+                    certTypeToLevel(data.getVisibilityLevel());
+                if (currentCertLevel == Level::UNKNOWN) {
+                    continue;
+                }
+                if (currentCertLevel > level) {
+                    level = currentCertLevel;
+                    LogDebug("level " << enumToString(level));
+                }
+            }
+        } Catch(ParserSchemaException::Base) {
+            LogError("Error occured in ParserSchema.");
+            ReThrowMsg(Exceptions::SignatureInvalid,
+                       "Error occured in ParserSchema.");
+        }
+    }
+
+    return level;
+}
+
+bool TaskCertifyLevel::checkSettingLevel(
+    TaskCertifyLevel::Level level)
+{
+    secureSettingMap data = {
+        {"sound-mode", Level::PARTNER}
+    };
+
+    FOREACH(it, m_contextData.widgetConfig.configInfo.settingsList) {
+        secureSettingIter ret = data.find(DPL::ToUTF8String(it->m_name));
+        if (ret != data.end()) {
+            if (level < ret->second) {
+                LogError("\"" <<
+                         it->m_name <<
+                         "\" needs \"" <<
+                         enumToString(ret->second) <<
+                         "\" level");
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+std::string TaskCertifyLevel::enumToString(
+    TaskCertifyLevel::Level level)
+{
+    switch (level) {
+#define X(x, y) case x: return #y;
+        X(Level::UNKNOWN, UNKNOWN)
+        X(Level::PUBLIC, PUBLIC)
+        X(Level::PARTNER, PARTNER)
+        X(Level::PLATFORM, PLATFORM)
+#undef X
+    default:
+        return "UNKNOWN";
+    }
+}
+
+TaskCertifyLevel::Level TaskCertifyLevel::certTypeToLevel(
+    CertStoreId::Type type)
+{
+    // CertStoreType.h (framework/security/cert-svc)
+    // RootCA's visibility level : public
+    // const Type VIS_PUBLIC = 1 << 6;
+    // RootCA's visibility level : partner
+    // const Type VIS_PARTNER = 1 << 7;
+    // RootCA's visibility level : platform
+    // const Type VIS_PLATFORM = 1 << 10;
+    if (type == CertStoreId::VIS_PUBLIC) {
+        return Level::PUBLIC;
+    } else if (type == CertStoreId::VIS_PARTNER) {
+        return Level::PARTNER;
+    } else if (type == CertStoreId::VIS_PLATFORM) {
+        return Level::PLATFORM;
+    }
+    return Level::UNKNOWN;
+}
+
+} //namespace WidgetInstall
+} //namespace Jobs
+
diff --git a/src/jobs/widget_install/task_certify_level.h b/src/jobs/widget_install/task_certify_level.h
new file mode 100644 (file)
index 0000000..ae8ce40
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013 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    task_certify_level.h
+ * @author  Jihoon Chung (jihoon.chung@samgsung.com)
+ * @version
+ * @brief
+ */
+#ifndef INSTALLER_CORE_JOS_WIDGET_INSTALL_TASK_CERTIFY_LEVEL_H
+#define INSTALLER_CORE_JOS_WIDGET_INSTALL_TASK_CERTIFY_LEVEL_H
+
+//SYSTEM INCLUDES
+#include <string>
+#include <cstdint>
+#include <map>
+
+//WRT INCLUDES
+#include <vcore/CertStoreType.h>
+#include <vcore/SignatureFinder.h>
+#include <dpl/task.h>
+
+class InstallerContext;
+
+namespace Jobs {
+namespace WidgetInstall {
+class TaskCertifyLevel :
+    public DPL::TaskDecl<TaskCertifyLevel>
+{
+  public:
+    TaskCertifyLevel(InstallerContext &inCont);
+
+  private:
+    //data
+    InstallerContext& m_contextData;
+
+    enum class Level : std::int8_t {
+        UNKNOWN  = 0,
+        PUBLIC   = 1,
+        PARTNER  = 2,
+        PLATFORM = 3
+    };
+    typedef std::map<std::string, Level> secureSettingMap;
+    typedef std::map<std::string, Level>::iterator secureSettingIter;
+
+    //steps
+    void stepCertifyLevel();
+
+    //util
+    void getSignatureFiles(const std::string& path,
+                           ValidationCore::SignatureFileInfoSet& file);
+    Level getCertifyLevel();
+    bool checkSettingLevel(Level level);
+    std::string enumToString(Level level);
+    Level certTypeToLevel(ValidationCore::CertStoreId::Type type);
+
+};
+} //namespace WidgetInstall
+} //namespace Jobs
+
+#endif // INSTALLER_CORE_JOS_WIDGET_INSTALL_TASK_CERTIFY_LEVEL_H
index 0317c0d..649de9b 100644 (file)
@@ -56,6 +56,7 @@ struct InstallerContext
         INSTALL_WIDGET_CONFIG2,
         INSTALL_DIGSIG_CHECK,
         INSTALL_CERT_CHECK,
+        INSTALL_CERTIFY_LEVEL_CHECK,
         INSTALL_ECRYPTION_FILES,
         INSTALL_CREATE_BACKUP_DIR,                     /* For Update */
         INSTALL_DIR_CREATE,