Combine Signature Steps
[platform/core/appfw/app-installers.git] / src / common / signature.cc
1 // Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
2 // Use of this source code is governed by an apache-2.0 license that can be
3 // found in the LICENSE file.
4
5 #include "common/signature.h"
6
7 #include <tzplatform_config.h>
8
9 #include <string>
10 #include <regex>
11
12 #include "common/certificate_validation.h"
13 #include "common/pkgmgr_query.h"
14 #include "common/request.h"
15 #include "common/utils/glist_range.h"
16 #include "common/utils/file_util.h"
17
18 namespace bf = boost::filesystem;
19 namespace ci = common_installer;
20
21 namespace common_installer {
22
23 bool CheckPkgCertificateMismatch(const std::string& pkgid,
24                                  const std::string& certificate) {
25   bool certificate_mismatch = false;
26   uid_t uid = G_MAXUINT;
27   auto old_certificate = ci::QueryCertificateAuthorCertificate(pkgid, uid);
28
29   if (!old_certificate.empty()) {
30     bool is_same = ci::IsSameAuthor(old_certificate, certificate);
31     certificate_mismatch = !is_same;
32   }
33   return certificate_mismatch;
34 }
35
36 bool Signature::CheckSignatureMismatch(std::string& error_message) {
37   const auto& cert = cert_info_->auth_cert.get();
38   if (cert) {
39     bool certificate_mismatch =
40         CheckPkgCertificateMismatch(pkgid_, cert->getBase64());
41     if (certificate_mismatch) {
42       error_message =
43           "Package with the same id and different certificate "
44           "has been already installed";
45       return false;
46     }
47   }
48   return true;
49 }
50
51 bool Signature::SetPath() {
52   bf::path path = bf::path((is_readonly_package_) ?
53       tzplatform_getenv(TZ_SYS_RO_SHARE) : tzplatform_getenv(TZ_SYS_SHARE)) /
54       "signatures";
55   if (!CreateDir(path))
56     return false;
57
58   file_path_ = path / std::string(pkgid_ + ".txt");
59   backup_path_ = path / std::string(pkgid_ + "_backup.txt");
60   if (bf::exists(backup_path_))
61     bf::remove(backup_path_);
62   if (bf::exists(file_path_))
63     bf::rename(file_path_, backup_path_);
64   return true;
65 }
66
67 bool Signature::CheckSignatures(bool check_reference, PrivilegeLevel* level,
68                     boost::filesystem::path sig_root_path,
69                     std::string *error_message) {
70   if (!ValidateSignatures(sig_root_path, level, cert_info_,
71                           check_reference, error_message))
72     return false;
73   return true;
74 }
75
76 bool Signature::GetPrivilegeLevel(boost::filesystem::path sig_root_path,
77                                  PrivilegeLevel* level,
78                                  std::string& error_message) {
79   bool check_reference = true;
80   if (request_type_ == ci::RequestType::Reinstall ||
81       request_type_ == ci::RequestType::ReadonlyUpdateUninstall ||
82       (getuid() == 0 &&
83       (skip_check_reference_ ||
84       request_type_ == ci::RequestType::ManifestDirectInstall ||
85       request_type_ == ci::RequestType::ManifestDirectUpdate ||
86       request_type_ == ci::RequestType::ManifestPartialInstall ||
87       request_type_ == ci::RequestType::ManifestPartialUpdate)))
88     check_reference = false;
89   if (!CheckSignatures(check_reference, level, sig_root_path, &error_message))
90     return false;
91
92   if (!CheckSignatureMismatch(error_message))
93     return false;
94
95   if (*level == PrivilegeLevel::UNTRUSTED)
96     if (!GetSignatureFromFile(pkgid_, is_readonly_package_, level, cert_info_))
97       LOG(INFO) << "Unable to get privilege level from file";
98
99   if (is_readonly_package_)
100     *level = PrivilegeLevel::PLATFORM;
101
102   return true;
103 }
104
105 bool Signature::CheckMetadataPrivilege(PrivilegeLevel level,
106                                       manifest_x* manifest,
107                                       std::string& error_message) {
108   if (is_readonly_package_)
109     return true;
110   for (application_x* app : GListRange<application_x*>(manifest->application)) {
111     if (!ValidateMetadataPrivilege(level, manifest->api_version,
112         app->metadata, &error_message))
113       return false;
114   }
115   return true;
116 }
117
118 bool Signature::StoreSignature(std::ofstream* ofs,
119     const ValidationCore::CertificatePtr& cert,
120     const ValidationCore::CertificatePtr& im_cert,
121     const ValidationCore::CertificatePtr& root_cert) {
122   if (!ofs)
123     return false;
124
125   *ofs << ((cert) ? cert->getBase64().c_str() : "") << std::endl;
126   *ofs << ((im_cert) ? im_cert->getBase64().c_str() : "") << std::endl;
127   *ofs << ((root_cert) ? root_cert->getBase64().c_str() : "") << std::endl;
128   return true;
129 }
130
131 bool Signature::Store() {
132   bool ret = true;
133   std::ofstream ofs(file_path_.c_str(),
134       std::ios::out | std::ios::trunc);
135   if (!StoreSignature(&ofs,
136                       cert_info_->dist2_cert.get(),
137                       cert_info_->dist2_im_cert.get(),
138                       cert_info_->dist2_root_cert.get()) ||
139       !StoreSignature(&ofs,
140                       cert_info_->dist_cert.get(),
141                       cert_info_->dist_im_cert.get(),
142                       cert_info_->dist_root_cert.get()))
143     ret = false;
144   ofs.close();
145   return ret;
146 }
147
148 bool Signature::RemoveSignature(const bf::path& path) {
149   // dist signatures cannot be removed when mount install/update
150   if (request_type_ == RequestType::MountInstall ||
151       request_type_ == RequestType::MountUpdate)
152     return true;
153
154   for (bf::directory_iterator file(path);
155       file != bf::directory_iterator();
156       ++file) {
157     try {
158       bf::path file_path(file->path());
159
160       if (bf::is_symlink(symlink_status(file_path)) ||
161           bf::is_directory(file_path))
162         continue;
163
164       std::regex distributor_regex("^(signature)([1-9][0-9]*)(\\.xml)");
165       if (std::regex_search(file_path.filename().string(), distributor_regex)) {
166         if (!common_installer::Remove(file_path)) {
167           LOG(ERROR) << "Failed to remove signature file";
168           return false;
169         }
170       }
171     } catch (const bf::filesystem_error& error) {
172       LOG(ERROR) << "Failed to remove signature files: " << error.what();
173       return false;
174     }
175   }
176
177   sync();
178   return true;
179 }
180
181 bool Signature::SaveSignature(const bf::path& path) {
182   if (!SetPath() || !Store() || !RemoveSignature(path))
183     return false;
184   return true;
185 }
186
187 const bf::path& Signature::GetFilePath() const {
188   return file_path_;
189 }
190
191 const bf::path& Signature::GetBackupPath() const {
192   return backup_path_;
193 }
194
195 }  // namespace common_installer