Remove boost dependency
[platform/core/appfw/app-installers.git] / src / common / certificate_validation.cc
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.
4
5 #include "common/certificate_validation.h"
6
7 #include <vcore/Certificate.h>
8 #include <vcore/SignatureValidator.h>
9
10 #include <algorithm>
11 #include <filesystem>
12 #include <fstream>
13 #include <regex>
14 #include <utility>
15
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"
20
21 namespace ci = common_installer;
22 namespace fs = std::filesystem;
23
24 namespace {
25
26 const char kSignatureAuthor[] = "author-signature.xml";
27 const char kRegexDistributorSignature[] = "^(signature)([1-9][0-9]*)(\\.xml)";
28
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";
38     return false;
39   }
40   certificate->set(*it);
41   ++it;
42   if (it == cert_list.end()) {
43     if (intermediate_mandatory) {
44       LOG(ERROR) << "No intermediate certificates in certificate list";
45       return false;
46     } else {
47       intermediate_certificate->set({});
48     }
49   } else {
50     intermediate_certificate->set(*it);
51   }
52   root_certificate->set(data.getRootCaCertificatePtr());
53   return true;
54 }
55
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";
62     return false;
63   }
64   unsigned char* public_key = nullptr;
65   size_t len;
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);
70   free(public_key);
71
72   return SetCertificate(data,
73       &cert_info->auth_cert,
74       &cert_info->auth_im_cert,
75       &cert_info->auth_root_cert,
76       true);
77 }
78
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,
85       true);
86 }
87
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,
94       false);
95 }
96
97 bool SetSignature(std::ifstream* ifs,
98     ValidationCore::CertificatePtr* certificate,
99     std::string* cert_str) {
100   std::string cert;
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);
108   }
109
110   return true;
111 }
112
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) {
118
119   SetSignature(ifs, cert, root_cert_str);
120   SetSignature(ifs, im_cert, root_cert_str);
121   SetSignature(ifs, root_cert, root_cert_str);
122   return true;
123 }
124
125 }  // namespace
126
127 namespace common_installer {
128
129 common_installer::PrivilegeLevel CertStoreIdToPrivilegeLevel(
130     ValidationCore::CertStoreId::Type id) {
131   switch (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;
138     default:
139       return common_installer::PrivilegeLevel::UNTRUSTED;
140   }
141 }
142
143 privilege_manager_visibility_e PrivilegeLevelToVisibility(
144     common_installer::PrivilegeLevel level) {
145   switch (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;
152     default:
153       assert(false && "Not reached");
154   }
155 }
156
157 void SetPrivilegeLevel(const ValidationCore::SignatureData& data,
158     common_installer::PrivilegeLevel* level) {
159   // already set
160   if (*level != common_installer::PrivilegeLevel::UNTRUSTED)
161     return;
162   *level = CertStoreIdToPrivilegeLevel(data.getVisibilityLevel());
163 }
164
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();
172
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);
178   } else {
179     result = validator.checkList(true, ValidationCore::UriList(), data);
180   }
181
182   std::string errnum = std::to_string(result);
183   *error_message = validator.errorToString(result);
184   *error_message += ":<" + errnum + ">";
185
186   switch (result) {
187     case ValidationCore::E_SIG_REVOKED:
188       LOG(ERROR) << "Certificate is revoked";
189       return false;
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))
195           return false;
196       }
197       break;
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))
202           return false;
203       } else if (file_info.getFileNumber() == 1) {
204         // First distributor signature sets the privilege level
205         // (wrt spec. 0620.)
206         SetPrivilegeLevel(data, level);
207         if (!SetDistributorCertificate(data, cert_info))
208           return false;
209       } else if (file_info.getFileNumber() == 2) {
210         if (!SetDistributor2Certificate(data, cert_info))
211           return false;
212       }
213       break;
214     default:
215       LOG(ERROR) << "signature validation check failed : "
216                  << validator.errorToString(result);
217       return false;
218   }
219   return true;
220 }
221
222 bool CheckAuthorSignature(const ValidationCore::SignatureFileInfo& file_info) {
223   return file_info.getFileName().find(kSignatureAuthor) != std::string::npos;
224 }
225
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);
230 }
231
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";
241     return false;
242   }
243   LOG(INFO) << "Number of signature files: " << signature_files.size();
244
245   bool author_signatures = std::any_of(
246       signature_files.begin(), signature_files.end(), CheckAuthorSignature);
247
248   bool distributor_signatures = std::any_of(
249       signature_files.begin(), signature_files.end(), CheckDistSignature);
250
251   if (getuid() != 0 && (!author_signatures || !distributor_signatures) &&
252       check_reference) {
253     LOG(ERROR) << "Author or distribuor signature is missing.";
254     return false;
255   }
256
257   // Read xml schema for signatures
258   for (auto& file_info : signature_files) {
259     std::string error;
260     if (!ValidateSignatureFile(base_path, file_info, level,
261                                cert_info, check_reference, &error)) {
262       *error_message = error;
263       return false;
264     }
265   }
266   return true;
267 }
268
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;
276
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;
283     return false;
284   }
285
286   if (!ReadSignature(&ifs,
287           &cert_info->dist2_cert.get(),
288           &cert_info->dist2_im_cert.get(),
289           &cert_info->dist2_root_cert.get(),
290           &root_cert) ||
291       !ReadSignature(&ifs,
292           &cert_info->dist_cert.get(),
293           &cert_info->dist_im_cert.get(),
294           &cert_info->dist_root_cert.get(),
295           &root_cert))
296     return false;
297   if (root_cert.length() == 0) {
298       LOG(INFO) << "Dist root cert not exists";
299       return false;
300   }
301
302   int ret = certsvc_instance_new(&instance);
303   if (ret != CERTSVC_SUCCESS) {
304     LOG(ERROR) << "certsvc_instance_new failed :" << ret;
305     return false;
306   }
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,
311       &certificate);
312   if (ret != CERTSVC_SUCCESS) {
313     LOG(ERROR) << "certsvc_certificate_new_from_memory failed :" << ret;
314     certsvc_instance_free(instance);
315     return false;
316   }
317
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);
323     return false;
324   }
325
326   certsvc_certificate_free(certificate);
327   certsvc_instance_free(instance);
328   *level = CertStoreIdToPrivilegeLevel(visibility);
329
330   return true;
331 }
332
333 void FreePrivilegeList(GList* priv) {
334   g_list_free_full(priv, free);
335 }
336
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) {
341     if (privileges) {
342       LOG(ERROR) << "Untrusted application cannot declare privileges";
343       return false;
344     } else {
345       return true;
346     }
347   }
348
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);
357
358   for (const std::pair<GList*, bool>& pair :
359        std::initializer_list<std::pair<GList*, bool>>{
360         {native_privileges, false},
361         {web_privileges, true}
362       }) {
363     char* error = nullptr;
364     int status = PRVMGR_ERR_NONE;
365     // Do the privilege check only if the package has privileges
366     if (pair.first) {
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);
370     }
371     if (status != PRVMGR_ERR_NONE) {
372       std::string errnum = std::to_string(status);
373       if (error)
374         *error_message = error;
375       else
376         *error_message = "";
377       LOG(ERROR) << "Error while verifing privilege level: "
378                  << *error_message << " <" << errnum << ">";
379       *error_message += ":<" + errnum + ">";
380       free(error);
381       return false;
382     }
383   }
384   LOG(INFO) << "Privilege level checked";
385   return true;
386 }
387
388 bool ValidateMetadataPrivilege(common_installer::PrivilegeLevel level,
389     const char* api_version, GList* metadata_list,
390     std::string* error_message) {
391   if (!metadata_list)
392     return true;
393   char* error = nullptr;
394   int status = PRVMGR_ERR_NONE;
395
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);
399
400   status = privilege_manager_verify_metadata(api_version, metadata_keylist,
401           PrivilegeLevelToVisibility(level), &error);
402
403   if (metadata_keylist)
404     g_list_free(metadata_keylist);
405
406   if (status != PRVMGR_ERR_NONE) {
407       std::string errnum = std::to_string(status);
408       if (error)
409         *error_message = error;
410       else
411         *error_message = "";
412       LOG(ERROR) << "Error while verifing metadata privilege: "
413                  << *error_message << " <" << errnum << ">";
414       *error_message += ":<" + errnum + ">";
415       free(error);
416       return false;
417   }
418   return true;
419 }
420
421 bool IsSameAuthor(const std::string& cert_str1, const std::string& cert_str2) {
422   try {
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: "
430                << e.DumpToString();
431     return false;
432   } catch (...) {
433     LOG(ERROR) << "Error while getting Certificate";
434     return false;
435   }
436 }
437
438 }  // namespace common_installer