342b5f4de7ec4385b0a18ccdecfacc20ff15a6c5
[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 <dpl/assert.h>
27 #include <appcore-common.h> //TODO is it necessary here?
28 #include <pcrecpp.h>
29
30 //WRT INCLUDES
31 #include <widget_install/task_certify.h>
32 #include <widget_install/job_widget_install.h>
33 #include <widget_install/widget_install_errors.h>
34 #include <widget_install/widget_install_context.h>
35 #include <dpl/log/log.h>
36 #include <wrt_error.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 <vcore/DeveloperModeValidator.h>
45 #include <dpl/utils/wrt_global_settings.h>
46 #include <dpl/wrt-dao-ro/global_dao_read_only.h>
47
48 #include <ITapiModem.h>
49 #include <tapi_common.h>
50
51 using namespace ValidationCore;
52 using namespace WrtDB;
53
54 namespace {
55 const std::string LABEL_NEW_LINE = "<br>";
56 const std::string LABEL_NEW_LINE_2 = "<br><br>";
57 const std::string UNTRUSTED_WIDGET = "It is an Untrusted Widget";
58 const char *QUESTION = "Do you wanto to install?";
59
60 WidgetCertificateData toWidgetCertificateData(const SignatureData &data,
61                                               bool root)
62 {
63     WidgetCertificateData result;
64
65     result.chainId = data.getSignatureNumber();
66
67     result.owner = data.isAuthorSignature() ?
68         WidgetCertificateData::AUTHOR : WidgetCertificateData::DISTRIBUTOR;
69
70     result.type = root ?
71         WidgetCertificateData::ROOT : WidgetCertificateData::ENDENTITY;
72
73     CertificatePtr certificate;
74
75     if (root) {
76         certificate = data.getRootCaCertificatePtr();
77     } else {
78         certificate = data.getEndEntityCertificatePtr();
79     }
80
81     Assert(certificate && !certificate->getCommonName().IsNull() &&
82            "CommonName is Null");
83
84     result.strCommonName = *certificate->getCommonName();
85
86     result.strMD5Fingerprint = std::string("md5 ") +
87         Certificate::FingerprintToColonHex(
88             certificate->getFingerprint(Certificate::FINGERPRINT_MD5));
89
90     result.strSHA1Fingerprint = std::string("sha-1 ") +
91         Certificate::FingerprintToColonHex(
92             certificate->getFingerprint(Certificate::FINGERPRINT_SHA1));
93
94     return result;
95 }
96 } // namespace anonymous
97
98 namespace Jobs {
99 namespace WidgetInstall {
100 TaskCertify::TaskCertify(InstallerContext &inCont) :
101     DPL::TaskDecl<TaskCertify>(this),
102     m_contextData(inCont),
103     WidgetInstallPopup(inCont)
104 {
105     AddStep(&TaskCertify::stepSignature);
106
107     // Block until fixed popup issues
108     if (!GlobalSettings::PopupsTestModeEnabled()
109         && !m_installContext.m_quiet && !isTizenWebApp())
110     {
111         AddStep(&TaskCertify::stepWarningPopup);
112         AddStep(&TaskCertify::stepWarningPopupAnswer);
113         AddStep(&TaskCertify::stepAuthorInfoPopup);
114         AddStep(&TaskCertify::stepAuthorInfoPopupAnswer);
115         AddStep(&TaskCertify::StepDeletePopupWin);
116     }
117     AddStep(&TaskCertify::stepFinalize);
118 }
119
120 void TaskCertify::processDistributorSignature(const SignatureData &data,
121                                               bool first)
122 {
123     // this signature is verified -
124     // no point in check domain WAC_ROOT and WAC_RECOGNIZED
125     m_contextData.wacSecurity.setDistributorSigned(true);
126
127     if (data.getStorageType().contains(CertStoreId::WAC_ROOT)) {
128         m_contextData.wacSecurity.setWacSigned(true);
129     }
130
131     CertificateCollection collection;
132     collection.load(data.getCertList());
133     Assert(collection.sort() &&
134            "Certificate collection can't sort");
135
136     Assert(collection.isChain() &&
137            "Certificate collection is not able to create chain. "
138            "It is not possible to verify this signature.");
139
140     m_contextData.wacSecurity.getCertificateChainListRef().push_back(
141         collection);
142
143     if (first) {
144         m_contextData.wacSecurity.getCertificateListRef().push_back(
145             toWidgetCertificateData(data, true));
146         m_contextData.wacSecurity.getCertificateListRef().push_back(
147             toWidgetCertificateData(data, false));
148     }
149 }
150
151 void TaskCertify::processAuthorSignature(const SignatureData &data)
152 {
153     using namespace ValidationCore;
154     LogInfo("DNS Identity match!");
155     // this signature is verified or widget is distributor signed
156     m_contextData.wacSecurity.getAuthorCertificatePtr() =
157         data.getEndEntityCertificatePtr();
158     m_contextData.wacSecurity.getCertificateListRef().push_back(
159         toWidgetCertificateData(data, true));
160     m_contextData.wacSecurity.getCertificateListRef().push_back(
161         toWidgetCertificateData(data, false));
162
163     // match widget_id with one from dns identity set
164     WacWidgetId widgetId(m_contextData.widgetConfig.configInfo.widget_id);
165
166     CertificatePtr cert = data.getEndEntityCertificatePtr();
167     Assert(cert);
168     Certificate::AltNameSet dnsIdentity = cert->getAlternativeNameDNS();
169
170     CertificateCollection collection;
171     collection.load(data.getCertList());
172     collection.sort();
173     Assert(collection.isChain() &&
174            "Certificate collection is not able to create chain. "
175            "It is not possible to verify this signature.");
176
177     m_contextData.wacSecurity.getAuthorsCertificateChainListRef().push_back(
178         collection);
179
180     FOREACH(it, dnsIdentity){
181         if (widgetId.matchHost(*it)) {
182             m_contextData.wacSecurity.setRecognized(true);
183             return;
184         }
185     }
186 }
187
188 void TaskCertify::stepSignature()
189 {
190     LogInfo("================ Step: <<Signature>> ENTER ===============");
191
192     std::string widgetPath = m_contextData.locations->getTemporaryRootDir() +
193         "/";
194
195     SignatureFileInfoSet signatureFiles;
196     SignatureFinder signatureFinder(widgetPath);
197     if (SignatureFinder::NO_ERROR != signatureFinder.find(signatureFiles)) {
198         LogError("Error in Signature Finder");
199         ThrowMsg(Exceptions::InvalidPackage,
200                  "Error openig temporary widget directory");
201     }
202
203     SignatureFileInfoSet::reverse_iterator iter = signatureFiles.rbegin();
204     LogInfo("Number of signatures: " << signatureFiles.size());
205
206     bool firstDistributorSignature = true;
207     bool testCertificate = false;
208
209     bool complianceMode = GlobalDAOReadOnly::getComplianceMode();
210
211     for (; iter != signatureFiles.rend(); ++iter) {
212         LogInfo("Checking signature with id=" << iter->getFileNumber());
213         SignatureData data(widgetPath + iter->getFileName(),
214                            iter->getFileNumber());
215
216         Try {
217             SignatureReader xml;
218             xml.initialize(data, GlobalConfig::GetSignatureXmlSchema());
219             xml.read(data);
220
221             WrtSignatureValidator::AppType appType =
222                 WrtSignatureValidator::WAC20;
223
224             if (m_installContext.widgetConfig.webAppType ==
225                 APP_TYPE_TIZENWEBAPP)
226             {
227                 appType = WrtSignatureValidator::TIZEN;
228             }
229
230             WrtSignatureValidator::Result result;
231
232             WrtSignatureValidator validator(
233                     appType,
234                     !GlobalSettings::
235                     OCSPTestModeEnabled(),
236                     !GlobalSettings::
237                     CrlTestModeEnabled(),
238                     complianceMode);
239
240             result = validator.check(data, widgetPath);
241
242             if (m_contextData.widgetConfig.packagingType
243                 == WrtDB::PKG_TYPE_DIRECTORY_WEB_APP)
244             {
245                 // In directory installation mode, the validation is skipped.
246
247                 result = WrtSignatureValidator::SIGNATURE_VERIFIED;
248             }
249
250             if (result == WrtSignatureValidator::SIGNATURE_REVOKED) {
251                 LogWarning("Certificate is REVOKED");
252                 ThrowMsg(Exceptions::InvalidPackage,
253                          "Certificate is REVOKED");
254             }
255
256             if (result == WrtSignatureValidator::SIGNATURE_INVALID) {
257                 LogWarning("Signature is INVALID");
258                 // TODO change exception name
259                 ThrowMsg(Exceptions::InvalidPackage,
260                          "Invalid Package");
261             }
262
263             if (data.isAuthorSignature()) {
264                 if (result == WrtSignatureValidator::SIGNATURE_VERIFIED ||
265                     m_contextData.wacSecurity.isDistributorSigned())
266                 {
267                     processAuthorSignature(data);
268                 } else if (result ==
269                            WrtSignatureValidator::SIGNATURE_DISREGARD)
270                 {
271                     continue;
272                 }
273             } else {
274                 if (result == WrtSignatureValidator::SIGNATURE_DISREGARD) {
275                     continue;
276                 }
277                 // now signature _must_ be verified
278                 processDistributorSignature(data, firstDistributorSignature);
279                 firstDistributorSignature = false;
280             }
281
282             bool developerMode = GlobalDAOReadOnly::GetDeveloperMode();
283
284             std::string realMEID;
285             TapiHandle *tapiHandle = tel_init(NULL);
286             char *meid = tel_get_misc_me_sn_sync(tapiHandle);
287             if (meid) {
288                 realMEID = meid;
289                 free(meid);
290             }
291             tel_deinit(tapiHandle);
292
293             DeveloperModeValidator developerModeValidator(
294                 complianceMode,
295                 developerMode,
296                 GlobalDAOReadOnly::getComplianceFakeImei(),
297                 GlobalDAOReadOnly::getComplianceFakeMeid(),
298                 realMEID);
299
300             developerModeValidator.check(data);
301
302             testCertificate |=
303                 data.getStorageType().contains(CertStoreId::DEVELOPER);
304
305             if (testCertificate && !developerMode) {
306                 LogError("Widget signed by test certificate, "
307                          "but developer mode is off.");
308                 ThrowMsg(Exceptions::InvalidPackage,
309                          "Widget signed by test certificate, "
310                          "but developer mode is off.");
311             }
312             m_contextData.widgetConfig.isTestWidget = testCertificate;
313         } Catch(ParserSchemaException::Base) {
314             LogError("Error occured in ParserSchema.");
315             ReThrowMsg(Exceptions::InvalidPackage,
316                        "Error occured in ParserSchema.");
317         }
318         Catch(DeveloperModeValidator::Exception::Base) {
319             LogError("Cannot validate developer certificate.");
320             ReThrowMsg(Exceptions::InvalidPackage,
321                        "Cannot validate developer certificate.");
322         }
323     }
324
325     if (signatureFiles.empty()) {
326         LogInfo("No signature files has been found.");
327     }
328
329     LogInfo("================ Step: <<Signature>> DONE ================");
330
331     m_contextData.job->UpdateProgress(
332         InstallerContext::INSTALL_DIGSIG_CHECK,
333         "Widget Signature checked");
334 }
335
336 void TaskCertify::createInstallPopup(PopupType type, const std::string &label)
337 {
338     m_contextData.job->Pause();
339     if (m_popup) {
340         destroyPopup();
341     }
342     bool ret = createPopup();
343     if (ret) {
344         loadPopup(type, label);
345         showPopup();
346     }
347 }
348 void TaskCertify::StepDeletePopupWin()
349 {
350     destroyPopup();
351 }
352
353 void TaskCertify::stepWarningPopup()
354 {
355     LogInfo("Step:: <<Warning Popup>>");
356     // SP-2151: If widget is not recognized (OCSP status of any of certificates
357     //          it is signed with is not recognized) WRT must notify user that
358     //          widget cannot be installed as a trusted application, and let the
359     //          user decide whether it should be installed as an untrusted
360     //          application.
361     if (!m_contextData.wacSecurity.isDistributorSigned()) {
362         std::string label = UNTRUSTED_WIDGET +
363             LABEL_NEW_LINE_2 +
364             QUESTION;
365         createInstallPopup(PopupType::WIDGET_UNRECOGNIZED, label);
366     }
367 }
368
369 std::string TaskCertify::createAuthorWidgetInfo() const
370 {
371     std::string authorInfo;
372     if (m_contextData.wacSecurity.isRecognized()) {
373         //authorInfo += _("IDS_IM_WIDGET_RECOGNISED");
374         authorInfo += _("WIDGET RECOGNISED");
375     } else {
376         //authorInfo += _("IDS_IM_WIDGET_UNRECOGNISED");
377         authorInfo += _("WIDGET UNRECOGNISED");
378     }
379
380     authorInfo += LABEL_NEW_LINE_2;
381     ValidationCore::CertificatePtr authorCert =
382         m_contextData.wacSecurity.getAuthorCertificatePtr();
383     if (!!authorCert) {
384         DPL::Optional < DPL::String > organizationName =
385             authorCert->getOrganizationName();
386
387         //authorInfo += _("IDS_IM_WIDGET_AUTHOR_ORGANIZATION_NAME");
388         authorInfo += _("AUTHOR ORGANIZATION NAME");
389         authorInfo += LABEL_NEW_LINE;
390
391         if (!organizationName.IsNull()) {
392             authorInfo += DPL::ToUTF8String(*organizationName);
393         } else {
394             //authorInfo += _("IDS_IM_WIDGET_ORGANIZATION_UNKNOWN");
395             authorInfo += _("WIDGET ORGANIZATION UNKNOWN");
396         }
397
398         authorInfo += LABEL_NEW_LINE_2;
399
400         DPL::Optional < DPL::String > countryName =
401             authorCert->getCountryName();
402
403         //authorInfo += _("IDS_IM_WIDGET_COUNTRY_NAME");
404         authorInfo += _("WIDGET COUNTRY NAME");
405         authorInfo += LABEL_NEW_LINE;
406
407         if (!countryName.IsNull()) {
408             authorInfo += DPL::ToUTF8String(*countryName);
409         } else {
410             //authorInfo += _("IDS_IM_WIDGET_COUNTRY_UNKNOWN");
411             authorInfo += _("WIDGET COUNTRY UNKNOWN");
412         }
413     } else {
414         authorInfo +=
415             //_("IDS_IM_WIDGET_DOES_NOT_CONTAIN_RECOGNIZED_AUTHOR_SIGNATURE");
416             _("Widget does not contain recognized author signature");
417     }
418     return authorInfo;
419 }
420
421 void TaskCertify::stepAuthorInfoPopup()
422 {
423     LogInfo("Step:: <<Author Popup Information>>");
424     std::string label
425         = createAuthorWidgetInfo() + LABEL_NEW_LINE_2 + QUESTION;
426     createInstallPopup(PopupType::WIDGET_AUTHOR_INFO, label);
427 }
428
429 void TaskCertify::stepFinalize()
430 {
431     LogInfo("Step: <<CERTYFYING DONE>>");
432
433     m_contextData.job->UpdateProgress(
434         InstallerContext::INSTALL_CERT_CHECK,
435         "Widget Certification Check Finished");
436 }
437
438 void TaskCertify::stepWarningPopupAnswer()
439 {
440     LogInfo("Step: <<Warning Popup Answer>>");
441     if (false == m_contextData.wacSecurity.isDistributorSigned() &&
442         WRT_POPUP_BUTTON_CANCEL == m_installCancel)
443     {
444         LogWarning("User does not agreed to install unsigned widgets!");
445         m_installCancel = WRT_POPUP_BUTTON;
446         destroyPopup();
447         ThrowMsg(Exceptions::NotAllowed, "Widget not allowed");
448     }
449 }
450
451 void TaskCertify::stepAuthorInfoPopupAnswer()
452 {
453     LogInfo("Step: <<Author Info Popup Answer>>");
454     if (WRT_POPUP_BUTTON_CANCEL == m_installCancel) {
455         LogWarning("User does not agreed to install widget!");
456         m_installCancel = WRT_POPUP_BUTTON;
457         destroyPopup();
458         ThrowMsg(Exceptions::NotAllowed, "Widget not allowed");
459     }
460 }
461
462 bool TaskCertify::isTizenWebApp() const
463 {
464     bool ret = FALSE;
465     if (m_installContext.widgetConfig.webAppType.appType
466         == WrtDB::AppType::APP_TYPE_TIZENWEBAPP)
467     {
468         ret = TRUE;
469     }
470
471     return ret;
472 }
473 } //namespace WidgetInstall
474 } //namespace Jobs
475