[C++ API +] Add proxy mode on SignatureValidator 81/90081/13
authorsangwan.kwon <sangwan.kwon@samsung.com>
Fri, 23 Sep 2016 00:49:58 +0000 (09:49 +0900)
committersangwan.kwon <sangwan.kwon@samsung.com>
Thu, 10 Nov 2016 08:10:16 +0000 (17:10 +0900)
* Purpose : Improve signature validation performance.
* Key-idea : Reference validation should be done only once
             on multiple-signatures during signature validation.

[Added C++ API]
- SignatureValidator::checkAll(bool checkOcsp,
                               bool checkReferences,
                               SignatureDataList &sigDataSet)
- SignatureValidator::checkListAll(bool checkOcsp,
                                   const UriList &uriList,
                                   SignatureDataList &sigDataSet)

Change-Id: I6abba2100fecd5fe779f0e7cdd977b6281f74d9c
Signed-off-by: sangwan.kwon <sangwan.kwon@samsung.com>
src/vcore/BaseValidator.cpp
src/vcore/BaseValidator.h
src/vcore/SignatureData.h
src/vcore/SignatureFinder.h
src/vcore/SignatureValidator.cpp
src/vcore/SignatureValidator.h
src/vcore/XmlsecAdapter.cpp
src/vcore/XmlsecAdapter.h
tests/vcore/test-signature-validator.cpp

index 6917a6d..1c7ac68 100644 (file)
@@ -81,8 +81,14 @@ inline bool _isTimeStrict(const Set &stores)
 namespace ValidationCore {
 
 BaseValidator::BaseValidator(const SignatureFileInfo &info) :
-       m_fileInfo(info),
-       m_disregarded(false)
+       m_disregarded(false),
+       m_fileInfo(info)
+{
+}
+
+BaseValidator::BaseValidator(const std::string &packagePath) :
+       m_disregarded(false),
+       m_packagePath(packagePath)
 {
 }
 
@@ -171,7 +177,7 @@ VCerr BaseValidator::parseSignature(void)
  */
 VCerr BaseValidator::makeDataBySignature(bool completeWithSystemCert)
 {
-       LogDebug("Start to make chain.");
+       LogDebug("Start to make chain about > " << m_fileInfo.getFileName());
        m_data = SignatureData(m_fileInfo.getFileName(), m_fileInfo.getFileNumber());
 
        if (parseSignature()) {
index 41e83e1..2a084a7 100644 (file)
@@ -39,8 +39,9 @@ using UriList = std::list<std::string>;
 
 class BaseValidator {
 public:
-       BaseValidator(const SignatureFileInfo &info);
-       virtual ~BaseValidator() {};
+       explicit BaseValidator(const SignatureFileInfo &info);
+       explicit BaseValidator(const std::string &packagePath);
+       virtual ~BaseValidator() {}
 
        VCerr makeChainBySignature(bool completeWithSystemCert,
                                                           CertificateList &certList);
@@ -54,6 +55,11 @@ protected:
        VCerr additionalCheck(VCerr result);
 
        SignatureData m_data;
+       bool m_disregarded;
+       std::string m_packagePath;
+       SignatureFileInfo m_fileInfo;
+       SignatureFileInfoSet m_fileInfoSet;
+       XmlSec::XmlSecContext m_context;
 
 private:
        VCerr makeDataBySignature(bool completeWithSystemCert);
@@ -65,9 +71,6 @@ private:
        bool checkObjectReferences(void);
 
        PluginHandler m_pluginHandler;
-       SignatureFileInfo m_fileInfo;
-       XmlSec::XmlSecContext m_context;
-       bool m_disregarded;
 };
 
 } // namespace ValidationCore
index 91b5b21..b3677d4 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <list>
 #include <set>
+#include <map>
 #include <string>
 
 #include <vcore/Certificate.h>
 
 namespace ValidationCore {
 
+enum SignatureType {
+       AUTHOR = -1,
+       DISTRIBUTOR1 = 1,
+       DISTRIBUTOR2 = 2
+}; // Distributor type can be increase, do not use enum class.
+
+class SignatureData;
+
 typedef std::set<std::string> ReferenceSet;
+typedef std::set<std::string> ProxySet;
 typedef std::list<std::string> ObjectList;
+typedef std::map<int, SignatureData> SignatureDataMap;
 
 class SignatureData {
 public:
@@ -69,6 +80,7 @@ public:
 
 private:
        ReferenceSet m_referenceSet;
+       ProxySet m_proxySet;
        CertificateList m_certList;
 
        //TargetRestriction
@@ -90,8 +102,6 @@ private:
        bool m_certificateSorted;
 };
 
-typedef std::set<SignatureData> SignatureDataSet;
-
 } // ValidationCore
 
 #endif
index 4fea63a..141a598 100644 (file)
@@ -29,9 +29,13 @@ namespace ValidationCore {
 
 class SignatureFileInfo {
 public:
-       SignatureFileInfo(const std::string &fileName, int num)
-               : m_fileName(fileName)
-               , m_fileNumber(num)
+       SignatureFileInfo() : m_fileName(std::string()), m_fileNumber(-1)
+       {
+       }
+
+       SignatureFileInfo(const std::string &fileName, int num) :
+               m_fileName(fileName),
+               m_fileNumber(num)
        {}
 
        std::string getFileName() const
index 29ef870..87c3672 100644 (file)
 #include <vcore/SignatureValidator.h>
 #include <vcore/BaseValidator.h>
 
+#include <dpl/log/log.h>
+
+#include <utility>
+
 namespace ValidationCore {
 
 class SignatureValidator::Impl : public BaseValidator {
 public:
-       Impl(const SignatureFileInfo &info);
-       virtual ~Impl() {};
+       explicit Impl(const SignatureFileInfo &info);
+       explicit Impl(const std::string &packagePath);
+       virtual ~Impl() {}
 
        VCerr check(const std::string &contentPath,
                                bool checkOcsp,
@@ -37,6 +42,13 @@ public:
        VCerr checkList(bool checkOcsp,
                                        const UriList &uriList,
                                        SignatureData &outData);
+
+       VCerr checkAll(bool checkOcsp,
+                                  bool checkReferences,
+                                  SignatureDataMap &sigDataMap);
+       VCerr checkListAll(bool checkOcsp,
+                                          const UriList &uriList,
+                                          SignatureDataMap &sigDataMap);
 };
 
 SignatureValidator::Impl::Impl(const SignatureFileInfo &info) :
@@ -44,6 +56,16 @@ SignatureValidator::Impl::Impl(const SignatureFileInfo &info) :
 {
 }
 
+SignatureValidator::Impl::Impl(const std::string &packagePath) :
+       BaseValidator(packagePath)
+{
+       m_context.isProxyMode = true;
+
+       SignatureFinder signatureFinder(m_packagePath);
+       if (SignatureFinder::NO_ERROR != signatureFinder.find(m_fileInfoSet))
+               LogError("Failed to find signature files.");
+}
+
 VCerr SignatureValidator::Impl::check(const std::string &contentPath,
                                                                          bool checkOcsp,
                                                                          bool checkReferences,
@@ -56,10 +78,9 @@ VCerr SignatureValidator::Impl::check(const std::string &contentPath,
        return result;
 }
 
-VCerr SignatureValidator::Impl::checkList(
-       bool checkOcsp,
-       const UriList &uriList,
-       SignatureData &outData)
+VCerr SignatureValidator::Impl::checkList(bool checkOcsp,
+                                                                                 const UriList &uriList,
+                                                                                 SignatureData &outData)
 {
        VCerr result;
        result = baseCheckList(checkOcsp, uriList);
@@ -68,6 +89,60 @@ VCerr SignatureValidator::Impl::checkList(
        return result;
 }
 
+VCerr SignatureValidator::Impl::checkAll(bool checkOcsp,
+                                                                                bool checkReferences,
+                                                                                SignatureDataMap &sigDataMap)
+{
+       if (m_fileInfoSet.size() < 2)
+               return E_SIG_UNKNOWN; // TODO(sangwan.kwon) Add error code (INVALID SIZE)
+
+       VCerr result;
+       for (const auto &sig : m_fileInfoSet) {
+               m_fileInfo = sig;
+               m_disregarded = false;
+
+               result = baseCheck(m_packagePath, checkOcsp, checkReferences);
+               result = additionalCheck(result);
+               if (result != E_SIG_NONE) {
+                       LogError("Failed to check on > " << m_fileInfo.getFileName());
+                       break;
+               }
+               sigDataMap.insert(std::make_pair(m_data.getSignatureNumber(), m_data));
+               LogDebug("Check done signature > " << m_data.getSignatureNumber());
+               for (const auto &certPtr : m_data.getCertList())
+                       LogDebug(certPtr->getBase64());
+       }
+
+       return result;
+}
+
+VCerr SignatureValidator::Impl::checkListAll(bool checkOcsp,
+                                                                                        const UriList &uriList,
+                                                                                        SignatureDataMap &sigDataMap)
+{
+       if (m_fileInfoSet.size() < 2)
+               return E_SIG_UNKNOWN; // TODO(sangwan.kwon) Add error code (INVALID SIZE)
+
+       VCerr result;
+       for (const auto &sig : m_fileInfoSet) {
+               m_fileInfo = sig;
+               m_disregarded = false;
+
+               result = baseCheckList(checkOcsp, uriList);
+               result = additionalCheck(result);
+               if (result != E_SIG_NONE) {
+                       LogError("Failed to check on > " << m_fileInfo.getFileName());
+                       break;
+               }
+               sigDataMap.insert(std::make_pair(m_data.getSignatureNumber(), m_data));
+               LogDebug("CheckList done signature > " << m_data.getSignatureNumber());
+               for (const auto &certPtr : m_data.getCertList())
+                       LogDebug(certPtr->getBase64());
+       }
+
+       return result;
+}
+
 SignatureValidator::SignatureValidator(const SignatureFileInfo &info)
 {
        using SVImpl = SignatureValidator::Impl;
@@ -75,6 +150,13 @@ SignatureValidator::SignatureValidator(const SignatureFileInfo &info)
        m_pImpl = std::move(impl);
 }
 
+SignatureValidator::SignatureValidator(const std::string &packagePath)
+{
+       using SVImpl = SignatureValidator::Impl;
+       std::unique_ptr<SVImpl> impl(new(std::nothrow) SVImpl(packagePath));
+       m_pImpl = std::move(impl);
+}
+
 SignatureValidator::~SignatureValidator() {}
 
 VCerr SignatureValidator::check(const std::string &contentPath,
@@ -98,6 +180,26 @@ VCerr SignatureValidator::checkList(bool checkOcsp,
        return m_pImpl->checkList(checkOcsp, uriList, outData);
 }
 
+VCerr SignatureValidator::checkAll(bool checkOcsp,
+                                                                  bool checkReferences,
+                                                                  SignatureDataMap &sigDataMap)
+{
+       if (!m_pImpl)
+               return E_SIG_OUT_OF_MEM;
+
+       return m_pImpl->checkAll(checkOcsp, checkReferences, sigDataMap);
+}
+
+VCerr SignatureValidator::checkListAll(bool checkOcsp,
+                                                                          const UriList &uriList,
+                                                                          SignatureDataMap &sigDataMap)
+{
+       if (!m_pImpl)
+               return E_SIG_OUT_OF_MEM;
+
+       return m_pImpl->checkListAll(checkOcsp, uriList, sigDataMap);
+}
+
 VCerr SignatureValidator::makeChainBySignature(
        bool completeWithSystemCert,
        CertificateList &certList)
index 6541180..048f7fa 100644 (file)
@@ -26,7 +26,6 @@
 #include <list>
 #include <memory>
 
-#include <vcore/Certificate.h>
 #include <vcore/SignatureData.h>
 #include <vcore/SignatureFinder.h>
 #include <vcore/Error.h>
@@ -64,7 +63,8 @@ using UriList = std::list<std::string>;
  */
 class SignatureValidator {
 public:
-       SignatureValidator(const SignatureFileInfo &info);
+       explicit SignatureValidator(const SignatureFileInfo &info);
+       explicit SignatureValidator(const std::string &packagePath);
        virtual ~SignatureValidator();
 
        SignatureValidator() = delete;
@@ -75,11 +75,17 @@ public:
                                bool checkOcsp,
                                bool checkReferences,
                                SignatureData &outData);
-
        VCerr checkList(bool checkOcsp,
                                        const UriList &uriList,
                                        SignatureData &outData);
 
+       VCerr checkAll(bool checkOcsp,
+                                  bool checkReferences,
+                                  SignatureDataMap &sigDataMap);
+       VCerr checkListAll(bool checkOcsp,
+                                          const UriList &uriList,
+                                          SignatureDataMap &sigDataMap);
+
        /*
         *  @Remarks : cert list isn't completed with self-signed root CA system cert
         *             if completeWithSystemCert is false.
index e870713..2eb1574 100644 (file)
@@ -301,10 +301,27 @@ void XmlSec::validateFile(XmlSecContext &context, xmlSecKeysMngrPtr mngrPtr)
                dsigCtx->keyInfoReadCtx.certsVerificationTime = context.validationTime;
        }
 
+       // Set proxy data to dsigCtx
+       if (context.isProxyMode && !context.proxySet.empty()) {
+               LogDebug("Set proxy data to xmlsec1 handle.");
+               for (auto data : context.proxySet) {
+                       if (!strcmp(data.c_str(), "#prop"))
+                               continue;
+
+                       if(xmlSecProxyCtxAdd(&(dsigCtx.get()->proxyCtxPtr),
+                                                                reinterpret_cast<const xmlChar *>(data.c_str())))
+                               ThrowMsg(Exception::InternalError, "Failed to add proxy data.");
+
+               }
+       }
+
        int res;
 
        switch (m_mode) {
        case ValidateMode::NORMAL: {
+               if (context.isProxyMode)
+                       dsigCtx.get()->flags |= XMLSEC_DSIG_FLAGS_SKIP_PROXY;
+
                res = xmlSecDSigCtxVerify(dsigCtx.get(), node);
                break;
        }
@@ -318,7 +335,7 @@ void XmlSec::validateFile(XmlSecContext &context, xmlSecKeysMngrPtr mngrPtr)
                dsigCtx.get()->flags |= XMLSEC_DSIG_FLAGS_CHECK_PROXY;
                for (auto uri : *m_pList) {
                        if(xmlSecProxyCtxAdd(&(dsigCtx.get()->proxyCtxPtr),
-                                                               reinterpret_cast<const xmlChar *>(uri.c_str())))
+                                                                reinterpret_cast<const xmlChar *>(uri.c_str())))
                                ThrowMsg(Exception::InternalError, "PARTIAL_HASH mode failed.");
                }
                res = xmlSecDSigCtxVerify(dsigCtx.get(), node);
@@ -341,8 +358,12 @@ void XmlSec::validateFile(XmlSecContext &context, xmlSecKeysMngrPtr mngrPtr)
        if (dsigCtx->status != xmlSecDSigStatusSucceeded)
                ThrowMsg(Exception::InvalidSig, "Signature status is not succedded.");
 
-       xmlSecSize refSize = xmlSecPtrListGetSize(&(dsigCtx->signedInfoReferences));
+       // Set references for reverse reference check by ReferenceValidator
+       if (context.isProxyMode)
+               for (auto &proxy : context.proxySet)
+                       context.referenceSet.insert(proxy);
 
+       xmlSecSize refSize = xmlSecPtrListGetSize(&(dsigCtx->signedInfoReferences));
        for (xmlSecSize i = 0; i < refSize; ++i) {
                xmlSecDSigReferenceCtxPtr dsigRefCtx = static_cast<xmlSecDSigReferenceCtxPtr>(
                                xmlSecPtrListGetItem(&(dsigCtx->signedInfoReferences), i));
@@ -362,6 +383,8 @@ void XmlSec::validateFile(XmlSecContext &context, xmlSecKeysMngrPtr mngrPtr)
                }
 
                context.referenceSet.emplace(reinterpret_cast<char *>(dsigRefCtx->uri));
+               if (context.isProxyMode)
+                       context.proxySet.emplace(reinterpret_cast<char *>(dsigRefCtx->uri));
        }
 }
 
index 10573e7..269ebd9 100644 (file)
@@ -50,7 +50,8 @@ public:
                XmlSecContext()
                        : validationTime(0)
                        , allowBrokenChain(false)
-                       , errorBrokenChain(false) {}
+                       , errorBrokenChain(false)
+                       , isProxyMode(false) {}
 
                /*
                 * Absolute path to signature file.
@@ -89,9 +90,20 @@ public:
                bool errorBrokenChain;
                /*
                 * Output parameter.
-                * Reference checked by xmlsec
+                * Reference checked by xmlsec.
                 */
                ReferenceSet referenceSet;
+               /*
+                * Input parameter.
+                * If true, proxy validation mode on and set XMLSEC_DSIG_FLAGS_SKIP_PROXY.
+                */
+               bool isProxyMode;
+               /*
+                * Output parameter.
+                * Reference checked by xmlsec.
+                * Reuse for proxy valdiation.
+                */
+               ProxySet proxySet;
        };
 
        struct Exception {
index cf7c04d..07008f6 100644 (file)
@@ -574,6 +574,65 @@ RUNNER_TEST(T00159_negative_tpk_with_nohash)
        }
 }
 
+RUNNER_TEST(T00160_positive_checkAll)
+{
+       SignatureValidator validator(TestData::widget_path);
+       SignatureDataMap sigDataMap;
+       VCerr result = validator.checkAll(true, true, sigDataMap);
+
+       RUNNER_ASSERT_MSG(result == E_SIG_NONE,
+                                         "sig validation should be success: "
+                                         << validator.errorToString(result));
+
+       /* Below codes is example for client.
+        *
+       auto authorSigData = sigDataMap[ValidationCore::SignatureType::AUTHOR];
+       for (const auto &certPtr : authorSigData.getCertList())
+               std::cout << "Author certificate > " << certPtr->getBase64() << std::endl;
+
+       auto distSigData = sigDataMap[ValidationCore::SignatureType::DISTRIBUTOR1];
+       for (const auto &certPtr : distSigData.getCertList())
+               std::cout << "Distributor certificate > "
+                                 << certPtr->getBase64() << std::endl;
+        *
+        */
+
+}
+
+RUNNER_TEST(T00161_positive_checkListAll)
+{
+       SignatureValidator validator(TestData::tpk_with_userdata_path);
+       UriList uriList;
+       uriList.emplace_back("author-siganture.xml");
+       uriList.emplace_back("bin/preference");
+       uriList.emplace_back("res/edje/pref_buttons_panel.edj");
+       uriList.emplace_back("res/edje/pref_edit_panel.edj");
+       uriList.emplace_back("res/edje/preference.edj");
+       uriList.emplace_back("res/images/icon_delete.png");
+       uriList.emplace_back("res/res.xml");
+       uriList.emplace_back("shared/res/preference.png");
+       uriList.emplace_back("tizen-manifest.xml");
+
+       SignatureDataMap sigDataMap;
+       VCerr result = validator.checkListAll(true, uriList, sigDataMap);
+       RUNNER_ASSERT_MSG(result == E_SIG_NONE,
+                                         "sig validation should be success: "
+                                         << validator.errorToString(result));
+
+       /* Below codes is example for client.
+        *
+       auto authorSigData = sigDataMap[ValidationCore::SignatureType::AUTHOR];
+       for (const auto &certPtr : authorSigData.getCertList())
+               std::cout << "Author certificate > " << certPtr->getBase64() << std::endl;
+
+       auto distSigData = sigDataMap[ValidationCore::SignatureType::DISTRIBUTOR1];
+       for (const auto &certPtr : distSigData.getCertList())
+               std::cout << "Distributor certificate > "
+                                 << certPtr->getBase64() << std::endl;
+        *
+        */
+}
+
 RUNNER_TEST_GROUP_INIT(T0020_SigVal_errorstring)
 
 RUNNER_TEST(T0021)