Add StepSaveSignature step 06/175406/1
authorJunghyun Yeon <jungh.yeon@samsung.com>
Tue, 6 Mar 2018 08:16:11 +0000 (17:16 +0900)
committerJunghyun Yeon <jungh.yeon@samsung.com>
Tue, 10 Apr 2018 05:41:29 +0000 (14:41 +0900)
- Storing distributor signature file itself let user extract
  installed package.
- New step will store signature values into separated files
  and it will be referenced when db has corrupted.
- Also, new step will remove distributor signature files.

Change-Id: I73de9304a9ad296ecc9a4a8687941d427bf5a9fe
Signed-off-by: Junghyun Yeon <jungh.yeon@samsung.com>
14 files changed:
packaging/app-installers.spec
src/common/certificate_validation.cc
src/common/certificate_validation.h
src/common/installer_context.h
src/common/pkgmgr_registration.cc
src/common/step/filesystem/step_remove_files.cc
src/common/step/pkgmgr/step_unregister_app.cc
src/common/step/pkgmgr/step_update_app.cc
src/common/step/security/step_check_old_certificate.cc
src/common/step/security/step_check_signature.cc
src/common/step/security/step_recover_signature.cc
src/common/step/security/step_recover_signature.h
src/common/step/security/step_save_signature.cc [new file with mode: 0644]
src/common/step/security/step_save_signature.h [new file with mode: 0644]

index 1fcbcaa..b37c27b 100644 (file)
@@ -1,5 +1,3 @@
-%define unpackdir /opt/usr/share/package-unpacked
-
 Name:           app-installers
 Summary:        Application installers
 Version:        1.22.12
@@ -46,6 +44,10 @@ Requires: libtzplatform-config
 Requires: xdelta3
 Requires(post): /usr/bin/chsmack
 
+%define unpackdir /opt/usr/share/package-unpacked
+%define rwsignaturedir /opt/share/signatures
+%define rosignaturedir /usr/share/signatures
+
 %description
 This is a meta package that installs the common application
 installers of Tizen.
@@ -88,6 +90,8 @@ make %{?_smp_mflags}
 mkdir -p %{buildroot}%{unpackdir}
 mkdir -p %{buildroot}%{_unitdir_user}/default.target.wants
 ln -sf ../package-recovery-helper.service %{buildroot}%{_unitdir_user}/default.target.wants/package-recovery-helper.service
+mkdir -p %{buildroot}%{rosignaturedir}
+mkdir -p %{buildroot}%{rwsignaturedir}
 
 %post
 chsmack -a System %{unpackdir}
@@ -115,6 +119,8 @@ chsmack -a System %{unpackdir}
 %{_unitdir_user}/default.target.wants/package-recovery-helper.service
 %{unpackdir}
 %license LICENSE
+%{rosignaturedir}
+%{rwsignaturedir}
 
 %files devel
 %{_includedir}/app-installers/common/*.h
index 3526af4..13fb2a8 100644 (file)
@@ -7,6 +7,7 @@
 #include <boost/format.hpp>
 #include <boost/filesystem/operations.hpp>
 #include <boost/scope_exit.hpp>
+#include <vcore/Certificate.h>
 #include <vcore/SignatureValidator.h>
 
 #include <algorithm>
@@ -16,6 +17,7 @@
 
 #include "common/privileges.h"
 #include "common/utils/base64.h"
+#include "common/utils/file_util.h"
 #include "common/utils/glist_range.h"
 
 namespace bf = boost::filesystem;
@@ -41,7 +43,7 @@ bool SetAuthorCertificate(ValidationCore::SignatureData data,
   std::string author_id =
       ci::EncodeBase64(public_key, len);
   cert_info->author_id.set(author_id);
-  cert_info->author_certificate.set(*it);
+  cert_info->auth_cert.set(*it);
   // cert_list has at least 3 certificates: end-user, intermediate, root
   // currently pkgmgr can store only one intermediate cert, so just set
   // first intermediate cert here.
@@ -50,8 +52,8 @@ bool SetAuthorCertificate(ValidationCore::SignatureData data,
     LOG(ERROR) << "No intermediate certificates in certificate list";
     return false;
   }
-  cert_info->author_intermediate_certificate.set(*it);
-  cert_info->author_root_certificate.set(data.getRootCaCertificatePtr());
+  cert_info->auth_im_cert.set(*it);
+  cert_info->auth_root_cert.set(data.getRootCaCertificatePtr());
   return true;
 }
 
@@ -63,14 +65,14 @@ bool SetDistributorCertificate(ValidationCore::SignatureData data,
     LOG(ERROR) << "No certificates in certificate list";
     return false;
   }
-  cert_info->distributor_certificate.set(*it);
+  cert_info->dist_cert.set(*it);
   ++it;
   if (it == cert_list.end()) {
     LOG(ERROR) << "No intermediate certificates in certificate list";
     return false;
   }
-  cert_info->distributor_intermediate_certificate.set(*it);
-  cert_info->distributor_root_certificate.set(data.getRootCaCertificatePtr());
+  cert_info->dist_im_cert.set(*it);
+  cert_info->dist_root_cert.set(data.getRootCaCertificatePtr());
   return true;
 }
 
@@ -82,15 +84,43 @@ bool SetDistributor2Certificate(ValidationCore::SignatureData data,
     LOG(ERROR) << "No certificates in certificate list";
     return false;
   }
-  cert_info->distributor2_certificate.set(*it);
+  cert_info->dist2_cert.set(*it);
   ++it;
   if (it == cert_list.end()) {
     LOG(INFO) << "No intermediate certificates in certificate list";
-    cert_info->distributor2_intermediate_certificate.set({});
+    cert_info->dist2_im_cert.set({});
   } else {
-    cert_info->distributor2_intermediate_certificate.set(*it);
+    cert_info->dist2_im_cert.set(*it);
   }
-  cert_info->distributor2_root_certificate.set(data.getRootCaCertificatePtr());
+  cert_info->dist2_root_cert.set(data.getRootCaCertificatePtr());
+  return true;
+}
+
+bool SetSignature(std::ifstream& ifs,
+    ValidationCore::CertificatePtr* certificate,
+    std::string* cert_str) {
+  std::string cert;
+  std::getline(ifs, cert);
+  if (cert.length() != 0) {
+    ValidationCore::CertificatePtr cert_ptr(
+        new ValidationCore::Certificate(
+            cert, ValidationCore::Certificate::FormType::FORM_BASE64));
+    *certificate = std::move(cert_ptr);
+    *cert_str = std::move(cert);
+  }
+
+  return true;
+}
+
+bool ReadSignature(std::ifstream& ifs,
+    ValidationCore::CertificatePtr* cert,
+    ValidationCore::CertificatePtr* im_cert,
+    ValidationCore::CertificatePtr* root_cert,
+    std::string* root_cert_str) {
+
+  SetSignature(ifs, cert, root_cert_str);
+  SetSignature(ifs, im_cert, root_cert_str);
+  SetSignature(ifs, root_cert, root_cert_str);
   return true;
 }
 
@@ -220,8 +250,8 @@ bool ValidateSignatures(const bf::path& base_path,
   bool distributor_signatures = std::any_of(
       signature_files.begin(), signature_files.end(), CheckDistSignature);
 
-  /* For platform update from 2.4.  signature1.xml of user app has deleted */
-  if (getuid() != 0 && (!author_signatures || !distributor_signatures)) {
+  if (getuid() != 0 && (!author_signatures || !distributor_signatures) &&
+      check_reference) {
     LOG(ERROR) << "Author or distribuor signature is missing.";
     return false;
   }
@@ -238,24 +268,38 @@ bool ValidateSignatures(const bf::path& base_path,
   return true;
 }
 
-bool CheckPrivLevelFromFile(const std::string& pkgid, PrivilegeLevel* level) {
+bool GetSignatureFromFile(const std::string& pkgid,
+    bool is_readonly_package, PrivilegeLevel* level,
+    ci::CertificateInfo* cert_info) {
   CertSvcInstance instance;
   CertSvcCertificate certificate;
   CertSvcVisibility visibility = CERTSVC_VISIBILITY_DEVELOPER;
-  std::string dist_root;
-
-  bf::path file_path("/tmp/");
-  file_path /= std::string(pkgid + ".txt");
-  if (!bf::exists(file_path))
+  std::string root_cert;
+
+  bf::path file_path((is_readonly_package) ?
+      tzplatform_getenv(TZ_SYS_RO_SHARE) : tzplatform_getenv(TZ_SYS_SHARE));
+  file_path /= std::string("signatures/" + pkgid + ".txt");
+  std::ifstream ifs(file_path.c_str(), std::ifstream::in);
+  if (!ifs.is_open()) {
+    LOG(INFO) << "Failed to open file : " << file_path;
     return false;
+  }
 
-  std::ifstream ifs(file_path.c_str(),
-      std::ifstream::in | std::ifstream::binary);
-  if (!ifs)
-    return false;
-  getline(ifs, dist_root);
-  if (dist_root.length() == 0)
+  if (!ReadSignature(ifs,
+          &cert_info->dist2_cert.get(),
+          &cert_info->dist2_im_cert.get(),
+          &cert_info->dist2_root_cert.get(),
+          &root_cert) ||
+      !ReadSignature(ifs,
+          &cert_info->dist_cert.get(),
+          &cert_info->dist_im_cert.get(),
+          &cert_info->dist_root_cert.get(),
+          &root_cert))
     return false;
+  if (root_cert.length() == 0) {
+      LOG(INFO) << "Dist root cert not exists";
+      return false;
+  }
 
   int ret = certsvc_instance_new(&instance);
   if (ret != CERTSVC_SUCCESS) {
@@ -263,8 +307,8 @@ bool CheckPrivLevelFromFile(const std::string& pkgid, PrivilegeLevel* level) {
     return false;
   }
   ret = certsvc_certificate_new_from_memory(instance,
-      reinterpret_cast<const unsigned char *>(dist_root.c_str()),
-      strlen(dist_root.c_str()),
+      reinterpret_cast<const unsigned char *>(root_cert.c_str()),
+      strlen(root_cert.c_str()),
       CERTSVC_FORM_DER_BASE64,
       &certificate);
   if (ret != CERTSVC_SUCCESS) {
index de5db7f..8208090 100644 (file)
@@ -41,7 +41,9 @@ bool ValidatePrivilegeLevel(common_installer::PrivilegeLevel level,
     uid_t uid, const char* api_version, GList* privileges,
     std::string* error_message);
 
-bool CheckPrivLevelFromFile(const std::string& pkgid, PrivilegeLevel* level);
+bool GetSignatureFromFile(const std::string& pkgid,
+    bool is_readonly_package, PrivilegeLevel* level,
+    common_installer::CertificateInfo* cert_info);
 
 bool ValidateMetadataPrivilege(common_installer::PrivilegeLevel level,
     const char* api_version, GList* metadata_list,
index 07620dd..cbf79c1 100644 (file)
@@ -74,24 +74,24 @@ class CertificateInfo {
   /** author_id (using public key from author certificate) */
   Property<std::string> author_id;
   /** author_certificate */
-  Property<ValidationCore::CertificatePtr> author_certificate;
+  Property<ValidationCore::CertificatePtr> auth_cert;
   /** author_intermediate_certificate */
-  Property<ValidationCore::CertificatePtr> author_intermediate_certificate;
+  Property<ValidationCore::CertificatePtr> auth_im_cert;
   /** author_root_certificate */
-  Property<ValidationCore::CertificatePtr> author_root_certificate;
+  Property<ValidationCore::CertificatePtr> auth_root_cert;
   /** distributor_certificate */
-  Property<ValidationCore::CertificatePtr> distributor_certificate;
+  Property<ValidationCore::CertificatePtr> dist_cert;
   /** distributor_intermediate_certificate */
-  Property<ValidationCore::CertificatePtr> distributor_intermediate_certificate;
+  Property<ValidationCore::CertificatePtr> dist_im_cert;
   /** distributor_root_certificate */
-  Property<ValidationCore::CertificatePtr> distributor_root_certificate;
+  Property<ValidationCore::CertificatePtr> dist_root_cert;
   /** distributor2_certificate */
-  Property<ValidationCore::CertificatePtr> distributor2_certificate;
+  Property<ValidationCore::CertificatePtr> dist2_cert;
   /** distributor2_intermediate_certificate */
   Property<ValidationCore::CertificatePtr>
-      distributor2_intermediate_certificate;
+      dist2_im_cert;
   /** distributor2_root_certificate */
-  Property<ValidationCore::CertificatePtr> distributor2_root_certificate;
+  Property<ValidationCore::CertificatePtr> dist2_root_cert;
 };
 
 /**
index 1dc5b67..ba18fe0 100644 (file)
@@ -42,17 +42,17 @@ typedef Property<ValidationCore::CertificatePtr> CertInfo::*PropertyOfCertInf;
 
 const std::vector<std::pair<PropertyOfCertInf, pkgmgr_instcert_type>>
     kCertTypePairs = {
-  {&CertInfo::author_certificate, PM_SET_AUTHOR_SIGNER_CERT},
-  {&CertInfo::author_intermediate_certificate, PM_SET_AUTHOR_INTERMEDIATE_CERT},
-  {&CertInfo::author_root_certificate, PM_SET_AUTHOR_ROOT_CERT},
-  {&CertInfo::distributor_certificate, PM_SET_DISTRIBUTOR_SIGNER_CERT},
-  {&CertInfo::distributor_intermediate_certificate,
+  {&CertInfo::auth_cert, PM_SET_AUTHOR_SIGNER_CERT},
+  {&CertInfo::auth_im_cert, PM_SET_AUTHOR_INTERMEDIATE_CERT},
+  {&CertInfo::auth_root_cert, PM_SET_AUTHOR_ROOT_CERT},
+  {&CertInfo::dist_cert, PM_SET_DISTRIBUTOR_SIGNER_CERT},
+  {&CertInfo::dist_im_cert,
       PM_SET_DISTRIBUTOR_INTERMEDIATE_CERT},
-  {&CertInfo::distributor_root_certificate, PM_SET_DISTRIBUTOR_ROOT_CERT},
-  {&CertInfo::distributor2_certificate, PM_SET_DISTRIBUTOR2_SIGNER_CERT},
-  {&CertInfo::distributor2_intermediate_certificate,
+  {&CertInfo::dist_root_cert, PM_SET_DISTRIBUTOR_ROOT_CERT},
+  {&CertInfo::dist2_cert, PM_SET_DISTRIBUTOR2_SIGNER_CERT},
+  {&CertInfo::dist2_im_cert,
       PM_SET_DISTRIBUTOR2_INTERMEDIATE_CERT},
-  {&CertInfo::distributor2_root_certificate, PM_SET_DISTRIBUTOR2_ROOT_CERT}
+  {&CertInfo::dist2_root_cert, PM_SET_DISTRIBUTOR2_ROOT_CERT}
 };
 
 bool RegisterCertificates(
index a49e6ad..f629fb1 100644 (file)
@@ -36,6 +36,17 @@ bool SkipRWDirectories(const bf::path& path) {
       dirs_to_ignore.end();
 }
 
+bool RemoveSignature(const std::string& pkgid, bool is_readonly) {
+  bf::path signature_path = bf::path(is_readonly ?
+      tzplatform_getenv(TZ_SYS_RO_SHARE) : tzplatform_getenv(TZ_SYS_SHARE)) /
+          "signatures";
+  signature_path /= std::string(pkgid + ".txt");
+  if (!common_installer::Remove(signature_path))
+    return false;
+
+  return true;
+}
+
 }  // namespace
 
 
@@ -112,6 +123,11 @@ Step::Status StepRemoveFiles::process() {
       return Status::APP_DIR_ERROR;
   }
 
+  // Remove stored signature file
+  if (!RemoveSignature(context_->pkgid.get(),
+                        context_->is_readonly_package.get()))
+    return Status::APP_DIR_ERROR;
+
   return Status::OK;
 }
 
index a4d4c8e..c92ab08 100644 (file)
@@ -53,7 +53,7 @@ bool StepUnregisterApplication::BackupCertInfo() {
   if (!base64.empty()) {
     CertificateInfo certificate_info;
     try {
-      certificate_info.author_certificate.set(ValidationCore::CertificatePtr(
+      certificate_info.auth_cert.set(ValidationCore::CertificatePtr(
           new ValidationCore::Certificate(
               base64,
               ValidationCore::Certificate::FormType::FORM_BASE64)));
index 4ca1854..5c55b11 100644 (file)
@@ -52,7 +52,7 @@ Step::Status StepUpdateApplication::undo() {
   CertificateInfo certificate_info;
   if (!base64.empty()) {
     try {
-      certificate_info.author_certificate.set(ValidationCore::CertificatePtr(
+      certificate_info.auth_cert.set(ValidationCore::CertificatePtr(
           new ValidationCore::Certificate(
               base64,
               ValidationCore::Certificate::FormType::FORM_BASE64)));
index 43252ef..afcd343 100644 (file)
@@ -21,7 +21,7 @@ Step::Status StepCheckOldCertificate::process() {
   std::string old_author_cert =
       QueryCertificateAuthorCertificate(context_->pkgid.get(),
                                         context_->uid.get());
-  const auto& cert = context_->certificate_info.get().author_certificate.get();
+  const auto& cert = context_->certificate_info.get().auth_cert.get();
 
   if (!old_author_cert.empty()) {
     if (!cert) {
index c450a2b..27eef70 100644 (file)
@@ -95,7 +95,7 @@ Step::Status StepCheckSignature::CheckSignatures(bool check_reference,
 }
 
 Step::Status StepCheckSignature::CheckSignatureMismatch() {
-  const auto& cert = context_->certificate_info.get().author_certificate.get();
+  const auto& cert = context_->certificate_info.get().auth_cert.get();
   if (cert) {
     bool certificate_mismatch =
         CheckPkgCertificateMismatch(context_->pkgid.get(), cert->getBase64());
@@ -166,14 +166,15 @@ Step::Status StepCheckSignature::process() {
   if (status != Status::OK)
     return status;
 
+  if (level == PrivilegeLevel::UNTRUSTED)
+    if (!GetSignatureFromFile(context_->pkgid.get(),
+        context_->is_readonly_package.get(), &level,
+        &context_->certificate_info.get()))
+      LOG(INFO) << "Unable to get privilege level from file";
+
   if (context_->is_readonly_package.get())
     level = PrivilegeLevel::PLATFORM;
 
-  // Try to get privilege level from file for migrate pkgs installed in 2.4
-  if (getuid() == 0 && level == PrivilegeLevel::UNTRUSTED)
-    if (!CheckPrivLevelFromFile(context_->pkgid.get(), &level))
-      LOG(ERROR) << "Unable to get privilege level from file";
-
   if (level == PrivilegeLevel::UNTRUSTED) {
     std::string error_message =
         "Unsigned applications can not be installed";
index 52d7f14..23d4424 100644 (file)
@@ -9,12 +9,44 @@
 #include <string>
 
 #include "common/certificate_validation.h"
+#include "common/utils/file_util.h"
 
 namespace bf = boost::filesystem;
 
+namespace {
+
+bf::path GetSignatureFilePath(bool is_readonly) {
+  return bf::path((is_readonly) ?
+      tzplatform_getenv(TZ_SYS_RO_SHARE) : tzplatform_getenv(TZ_SYS_SHARE)) /
+          "signature";
+}
+
+bool RecoverSignatureFile(const std::string& pkgid, bool is_readonly) {
+  bf::path path = GetSignatureFilePath(is_readonly);
+  bf::path target_path = bf::path(path) / std::string(pkgid + ".txt");
+  bf::path backup_path = bf::path(path) / std::string(pkgid + "_backup.txt");
+
+  if (bf::exists(backup_path) &&
+      !common_installer::MoveFile(backup_path, target_path, true))
+    return false;
+
+  return true;
+}
+
+}  // namespace
+
 namespace common_installer {
 namespace security {
 
+Step::Status StepRecoverSignature::RecoveryNew() {
+  bf::path path = GetSignatureFilePath(context_->is_readonly_package.get());
+  path /= std::string(context_->pkgid.get() + ".txt");
+  if (!common_installer::Remove(path))
+    return Status::CERT_ERROR;
+
+  return Status::OK;
+}
+
 Step::Status StepRecoverSignature::RecoveryUpdate() {
   std::string error_message;
   PrivilegeLevel level = PrivilegeLevel::UNTRUSTED;
@@ -24,6 +56,21 @@ Step::Status StepRecoverSignature::RecoveryUpdate() {
     LOG(ERROR) << "Failed to verify signature: " << error_message;
     return Status::CERT_ERROR;
   }
+
+  if (level == PrivilegeLevel::UNTRUSTED) {
+    // if priv level is untrusted, get priv level from backed up signature file
+    if (!GetSignatureFromFile(context_->pkgid.get(),
+        context_->is_readonly_package.get(), &level,
+        &context_->certificate_info.get())) {
+      LOG(INFO) << "Unable to get privilege level from file";
+      return Status::CERT_ERROR;
+    }
+  }
+
+  if (!RecoverSignatureFile(context_->pkgid.get(),
+                            context_->is_readonly_package.get()))
+    return Status::CERT_ERROR;
+
   context_->privilege_level.set(level);
   return Status::OK;
 }
@@ -40,6 +87,19 @@ Step::Status StepRecoverSignature::RecoveryReadonlyUpdateInstall() {
     LOG(ERROR) << "Failed to verify signature: " << error_message;
     return Status::CERT_ERROR;
   }
+
+  if (level == PrivilegeLevel::UNTRUSTED) {
+    if (!GetSignatureFromFile(context_->pkgid.get(),
+        context_->is_readonly_package.get(), &level,
+        &context_->certificate_info.get())) {
+      LOG(INFO) << "Unable to get privilege level from file";
+      return Status::CERT_ERROR;
+    }
+  }
+
+  if (!RecoverSignatureFile(context_->pkgid.get(), false))
+    return Status::CERT_ERROR;
+
   context_->privilege_level.set(level);
   return Status::OK;
 }
index e695d04..f1221f0 100644 (file)
@@ -28,7 +28,7 @@ class StepRecoverSignature : public recovery::StepRecovery {
  public:
   using StepRecovery::StepRecovery;
 
-  Status RecoveryNew() override { return Status::OK; }
+  Status RecoveryNew() override;
   Status RecoveryUpdate() override;
   Status RecoveryReadonlyUpdateInstall() override;
 
diff --git a/src/common/step/security/step_save_signature.cc b/src/common/step/security/step_save_signature.cc
new file mode 100644 (file)
index 0000000..e1964ed
--- /dev/null
@@ -0,0 +1,155 @@
+// Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by a apache 2.0 license that can be
+// found in the LICENSE file.
+
+#include "common/step/security/step_save_signature.h"
+
+#include <manifest_parser/utils/logging.h>
+#include <pkgmgr-info.h>
+#include <unistd.h>
+
+#include <cstdlib>
+#include <fstream>
+#include <regex>
+#include <string>
+
+#include "common/utils/file_util.h"
+
+namespace bf = boost::filesystem;
+
+namespace {
+
+bool StoreSignature(std::ofstream& ofs,
+    ValidationCore::CertificatePtr& cert,
+    ValidationCore::CertificatePtr& im_cert,
+    ValidationCore::CertificatePtr& root_cert) {
+  if (!ofs)
+    return false;
+
+  ofs << ((cert) ? cert->getBase64().c_str() : "") << std::endl;
+  ofs << ((im_cert) ? im_cert->getBase64().c_str() : "") << std::endl;
+  ofs << ((root_cert) ? root_cert->getBase64().c_str() : "") << std::endl;
+  return true;
+}
+
+bool RemoveSignature(bf::path& path) {
+  for (bf::directory_iterator file(path);
+      file != bf::directory_iterator();
+      ++file) {
+    try {
+      bf::path file_path(file->path());
+
+      if (bf::is_symlink(symlink_status(file_path)) ||
+          bf::is_directory(file_path))
+        continue;
+
+      std::regex distributor_regex("^(signature)([1-9][0-9]*)(\\.xml)");
+      if (std::regex_search(file_path.filename().string(), distributor_regex)) {
+        if (!common_installer::Remove(file_path)) {
+          LOG(ERROR) << "Failed to remove signature file";
+          return false;
+        }
+      }
+    } catch (const bf::filesystem_error& error) {
+      LOG(ERROR) << "Failed to remove signature files: " << error.what();
+      return false;
+    }
+  }
+
+  return true;
+}
+
+} // namespace
+
+namespace common_installer {
+namespace security {
+
+Step::Status StepSaveSignature::precheck() {
+  if (context_->pkgid.get().empty())
+    return Step::Status::INVALID_VALUE;
+
+  signature_path_ = bf::path((context_->is_readonly_package.get()) ?
+      tzplatform_getenv(TZ_SYS_RO_SHARE) : tzplatform_getenv(TZ_SYS_SHARE)) /
+          "signatures";
+
+  if (!CreateDir(signature_path_))
+    return Step::Status::APP_DIR_ERROR;
+
+  return Step::Status::OK;
+}
+
+Step::Status StepSaveSignature::process() {
+  common_installer::CertificateInfo cert_info =
+      context_->certificate_info.get();
+
+  bf::path signature_filepath = signature_path_ /
+      std::string(context_->pkgid.get() + ".txt");
+  backup_path_ = signature_path_ /
+      std::string(context_->pkgid.get() + "_backup.txt");
+  if (bf::exists(backup_path_))
+    bf::remove(backup_path_);
+  if (bf::exists(signature_filepath))
+    bf::rename(signature_filepath, backup_path_);
+
+  std::ofstream ofs(signature_filepath.c_str(),
+      std::ios::out | std::ios::trunc);
+  if (!StoreSignature(ofs,
+                      cert_info.dist2_cert.get(),
+                      cert_info.dist2_im_cert.get(),
+                      cert_info.dist2_root_cert.get()) ||
+      !StoreSignature(ofs,
+                      cert_info.dist_cert.get(),
+                      cert_info.dist_im_cert.get(),
+                      cert_info.dist_root_cert.get()))
+    return Step::Status::APP_DIR_ERROR;
+  ofs.close();
+
+  if (!RemoveSignature(context_->unpacked_dir_path.get()))
+    return Step::Status::APP_DIR_ERROR;
+
+  for (bf::directory_iterator file(context_->unpacked_dir_path.get());
+      file != bf::directory_iterator();
+      ++file) {
+    try {
+      bf::path file_path(file->path());
+
+      if (bf::is_symlink(symlink_status(file_path)) ||
+          bf::is_directory(file_path))
+        continue;
+
+      std::regex distributor_regex("^(signature)([1-9][0-9]*)(\\.xml)");
+      if (std::regex_search(file_path.filename().string(), distributor_regex)) {
+        if (!Remove(file_path)) {
+          LOG(ERROR) << "Failed to remove signature file";
+          return Step::Status::APP_DIR_ERROR;
+        }
+      }
+    } catch (const bf::filesystem_error& error) {
+      LOG(ERROR) << "Failed to remove signature files: " << error.what();
+      return Step::Status::APP_DIR_ERROR;
+    }
+  }
+
+  sync();
+  return Step::Status::OK;
+}
+
+Step::Status StepSaveSignature::undo() {
+  bf::path signature_filepath = signature_path_ /
+      std::string(context_->pkgid.get() + ".txt");
+  bf::remove(signature_filepath);
+  if (bf::exists(backup_path_))
+    bf::rename(backup_path_, signature_filepath);
+
+  return Step::Status::OK;
+}
+
+Step::Status StepSaveSignature::clean() {
+  if (bf::exists(backup_path_))
+    bf::remove(backup_path_);
+
+  return Step::Status::OK;
+}
+
+}  // namespace security
+}  // namespace common_installer
diff --git a/src/common/step/security/step_save_signature.h b/src/common/step/security/step_save_signature.h
new file mode 100644 (file)
index 0000000..549946e
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by a apache 2.0 license that can be
+// found in the LICENSE file.
+
+#ifndef COMMON_STEP_SECURITY_STEP_SAVE_SIGNATURE_H_
+#define COMMON_STEP_SECURITY_STEP_SAVE_SIGNATURE_H_
+
+#include <manifest_parser/utils/logging.h>
+
+#include <boost/filesystem/path.hpp>
+
+#include "common/installer_context.h"
+#include "common/step/step.h"
+
+namespace common_installer {
+namespace security {
+
+/**
+ * \brief step responsible for saving certificates into individual files to restore
+ *        certificate database. Used by WGT and TPK
+ */
+class StepSaveSignature : public Step {
+ public:
+  using Step::Step;
+
+  Status process() override;
+  Status undo() override;
+  Status clean() override;
+  Status precheck() override;
+
+ private:
+  boost::filesystem::path signature_path_;
+  boost::filesystem::path backup_path_;
+
+  STEP_NAME(StepSaveSignature)
+};
+
+}  // namespace security
+}  // namespace common_installer
+
+#endif  // COMMON_STEP_SECURITY_STEP_SAVE_SIGNATURE_H_