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 <vcore/Certificate.h>
8 #include <vcore/SignatureValidator.h>
16 #include "common/privileges.h"
17 #include "common/utils/base64.h"
18 #include "common/utils/file_util.h"
19 #include "common/utils/glist_range.h"
21 namespace ci = common_installer;
22 namespace fs = std::filesystem;
26 const char kSignatureAuthor[] = "author-signature.xml";
27 const char kRegexDistributorSignature[] = "^(signature)([1-9][0-9]*)(\\.xml)";
29 static bool SetCertificate(const ValidationCore::SignatureData& data,
30 Property<ValidationCore::CertificatePtr>* certificate,
31 Property<ValidationCore::CertificatePtr>* intermediate_certificate,
32 Property<ValidationCore::CertificatePtr>* root_certificate,
33 bool intermediate_mandatory) {
34 ValidationCore::CertificateList cert_list = data.getCertList();
35 ValidationCore::CertificateList::iterator it = cert_list.begin();
36 if (it == cert_list.end()) {
37 LOG(ERROR) << "No certificates in certificate list";
40 certificate->set(*it);
42 if (it == cert_list.end()) {
43 if (intermediate_mandatory) {
44 LOG(ERROR) << "No intermediate certificates in certificate list";
47 intermediate_certificate->set({});
50 intermediate_certificate->set(*it);
52 root_certificate->set(data.getRootCaCertificatePtr());
56 static bool SetAuthorCertificate(const ValidationCore::SignatureData& data,
57 common_installer::CertificateInfo* cert_info) {
58 ValidationCore::CertificateList cert_list = data.getCertList();
59 ValidationCore::CertificateList::iterator it = cert_list.begin();
60 if (it == cert_list.end()) {
61 LOG(ERROR) << "No certificates in certificate list";
64 unsigned char* public_key = nullptr;
66 (*it)->getPublicKeyDER(&public_key, &len);
67 std::string author_id =
68 ci::EncodeBase64(public_key, len);
69 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 fs::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 fs::path file_path(file_info.getFileName());
229 return std::regex_search(file_path.filename().string(), distributor_regex);
232 bool ValidateSignatures(const fs::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 fs::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 void FreePrivilegeList(GList* priv) {
334 g_list_free_full(priv, free);
337 bool ValidatePrivilegeLevel(common_installer::PrivilegeLevel level,
338 uid_t uid, const char* api_version, GList* privileges,
339 std::string* error_message) {
340 if (level == common_installer::PrivilegeLevel::UNTRUSTED) {
342 LOG(ERROR) << "Untrusted application cannot declare privileges";
349 GList* native_privileges =
350 ci::PrivilegeXToPrivilege(privileges, ci::kNativePrivilegeType);
351 std::unique_ptr<GList, decltype(FreePrivilegeList)*> native_privs_deleter(
352 native_privileges, FreePrivilegeList);
353 GList* web_privileges =
354 ci::PrivilegeXToPrivilege(privileges, ci::kWebPrivilegeType);
355 std::unique_ptr<GList, decltype(FreePrivilegeList)*> web_privs_deleter(
356 web_privileges, FreePrivilegeList);
358 for (const std::pair<GList*, bool>& pair :
359 std::initializer_list<std::pair<GList*, bool>>{
360 {native_privileges, false},
361 {web_privileges, true}
363 char* error = nullptr;
364 int status = PRVMGR_ERR_NONE;
365 // Do the privilege check only if the package has privileges
367 status = privilege_manager_verify_privilege(uid, api_version,
368 pair.second ? PRVMGR_PACKAGE_TYPE_WRT : PRVMGR_PACKAGE_TYPE_CORE,
369 pair.first, PrivilegeLevelToVisibility(level), &error);
371 if (status != PRVMGR_ERR_NONE) {
372 std::string errnum = std::to_string(status);
374 *error_message = error;
377 LOG(ERROR) << "Error while verifing privilege level: "
378 << *error_message << " <" << errnum << ">";
379 *error_message += ":<" + errnum + ">";
384 LOG(INFO) << "Privilege level checked";
388 bool ValidateMetadataPrivilege(common_installer::PrivilegeLevel level,
389 const char* api_version, GList* metadata_list,
390 std::string* error_message) {
393 char* error = nullptr;
394 int status = PRVMGR_ERR_NONE;
396 GList *metadata_keylist = NULL;
397 for (metadata_x* meta : GListRange<metadata_x*>(metadata_list))
398 metadata_keylist = g_list_append(metadata_keylist, meta->key);
400 status = privilege_manager_verify_metadata(api_version, metadata_keylist,
401 PrivilegeLevelToVisibility(level), &error);
403 if (metadata_keylist)
404 g_list_free(metadata_keylist);
406 if (status != PRVMGR_ERR_NONE) {
407 std::string errnum = std::to_string(status);
409 *error_message = error;
412 LOG(ERROR) << "Error while verifing metadata privilege: "
413 << *error_message << " <" << errnum << ">";
414 *error_message += ":<" + errnum + ">";
421 bool IsSameAuthor(const std::string& cert_str1, const std::string& cert_str2) {
423 ValidationCore::Certificate cert1 = ValidationCore::Certificate(
424 cert_str1, ValidationCore::Certificate::FormType::FORM_BASE64);
425 ValidationCore::Certificate cert2 = ValidationCore::Certificate(
426 cert_str2, ValidationCore::Certificate::FormType::FORM_BASE64);
427 return cert1.getPublicKeyString() == cert2.getPublicKeyString();
428 } catch (const ValidationCore::Certificate::Exception::Base &e) {
429 LOG(ERROR) << "Exception occured on cert-svc-vcore getBase64: "
433 LOG(ERROR) << "Error while getting Certificate";
438 } // namespace common_installer