[Release] wrt-installer_0.1.92
[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 <dpl/assert.h>
28 #include <appcore-common.h> //TODO is it necessary here?
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/log/log.h>
37 #include <dpl/wrt-dao-ro/global_config.h>
38 #include "wac_widget_id.h"
39
40 #include <vcore/Certificate.h>
41 #include <vcore/SignatureReader.h>
42 #include <vcore/SignatureFinder.h>
43 #include <vcore/WrtSignatureValidator.h>
44 #include <dpl/utils/wrt_global_settings.h>
45 #include <dpl/wrt-dao-ro/global_dao_read_only.h>
46
47 #include <ITapiModem.h>
48 #include <tapi_common.h>
49
50 using namespace ValidationCore;
51 using namespace WrtDB;
52
53 namespace {
54
55 WidgetCertificateData toWidgetCertificateData(const SignatureData &data,
56                                               bool root)
57 {
58     WidgetCertificateData result;
59
60     result.chainId = data.getSignatureNumber();
61     LogDebug("result.chainId : " << result.chainId);
62
63     result.owner = data.isAuthorSignature() ?
64         WidgetCertificateData::AUTHOR : WidgetCertificateData::DISTRIBUTOR;
65
66     result.type = root ?
67         WidgetCertificateData::ROOT : WidgetCertificateData::ENDENTITY;
68
69     CertificatePtr certificate;
70
71     if (root) {
72         certificate = data.getRootCaCertificatePtr();
73     } else {
74         certificate = data.getEndEntityCertificatePtr();
75     }
76
77     Assert(certificate && !certificate->getCommonName().IsNull() &&
78            "CommonName is Null");
79
80     result.strCommonName = *certificate->getCommonName();
81
82     result.strMD5Fingerprint = std::string("md5 ") +
83         Certificate::FingerprintToColonHex(
84             certificate->getFingerprint(Certificate::FINGERPRINT_MD5));
85
86     result.strSHA1Fingerprint = std::string("sha-1 ") +
87         Certificate::FingerprintToColonHex(
88             certificate->getFingerprint(Certificate::FINGERPRINT_SHA1));
89
90     return result;
91 }
92
93 CertificatePtr getOldAuthorSignerCertificate(DPL::String appid)
94 {
95     WidgetDAOReadOnly dao(appid);
96     CertificateChainList chainList = dao.getWidgetCertificate(SIGNATURE_AUTHOR);
97
98     FOREACH(it, chainList)
99     {
100         ValidationCore::CertificateCollection chain;
101         if (false == chain.load(*it)) {
102             LogError("Chain is broken");
103         }
104
105         if (!chain.sort()) {
106             LogError("Chain failed at sorting");
107         }
108
109         ValidationCore::CertificateList list = chain.getCertificateList();
110
111         FOREACH(cert, list)
112         {
113             if (!(*cert)->isRootCert() && !(*cert)->isCA()) {
114                 return *cert;
115             }
116         }
117     }
118     return CertificatePtr(NULL);
119 }
120 } // namespace anonymous
121
122 namespace Jobs {
123 namespace WidgetInstall {
124 TaskCertify::TaskCertify(InstallerContext &inCont) :
125     DPL::TaskDecl<TaskCertify>(this),
126     m_contextData(inCont)
127 {
128     AddStep(&TaskCertify::stepSignature);
129     // certi comparison determines whether the update.
130     if (true == m_contextData.isUpdateMode) {
131         AddStep(&TaskCertify::stepVerifyUpdate);
132     }
133     AddStep(&TaskCertify::stepFinalize);
134 }
135
136 void TaskCertify::processDistributorSignature(const SignatureData &data)
137 {
138     // this signature is verified -
139     // no point in check domain WAC_ROOT and WAC_RECOGNIZED
140     m_contextData.wacSecurity.setDistributorSigned(true);
141
142     CertificateCollection collection;
143     collection.load(data.getCertList());
144     Assert(collection.sort() &&
145            "Certificate collection can't sort");
146
147     Assert(collection.isChain() &&
148            "Certificate collection is not able to create chain. "
149            "It is not possible to verify this signature.");
150
151     m_contextData.wacSecurity.getCertificateChainListRef().push_back(
152         collection);
153
154     if (data.getSignatureNumber() == 1) {
155         m_contextData.wacSecurity.getCertificateListRef().push_back(
156             toWidgetCertificateData(data, true));
157         m_contextData.wacSecurity.getCertificateListRef().push_back(
158             toWidgetCertificateData(data, false));
159     }
160 }
161
162 void TaskCertify::processAuthorSignature(const SignatureData &data)
163 {
164     using namespace ValidationCore;
165     LogInfo("DNS Identity match!");
166     // this signature is verified or widget is distributor signed
167     m_contextData.wacSecurity.setAuthorCertificatePtr(data.getEndEntityCertificatePtr());
168     CertificatePtr test = m_contextData.wacSecurity.getAuthorCertificatePtr();
169
170     m_contextData.wacSecurity.getCertificateListRef().push_back(
171         toWidgetCertificateData(data, true));
172     m_contextData.wacSecurity.getCertificateListRef().push_back(
173         toWidgetCertificateData(data, false));
174
175     // match widget_id with one from dns identity set
176     WacWidgetId widgetId(m_contextData.widgetConfig.configInfo.widget_id);
177
178     CertificatePtr cert = data.getEndEntityCertificatePtr();
179     Assert(cert);
180     Certificate::AltNameSet dnsIdentity = cert->getAlternativeNameDNS();
181
182     CertificateCollection collection;
183     collection.load(data.getCertList());
184     collection.sort();
185     Assert(collection.isChain() &&
186            "Certificate collection is not able to create chain. "
187            "It is not possible to verify this signature.");
188
189     m_contextData.wacSecurity.getAuthorsCertificateChainListRef().push_back(
190         collection);
191
192     FOREACH(it, dnsIdentity){
193         if (widgetId.matchHost(*it)) {
194             m_contextData.wacSecurity.setRecognized(true);
195             return;
196         }
197     }
198 }
199
200 void TaskCertify::getSignatureFiles(std::string path, SignatureFileInfoSet& file)
201 {
202     LogDebug("path : " << path);
203     SignatureFileInfoSet signatureFiles;
204     SignatureFinder signatureFinder(path);
205     if (SignatureFinder::NO_ERROR != signatureFinder.find(file)) {
206         LogError("Error in Signature Finder : " << path);
207         ThrowMsg(Exceptions::SignatureNotFound,
208                 "Error openig temporary widget directory");
209     }
210 }
211
212 void TaskCertify::stepSignature()
213 {
214     LogInfo("================ Step: <<Signature>> ENTER ===============");
215
216     std::string widgetPath;
217     widgetPath = m_contextData.locations->getTemporaryPackageDir() + "/";
218
219     if (m_contextData.mode.command ==
220             InstallMode::Command::REINSTALL)
221     {
222         widgetPath = m_contextData.locations->getPackageInstallationDir() + "/";
223     }
224
225     SignatureFileInfoSet signatureFiles;
226
227     Try {
228         getSignatureFiles(widgetPath, signatureFiles);
229
230         if (signatureFiles.size() <= 0) {
231             widgetPath += std::string(WrtDB::GlobalConfig::GetWidgetSrcPath())
232                 + "/";
233             if (0 == access(widgetPath.c_str(), F_OK)) {
234                 getSignatureFiles(widgetPath, signatureFiles);
235             }
236         }
237     } Catch(Exceptions::SignatureNotFound) {
238         ReThrowMsg(Exceptions::SignatureNotFound, widgetPath);
239     }
240
241     SignatureFileInfoSet::reverse_iterator iter = signatureFiles.rbegin();
242     LogInfo("Number of signatures: " << signatureFiles.size());
243
244     bool complianceMode = GlobalDAOReadOnly::getComplianceMode();
245
246     for (; iter != signatureFiles.rend(); ++iter) {
247         LogInfo("Checking signature with id=" << 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::AppType appType =
257                 WrtSignatureValidator::WAC20;
258
259             if (m_contextData.widgetConfig.webAppType ==
260                 APP_TYPE_TIZENWEBAPP)
261             {
262                 appType = WrtSignatureValidator::TIZEN;
263             }
264
265             WrtSignatureValidator::Result result;
266
267             WrtSignatureValidator validator(
268                     appType,
269                     !GlobalSettings::
270                     OCSPTestModeEnabled(),
271                     !GlobalSettings::
272                     CrlTestModeEnabled(),
273                     complianceMode);
274
275             result = validator.check(data, widgetPath);
276
277             if (m_contextData.mode.installTime
278                 ==  InstallMode::InstallTime::PRELOAD)
279             {
280                 result = WrtSignatureValidator::SIGNATURE_VERIFIED;
281             }
282
283             if (result == WrtSignatureValidator::SIGNATURE_REVOKED) {
284                 LogWarning("Certificate is REVOKED");
285                 ThrowMsg(Exceptions::CertificateExpired,
286                          "Certificate is REVOKED");
287             }
288
289             if (result == WrtSignatureValidator::SIGNATURE_INVALID &&
290                     iter->getFileNumber() <= 1) {
291                 LogWarning("Signature is INVALID");
292                 // TODO change exception name
293                 ThrowMsg(Exceptions::SignatureInvalid,
294                          "Invalid Package");
295             }
296
297             if (data.isAuthorSignature()) {
298                 if (result == WrtSignatureValidator::SIGNATURE_VERIFIED ) {
299                     processAuthorSignature(data);
300                 }
301             } else {
302                 if (result != WrtSignatureValidator::SIGNATURE_INVALID) {
303                     processDistributorSignature(data);
304                 }
305             }
306         } Catch(ParserSchemaException::Base) {
307             LogError("Error occured in ParserSchema.");
308             ReThrowMsg(Exceptions::SignatureInvalid,
309                        "Error occured in ParserSchema.");
310         }
311     }
312
313     if (signatureFiles.empty()) {
314         LogInfo("No signature files has been found.");
315     }
316
317     LogInfo("================ Step: <<Signature>> DONE ================");
318
319     m_contextData.job->UpdateProgress(
320         InstallerContext::INSTALL_DIGSIG_CHECK,
321         "Widget Signature checked");
322 }
323
324 void TaskCertify::stepFinalize()
325 {
326     LogInfo("Step: <<CERTYFYING DONE>>");
327
328     m_contextData.job->UpdateProgress(
329         InstallerContext::INSTALL_CERT_CHECK,
330         "Widget Certification Check Finished");
331 }
332
333 bool TaskCertify::isTizenWebApp() const
334 {
335     bool ret = FALSE;
336     if (m_contextData.widgetConfig.webAppType.appType
337         == WrtDB::AppType::APP_TYPE_TIZENWEBAPP)
338     {
339         ret = TRUE;
340     }
341
342     return ret;
343 }
344
345 void TaskCertify::stepVerifyUpdate()
346 {
347     LogInfo("Step: <<Check Update>>");
348     CertificatePtr newCertificate =
349         m_contextData.wacSecurity.getAuthorCertificatePtr();
350     CertificatePtr oldCertificate =
351         getOldAuthorSignerCertificate(m_contextData.widgetConfig.tzAppid);
352
353     if (!!newCertificate && !!oldCertificate) {
354         if (0 != newCertificate->getBase64().compare(oldCertificate->getBase64())) {
355             LogDebug("old widget's author signer certificate : " <<
356                     oldCertificate->getBase64());
357             LogDebug("new widget's author signer certificate : " <<
358                     newCertificate->getBase64());
359             ThrowMsg(Exceptions::NotMatchedCertification,
360                     "Author signer certificates doesn't match \
361                     between old widget and installing widget");
362         }
363     } else {
364         if (!(NULL == newCertificate.Get() && NULL == oldCertificate.Get())) {
365             ThrowMsg(Exceptions::NotMatchedCertification,
366                     "Author signer certificates doesn't match \
367                     between old widget and installing widget");
368         }
369     }
370 }
371 } //namespace WidgetInstall
372 } //namespace Jobs
373