1 // Copyright (c) 2016 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.
5 #include "common/certificate_validation.h"
7 #include <boost/format.hpp>
8 #include <boost/filesystem/operations.hpp>
9 #include <boost/scope_exit.hpp>
10 #include <vcore/Certificate.h>
11 #include <vcore/SignatureValidator.h>
18 #include "common/privileges.h"
19 #include "common/utils/base64.h"
20 #include "common/utils/file_util.h"
21 #include "common/utils/glist_range.h"
23 namespace bf = boost::filesystem;
24 namespace ci = common_installer;
28 const char kSignatureAuthor[] = "author-signature.xml";
29 const char kRegexDistributorSignature[] = "^(signature)([1-9][0-9]*)(\\.xml)";
31 static bool SetCertificate(const ValidationCore::SignatureData& data,
32 Property<ValidationCore::CertificatePtr>* certificate,
33 Property<ValidationCore::CertificatePtr>* intermediate_certificate,
34 Property<ValidationCore::CertificatePtr>* root_certificate,
35 bool intermediate_mandatory) {
36 ValidationCore::CertificateList cert_list = data.getCertList();
37 ValidationCore::CertificateList::iterator it = cert_list.begin();
38 if (it == cert_list.end()) {
39 LOG(ERROR) << "No certificates in certificate list";
42 certificate->set(*it);
44 if (it == cert_list.end()) {
45 if (intermediate_mandatory) {
46 LOG(ERROR) << "No intermediate certificates in certificate list";
49 intermediate_certificate->set({});
52 intermediate_certificate->set(*it);
54 root_certificate->set(data.getRootCaCertificatePtr());
58 static bool SetAuthorCertificate(const ValidationCore::SignatureData& data,
59 common_installer::CertificateInfo* cert_info) {
60 ValidationCore::CertificateList cert_list = data.getCertList();
61 ValidationCore::CertificateList::iterator it = cert_list.begin();
62 if (it == cert_list.end()) {
63 LOG(ERROR) << "No certificates in certificate list";
66 unsigned char* public_key;
68 (*it)->getPublicKeyDER(&public_key, &len);
69 std::string author_id =
70 ci::EncodeBase64(public_key, len);
71 cert_info->author_id.set(author_id);
72 return SetCertificate(data,
73 &cert_info->auth_cert,
74 &cert_info->auth_im_cert,
75 &cert_info->auth_root_cert,
79 bool SetDistributorCertificate(const ValidationCore::SignatureData& data,
80 common_installer::CertificateInfo* cert_info) {
81 return SetCertificate(data,
82 &cert_info->dist_cert,
83 &cert_info->dist_im_cert,
84 &cert_info->dist_root_cert,
88 bool SetDistributor2Certificate(const ValidationCore::SignatureData& data,
89 common_installer::CertificateInfo* cert_info) {
90 return SetCertificate(data,
91 &cert_info->dist2_cert,
92 &cert_info->dist2_im_cert,
93 &cert_info->dist2_root_cert,
97 bool SetSignature(std::ifstream* ifs,
98 ValidationCore::CertificatePtr* certificate,
99 std::string* cert_str) {
101 std::getline(*ifs, cert);
102 if (cert.length() != 0) {
103 ValidationCore::CertificatePtr cert_ptr(
104 new ValidationCore::Certificate(
105 cert, ValidationCore::Certificate::FormType::FORM_BASE64));
106 *certificate = std::move(cert_ptr);
107 *cert_str = std::move(cert);
113 bool ReadSignature(std::ifstream* ifs,
114 ValidationCore::CertificatePtr* cert,
115 ValidationCore::CertificatePtr* im_cert,
116 ValidationCore::CertificatePtr* root_cert,
117 std::string* root_cert_str) {
119 SetSignature(ifs, cert, root_cert_str);
120 SetSignature(ifs, im_cert, root_cert_str);
121 SetSignature(ifs, root_cert, root_cert_str);
127 namespace common_installer {
129 common_installer::PrivilegeLevel CertStoreIdToPrivilegeLevel(
130 ValidationCore::CertStoreId::Type id) {
132 case ValidationCore::CertStoreId::VIS_PUBLIC:
133 return common_installer::PrivilegeLevel::PUBLIC;
134 case ValidationCore::CertStoreId::VIS_PARTNER:
135 return common_installer::PrivilegeLevel::PARTNER;
136 case ValidationCore::CertStoreId::VIS_PLATFORM:
137 return common_installer::PrivilegeLevel::PLATFORM;
139 return common_installer::PrivilegeLevel::UNTRUSTED;
143 privilege_manager_visibility_e PrivilegeLevelToVisibility(
144 common_installer::PrivilegeLevel level) {
146 case common_installer::PrivilegeLevel::PUBLIC:
147 return PRVMGR_PACKAGE_VISIBILITY_PUBLIC;
148 case common_installer::PrivilegeLevel::PARTNER:
149 return PRVMGR_PACKAGE_VISIBILITY_PARTNER;
150 case common_installer::PrivilegeLevel::PLATFORM:
151 return PRVMGR_PACKAGE_VISIBILITY_PLATFORM;
153 assert(false && "Not reached");
157 void SetPrivilegeLevel(const ValidationCore::SignatureData& data,
158 common_installer::PrivilegeLevel* level) {
160 if (*level != common_installer::PrivilegeLevel::UNTRUSTED)
162 *level = CertStoreIdToPrivilegeLevel(data.getVisibilityLevel());
165 bool ValidateSignatureFile(
166 const bf::path& base_path,
167 const ValidationCore::SignatureFileInfo& file_info,
168 common_installer::PrivilegeLevel* level,
169 common_installer::CertificateInfo* cert_info,
170 bool check_reference, std::string* error_message) {
171 LOG(INFO) << "Processing signature: " << file_info.getFileName();
173 ValidationCore::SignatureValidator validator(file_info);
174 ValidationCore::SignatureData data;
175 ValidationCore::VCerr result;
176 if (check_reference) {
177 result = validator.check(base_path.string(), true, true, data);
179 result = validator.checkList(true, ValidationCore::UriList(), data);
182 std::string errnum = std::to_string(result);
183 *error_message = validator.errorToString(result);
184 *error_message += ":<" + errnum + ">";
187 case ValidationCore::E_SIG_REVOKED:
188 LOG(ERROR) << "Certificate is revoked";
190 case ValidationCore::E_SIG_DISREGARDED:
191 LOG(INFO) << "Signature disregarded: " << file_info.getFileName();
192 // in this case, signature2.xml is signed with non-Tizen certificate
193 if (file_info.getFileNumber() == 2) {
194 if (!SetDistributor2Certificate(data, cert_info))
198 case ValidationCore::E_SIG_NONE:
199 if (data.isAuthorSignature()) {
200 // set author certificates to be saved in pkgmgr
201 if (!SetAuthorCertificate(data, cert_info))
203 } else if (file_info.getFileNumber() == 1) {
204 // First distributor signature sets the privilege level
206 SetPrivilegeLevel(data, level);
207 if (!SetDistributorCertificate(data, cert_info))
209 } else if (file_info.getFileNumber() == 2) {
210 if (!SetDistributor2Certificate(data, cert_info))
215 LOG(ERROR) << "signature validation check failed : "
216 << validator.errorToString(result);
222 bool CheckAuthorSignature(const ValidationCore::SignatureFileInfo& file_info) {
223 return file_info.getFileName().find(kSignatureAuthor) != std::string::npos;
226 bool CheckDistSignature(const ValidationCore::SignatureFileInfo& file_info) {
227 std::regex distributor_regex(kRegexDistributorSignature);
228 bf::path file_path(file_info.getFileName());
229 return std::regex_search(file_path.filename().string(), distributor_regex);
232 bool ValidateSignatures(const bf::path& base_path,
233 PrivilegeLevel* level, common_installer::CertificateInfo* cert_info,
234 bool check_reference, std::string* error_message) {
235 // Find signature files
236 ValidationCore::SignatureFileInfoSet signature_files;
237 ValidationCore::SignatureFinder signature_finder(base_path.string());
238 if (signature_finder.find(signature_files) !=
239 ValidationCore::SignatureFinder::NO_ERROR) {
240 LOG(ERROR) << "Error while searching for signatures";
243 LOG(INFO) << "Number of signature files: " << signature_files.size();
245 bool author_signatures = std::any_of(
246 signature_files.begin(), signature_files.end(), CheckAuthorSignature);
248 bool distributor_signatures = std::any_of(
249 signature_files.begin(), signature_files.end(), CheckDistSignature);
251 if (getuid() != 0 && (!author_signatures || !distributor_signatures) &&
253 LOG(ERROR) << "Author or distribuor signature is missing.";
257 // Read xml schema for signatures
258 for (auto& file_info : signature_files) {
260 if (!ValidateSignatureFile(base_path, file_info, level,
261 cert_info, check_reference, &error)) {
262 *error_message = error;
269 bool GetSignatureFromFile(const std::string& pkgid,
270 bool is_readonly_package, PrivilegeLevel* level,
271 ci::CertificateInfo* cert_info) {
272 CertSvcInstance instance;
273 CertSvcCertificate certificate;
274 CertSvcVisibility visibility = CERTSVC_VISIBILITY_DEVELOPER;
275 std::string root_cert;
277 bf::path file_path((is_readonly_package) ?
278 tzplatform_getenv(TZ_SYS_RO_SHARE) : tzplatform_getenv(TZ_SYS_SHARE));
279 file_path /= std::string("signatures/" + pkgid + ".txt");
280 std::ifstream ifs(file_path.c_str(), std::ifstream::in);
281 if (!ifs.is_open()) {
282 LOG(INFO) << "Failed to open file : " << file_path;
286 if (!ReadSignature(&ifs,
287 &cert_info->dist2_cert.get(),
288 &cert_info->dist2_im_cert.get(),
289 &cert_info->dist2_root_cert.get(),
292 &cert_info->dist_cert.get(),
293 &cert_info->dist_im_cert.get(),
294 &cert_info->dist_root_cert.get(),
297 if (root_cert.length() == 0) {
298 LOG(INFO) << "Dist root cert not exists";
302 int ret = certsvc_instance_new(&instance);
303 if (ret != CERTSVC_SUCCESS) {
304 LOG(ERROR) << "certsvc_instance_new failed :" << ret;
307 ret = certsvc_certificate_new_from_memory(instance,
308 reinterpret_cast<const unsigned char *>(root_cert.c_str()),
309 strlen(root_cert.c_str()),
310 CERTSVC_FORM_DER_BASE64,
312 if (ret != CERTSVC_SUCCESS) {
313 LOG(ERROR) << "certsvc_certificate_new_from_memory failed :" << ret;
314 certsvc_instance_free(instance);
318 ret = certsvc_certificate_get_visibility(certificate, &visibility);
319 if (ret != CERTSVC_SUCCESS) {
320 LOG(ERROR) << "Failed to get visibility from file :" << ret;
321 certsvc_certificate_free(certificate);
322 certsvc_instance_free(instance);
326 certsvc_certificate_free(certificate);
327 certsvc_instance_free(instance);
328 *level = CertStoreIdToPrivilegeLevel(visibility);
333 bool ValidatePrivilegeLevel(common_installer::PrivilegeLevel level,
334 uid_t uid, const char* api_version, GList* privileges,
335 std::string* error_message) {
336 if (level == common_installer::PrivilegeLevel::UNTRUSTED) {
338 LOG(ERROR) << "Untrusted application cannot declare privileges";
345 GList* native_privileges =
346 ci::PrivilegeXToPrivilege(privileges, ci::kNativePrivilegeType);
347 BOOST_SCOPE_EXIT_ALL(&) {
348 g_list_free_full(native_privileges, free);
350 GList* web_privileges =
351 ci::PrivilegeXToPrivilege(privileges, ci::kWebPrivilegeType);
352 BOOST_SCOPE_EXIT_ALL(&) {
353 g_list_free_full(web_privileges, free);
356 for (const std::pair<GList*, bool>& pair :
357 std::initializer_list<std::pair<GList*, bool>>{
358 {native_privileges, false},
359 {web_privileges, true}
361 char* error = nullptr;
362 int status = PRVMGR_ERR_NONE;
363 // Do the privilege check only if the package has privileges
365 status = privilege_manager_verify_privilege(uid, api_version,
366 pair.second ? PRVMGR_PACKAGE_TYPE_WRT : PRVMGR_PACKAGE_TYPE_CORE,
367 pair.first, PrivilegeLevelToVisibility(level), &error);
369 if (status != PRVMGR_ERR_NONE) {
370 std::string errnum = std::to_string(status);
372 *error_message = error;
375 LOG(ERROR) << "Error while verifing privilege level: "
376 << *error_message << " <" << errnum << ">";
377 *error_message += ":<" + errnum + ">";
382 LOG(INFO) << "Privilege level checked";
386 bool ValidateMetadataPrivilege(common_installer::PrivilegeLevel level,
387 const char* api_version, GList* metadata_list,
388 std::string* error_message) {
391 char* error = nullptr;
392 int status = PRVMGR_ERR_NONE;
394 GList *metadata_keylist = NULL;
395 for (metadata_x* meta : GListRange<metadata_x*>(metadata_list))
396 metadata_keylist = g_list_append(metadata_keylist, meta->key);
398 status = privilege_manager_verify_metadata(api_version, metadata_keylist,
399 PrivilegeLevelToVisibility(level), &error);
401 if (metadata_keylist)
402 g_list_free(metadata_keylist);
404 if (status != PRVMGR_ERR_NONE) {
405 std::string errnum = std::to_string(status);
407 *error_message = error;
410 LOG(ERROR) << "Error while verifing metadata privilege: "
411 << *error_message << " <" << errnum << ">";
412 *error_message += ":<" + errnum + ">";
419 bool IsSameAuthor(const std::string& cert_str1, const std::string& cert_str2) {
421 ValidationCore::Certificate cert1 = ValidationCore::Certificate(
422 cert_str1, ValidationCore::Certificate::FormType::FORM_BASE64);
423 ValidationCore::Certificate cert2 = ValidationCore::Certificate(
424 cert_str2, ValidationCore::Certificate::FormType::FORM_BASE64);
425 return cert1.getPublicKeyString() == cert2.getPublicKeyString();
426 } catch (const ValidationCore::Certificate::Exception::Base &e) {
427 LOG(ERROR) << "Exception occured on cert-svc-vcore getBase64: "
431 LOG(ERROR) << "Error while getting Certificate";
436 } // namespace common_installer