-%define unpackdir /opt/usr/share/package-unpacked
-
Name: app-installers
Summary: Application installers
Version: 1.22.12
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.
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}
%{_unitdir_user}/default.target.wants/package-recovery-helper.service
%{unpackdir}
%license LICENSE
+%{rosignaturedir}
+%{rwsignaturedir}
%files devel
%{_includedir}/app-installers/common/*.h
#include <boost/format.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/scope_exit.hpp>
+#include <vcore/Certificate.h>
#include <vcore/SignatureValidator.h>
#include <algorithm>
#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;
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.
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;
}
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;
}
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;
}
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;
}
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) {
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) {
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,
/** 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;
};
/**
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(
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
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;
}
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)));
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)));
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) {
}
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());
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";
#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;
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;
}
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;
}
public:
using StepRecovery::StepRecovery;
- Status RecoveryNew() override { return Status::OK; }
+ Status RecoveryNew() override;
Status RecoveryUpdate() override;
Status RecoveryReadonlyUpdateInstall() override;
--- /dev/null
+// 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
--- /dev/null
+// 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_