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