Rename invalid WRT_SMACK_LABEL macro to WRT_SMACK_ENABLED
[platform/framework/web/wrt-installer.git] / src / jobs / widget_install / task_certify.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @file    task_certify.cpp
18  * @author  Pawel Sikorski (p.sikorski@samgsung.com)
19  * @version
20  * @brief
21  */
22
23 //SYSTEM INCLUDES
24 #include <cstring>
25 #include <string>
26 #include <sstream>
27 #include <unistd.h>
28 #include <dpl/assert.h>
29 #include <pcrecpp.h>
30
31 //WRT INCLUDES
32 #include <widget_install/task_certify.h>
33 #include <widget_install/job_widget_install.h>
34 #include <widget_install/widget_install_errors.h>
35 #include <widget_install/widget_install_context.h>
36 #include <dpl/wrt-dao-ro/global_config.h>
37 #include "wac_widget_id.h"
38
39 #include <vcore/Certificate.h>
40 #include <vcore/SignatureReader.h>
41 #include <vcore/SignatureFinder.h>
42 #include <vcore/WrtSignatureValidator.h>
43 #include <dpl/utils/wrt_global_settings.h>
44 #include <dpl/wrt-dao-ro/global_dao_read_only.h>
45
46 #include <ITapiModem.h>
47 #include <tapi_common.h>
48
49 #include <installer_log.h>
50
51 using namespace ValidationCore;
52 using namespace WrtDB;
53
54 namespace {
55
56 WidgetCertificateData toWidgetCertificateData(const SignatureData &data,
57                                               bool root)
58 {
59     WidgetCertificateData result;
60
61     result.chainId = data.getSignatureNumber();
62     _D("result.chainId : %d", result.chainId);
63
64     result.owner = data.isAuthorSignature() ?
65         WidgetCertificateData::AUTHOR : WidgetCertificateData::DISTRIBUTOR;
66
67     result.type = root ?
68         WidgetCertificateData::ROOT : WidgetCertificateData::ENDENTITY;
69
70     CertificatePtr certificate;
71
72     if (root) {
73         certificate = data.getRootCaCertificatePtr();
74     } else {
75         certificate = data.getEndEntityCertificatePtr();
76     }
77
78     Assert(certificate && !certificate->getCommonName().IsNull() &&
79            "CommonName is Null");
80
81     result.strCommonName = *certificate->getCommonName();
82
83     result.strMD5Fingerprint = std::string("md5 ") +
84         Certificate::FingerprintToColonHex(
85             certificate->getFingerprint(Certificate::FINGERPRINT_MD5));
86
87     result.strSHA1Fingerprint = std::string("sha-1 ") +
88         Certificate::FingerprintToColonHex(
89             certificate->getFingerprint(Certificate::FINGERPRINT_SHA1));
90
91     return result;
92 }
93
94 CertificatePtr getOldAuthorSignerCertificate(DPL::String appid)
95 {
96     WidgetDAOReadOnly dao(appid);
97     CertificateChainList chainList = dao.getWidgetCertificate(SIGNATURE_AUTHOR);
98
99     FOREACH(it, chainList)
100     {
101         ValidationCore::CertificateCollection chain;
102         if (false == chain.load(*it)) {
103             _E("Chain is broken");
104         }
105
106         if (!chain.sort()) {
107             _E("Chain failed at sorting");
108         }
109
110         ValidationCore::CertificateList list = chain.getCertificateList();
111
112         FOREACH(cert, list)
113         {
114             if (!(*cert)->isRootCert() && !(*cert)->isCA()) {
115                 return *cert;
116             }
117         }
118     }
119     return CertificatePtr(NULL);
120 }
121 } // namespace anonymous
122
123 namespace Jobs {
124 namespace WidgetInstall {
125 TaskCertify::TaskCertify(InstallerContext &inCont) :
126     DPL::TaskDecl<TaskCertify>(this),
127     m_contextData(inCont)
128 {
129     AddStep(&TaskCertify::StartStep);
130     AddStep(&TaskCertify::stepSignature);
131     // certi comparison determines whether the update.
132     if (true == m_contextData.isUpdateMode) {
133         AddStep(&TaskCertify::stepVerifyUpdate);
134     }
135     AddStep(&TaskCertify::EndStep);
136 }
137
138 void TaskCertify::processDistributorSignature(const SignatureData &data)
139 {
140     // this signature is verified -
141     // no point in check domain WAC_ROOT and WAC_RECOGNIZED
142     m_contextData.widgetSecurity.setDistributorSigned(true);
143
144     CertificateCollection collection;
145     collection.load(data.getCertList());
146     Assert(collection.sort() &&
147            "Certificate collection can't sort");
148
149     Assert(collection.isChain() &&
150            "Certificate collection is not able to create chain. "
151            "It is not possible to verify this signature.");
152
153     m_contextData.widgetSecurity.getCertificateChainListRef().push_back(
154         collection);
155
156     if (data.getSignatureNumber() == 1) {
157         m_contextData.widgetSecurity.getCertificateListRef().push_back(
158             toWidgetCertificateData(data, true));
159         m_contextData.widgetSecurity.getCertificateListRef().push_back(
160             toWidgetCertificateData(data, false));
161     }
162 }
163
164 void TaskCertify::processAuthorSignature(const SignatureData &data)
165 {
166     using namespace ValidationCore;
167     _D("DNS Identity match!");
168     // this signature is verified or widget is distributor signed
169     m_contextData.widgetSecurity.setAuthorCertificatePtr(data.getEndEntityCertificatePtr());
170     CertificatePtr test = m_contextData.widgetSecurity.getAuthorCertificatePtr();
171
172     m_contextData.widgetSecurity.getCertificateListRef().push_back(
173         toWidgetCertificateData(data, true));
174     m_contextData.widgetSecurity.getCertificateListRef().push_back(
175         toWidgetCertificateData(data, false));
176
177     // match widget_id with one from dns identity set
178     WacWidgetId widgetId(m_contextData.widgetConfig.configInfo.widget_id);
179
180     CertificatePtr cert = data.getEndEntityCertificatePtr();
181     Assert(cert);
182     Certificate::AltNameSet dnsIdentity = cert->getAlternativeNameDNS();
183
184     CertificateCollection collection;
185     collection.load(data.getCertList());
186     collection.sort();
187     Assert(collection.isChain() &&
188            "Certificate collection is not able to create chain. "
189            "It is not possible to verify this signature.");
190
191     m_contextData.widgetSecurity.getAuthorsCertificateChainListRef().push_back(
192         collection);
193
194     FOREACH(it, dnsIdentity){
195         if (widgetId.matchHost(*it)) {
196             m_contextData.widgetSecurity.setRecognized(true);
197             return;
198         }
199     }
200 }
201
202 void TaskCertify::getSignatureFiles(std::string path, SignatureFileInfoSet& file)
203 {
204     _D("path : %s", path.c_str());
205     SignatureFileInfoSet signatureFiles;
206     SignatureFinder signatureFinder(path);
207     if (SignatureFinder::NO_ERROR != signatureFinder.find(file)) {
208         _E("Error in Signature Finder : %s", path.c_str());
209         ThrowMsg(Exceptions::SignatureNotFound,
210                 "Error openig temporary widget directory");
211     }
212 }
213
214 void TaskCertify::stepSignature()
215 {
216     _D("================ Step: <<Signature>> ENTER ===============");
217
218     std::string widgetPath;
219     widgetPath = m_contextData.locations->getTemporaryPackageDir() + "/";
220
221     if (m_contextData.mode.command ==
222             InstallMode::Command::REINSTALL)
223     {
224         widgetPath = m_contextData.locations->getPackageInstallationDir() + "/";
225     }
226
227     SignatureFileInfoSet signatureFiles;
228
229     Try {
230         getSignatureFiles(widgetPath, signatureFiles);
231
232         if (signatureFiles.size() <= 0) {
233             widgetPath += std::string(WrtDB::GlobalConfig::GetWidgetSrcPath())
234                 + "/";
235             if (0 == access(widgetPath.c_str(), F_OK)) {
236                 getSignatureFiles(widgetPath, signatureFiles);
237             }
238         }
239     } Catch(Exceptions::SignatureNotFound) {
240         ReThrowMsg(Exceptions::SignatureNotFound, widgetPath);
241     }
242
243     SignatureFileInfoSet::reverse_iterator iter = signatureFiles.rbegin();
244     _D("Number of signatures: %d", signatureFiles.size());
245
246     for (; iter != signatureFiles.rend(); ++iter) {
247         _D("Checking signature with id=%d", iter->getFileNumber());
248         SignatureData data(widgetPath + iter->getFileName(),
249                            iter->getFileNumber());
250
251         Try {
252             SignatureReader xml;
253             xml.initialize(data, GlobalConfig::GetSignatureXmlSchema());
254             xml.read(data);
255
256             WrtSignatureValidator::Result result;
257
258             WrtSignatureValidator validator(
259                     WrtSignatureValidator::TIZEN,
260                     !GlobalSettings::
261                     OCSPTestModeEnabled(),
262                     !GlobalSettings::
263                     CrlTestModeEnabled(),
264                     false);
265
266             result = validator.check(data, widgetPath);
267
268             if (m_contextData.mode.installTime
269                 ==  InstallMode::InstallTime::PRELOAD)
270             {
271                 result = WrtSignatureValidator::SIGNATURE_VERIFIED;
272             }
273
274             if (result == WrtSignatureValidator::SIGNATURE_REVOKED) {
275                 _W("Certificate is REVOKED");
276                 ThrowMsg(Exceptions::CertificateExpired,
277                          "Certificate is REVOKED");
278             }
279
280             if (result == WrtSignatureValidator::SIGNATURE_INVALID &&
281                     iter->getFileNumber() <= 1) {
282                 _W("Signature is INVALID");
283                 // TODO change exception name
284                 ThrowMsg(Exceptions::SignatureInvalid,
285                          "Invalid Package");
286             }
287
288             if (data.isAuthorSignature()) {
289                 if (result == WrtSignatureValidator::SIGNATURE_VERIFIED ) {
290                     processAuthorSignature(data);
291                 }
292             } else {
293                 if (result != WrtSignatureValidator::SIGNATURE_INVALID) {
294                     processDistributorSignature(data);
295                 }
296             }
297         } Catch(ParserSchemaException::Base) {
298             _E("Error occured in ParserSchema.");
299             ReThrowMsg(Exceptions::SignatureInvalid,
300                        "Error occured in ParserSchema.");
301         }
302     }
303
304     if (signatureFiles.empty()) {
305         _D("No signature files has been found.");
306     }
307
308     _D("================ Step: <<Signature>> DONE ================");
309
310     m_contextData.job->UpdateProgress(
311         InstallerContext::INSTALL_DIGSIG_CHECK,
312         "Widget Signature checked");
313 }
314
315 bool TaskCertify::isTizenWebApp() const
316 {
317     bool ret = FALSE;
318     if (m_contextData.widgetConfig.webAppType.appType
319         == WrtDB::AppType::APP_TYPE_TIZENWEBAPP)
320     {
321         ret = TRUE;
322     }
323
324     return ret;
325 }
326
327 void TaskCertify::stepVerifyUpdate()
328 {
329     _D("Step: <<Check Update>>");
330     CertificatePtr newCertificate =
331         m_contextData.widgetSecurity.getAuthorCertificatePtr();
332     CertificatePtr oldCertificate =
333         getOldAuthorSignerCertificate(m_contextData.widgetConfig.tzAppid);
334
335     if (!!newCertificate && !!oldCertificate) {
336         if (0 != newCertificate->getBase64().compare(oldCertificate->getBase64())) {
337             _D("old widget's author signer certificate : %s", (oldCertificate->getBase64()).c_str());
338             _D("new widget's author signer certificate : %s", (newCertificate->getBase64()).c_str());
339             ThrowMsg(Exceptions::NotMatchedCertification,
340                     "Author signer certificates doesn't match \
341                     between old widget and installing widget");
342         }
343     } else {
344         if (!(NULL == newCertificate.Get() && NULL == oldCertificate.Get())) {
345             ThrowMsg(Exceptions::NotMatchedCertification,
346                     "Author signer certificates doesn't match \
347                     between old widget and installing widget");
348         }
349     }
350 }
351
352 void TaskCertify::StartStep()
353 {
354     _D("--------- <TaskCertify> : START ----------");
355 }
356
357 void TaskCertify::EndStep()
358 {
359     _D("Step: <<CERTYFYING DONE>>");
360
361     m_contextData.job->UpdateProgress(
362         InstallerContext::INSTALL_CERT_CHECK,
363         "Widget Certification Check Finished");
364
365     _D("--------- <TaskCertify> : END ----------");
366 }
367 } //namespace WidgetInstall
368 } //namespace Jobs
369