[Release] wrt-installer_0.1.3 for sdk branch
[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         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     SignatureFileInfoSet signatureFiles;
194     SignatureFinder signatureFinder(widgetPath);
195     if (SignatureFinder::NO_ERROR != signatureFinder.find(signatureFiles)) {
196         LogError("Error in Signature Finder");
197         ThrowMsg(Exceptions::InvalidPackage,
198                  "Error openig temporary widget directory");
199     }
200
201     SignatureFileInfoSet::reverse_iterator iter = signatureFiles.rbegin();
202     LogInfo("Number of signatures: " << signatureFiles.size());
203
204     bool firstDistributorSignature = true;
205     bool testCertificate = false;
206
207     bool complianceMode = GlobalDAOReadOnly::getComplianceMode();
208
209     for (; iter != signatureFiles.rend(); ++iter) {
210         LogInfo("Checking signature with id=" << iter->getFileNumber());
211         SignatureData data(widgetPath + iter->getFileName(),
212                            iter->getFileNumber());
213
214         Try {
215             SignatureReader xml;
216             xml.initialize(data, GlobalConfig::GetSignatureXmlSchema());
217             xml.read(data);
218
219             WrtSignatureValidator::AppType appType = WrtSignatureValidator::WAC20;
220
221             if (m_installContext.widgetConfig.webAppType == APP_TYPE_TIZENWEBAPP) {
222                 appType = WrtSignatureValidator::TIZEN;
223             }
224
225             WrtSignatureValidator::Result result;
226
227             if (m_contextData.widgetConfig.packagingType
228                     == WrtDB::PKG_TYPE_DIRECTORY_WEB_APP)
229             {
230                 // In directory installation mode, the validation is skipped.
231
232                 result = WrtSignatureValidator::SIGNATURE_VERIFIED;
233             }
234             else
235             {
236                 WrtSignatureValidator validator(appType,
237                                         !GlobalSettings::OCSPTestModeEnabled(),
238                                         !GlobalSettings::CrlTestModeEnabled(),
239                                         complianceMode);
240
241                 result = validator.check(data, widgetPath);
242             }
243
244             if (result == WrtSignatureValidator::SIGNATURE_REVOKED) {
245                 LogWarning("Certificate is REVOKED");
246                 ThrowMsg(Exceptions::InvalidPackage,
247                          "Certificate is REVOKED");
248             }
249
250             if (result == WrtSignatureValidator::SIGNATURE_INVALID) {
251                 LogWarning("Signature is INVALID");
252                 // TODO change exception name
253                 ThrowMsg(Exceptions::InvalidPackage,
254                          "Invalid Package");
255             }
256
257             if (data.isAuthorSignature()) {
258                 if (result == WrtSignatureValidator::SIGNATURE_VERIFIED ||
259                     m_contextData.wacSecurity.isDistributorSigned())
260                 {
261                     processAuthorSignature(data);
262                 } else if (result == WrtSignatureValidator::SIGNATURE_DISREGARD) {
263                     continue;
264                 }
265             } else {
266                 if (result == WrtSignatureValidator::SIGNATURE_DISREGARD) {
267                     continue;
268                 }
269                 // now signature _must_ be verified
270                 processDistributorSignature(data, firstDistributorSignature);
271                 firstDistributorSignature = false;
272             }
273
274             bool developerMode = GlobalDAOReadOnly::GetDeveloperMode();
275
276             std::string realMEID;
277             TapiHandle *tapiHandle = tel_init(NULL);
278             char *meid = tel_get_misc_me_sn_sync(tapiHandle);
279             if (meid)
280             {
281                 realMEID = meid;
282                 free(meid);
283             }
284             tel_deinit(tapiHandle);
285
286             DeveloperModeValidator developerModeValidator(
287                 complianceMode,
288                 developerMode,
289                 GlobalDAOReadOnly::getComplianceFakeImei(),
290                 GlobalDAOReadOnly::getComplianceFakeMeid(),
291                 realMEID);
292
293             developerModeValidator.check(data);
294
295             testCertificate |=
296                 data.getStorageType().contains(CertStoreId::DEVELOPER);
297
298             if (testCertificate && !developerMode) {
299                 LogError("Widget signed by test certificate, "
300                          "but developer mode is off.");
301                 ThrowMsg(Exceptions::InvalidPackage,
302                          "Widget signed by test certificate, "
303                          "but developer mode is off.");
304             }
305             m_contextData.widgetConfig.isTestWidget = testCertificate;
306         } Catch(ParserSchemaException::Base) {
307             LogError("Error occured in ParserSchema.");
308             ReThrowMsg(Exceptions::InvalidPackage,
309                        "Error occured in ParserSchema.");
310         }
311         Catch(DeveloperModeValidator::Exception::Base) {
312             LogError("Cannot validate developer certificate.");
313             ReThrowMsg(Exceptions::InvalidPackage,
314                        "Cannot validate developer certificate.");
315         }
316     }
317
318     if (signatureFiles.empty()) {
319         LogInfo("No signature files has been found.");
320     }
321
322     LogInfo("================ Step: <<Signature>> DONE ================");
323
324     m_contextData.job->UpdateProgress(
325         InstallerContext::INSTALL_DIGSIG_CHECK,
326         "Widget Signature checked");
327 }
328
329 void TaskCertify::createInstallPopup(PopupType type, const std::string &label)
330 {
331     m_contextData.job->Pause();
332     if(m_popup)
333         destroyPopup();
334     bool ret = createPopup();
335     if(ret)
336     {
337         loadPopup(type, label);
338         showPopup();
339     }
340 }
341 void TaskCertify::StepDeletePopupWin()
342 {
343     destroyPopup();
344 }
345
346 void TaskCertify::stepWarningPopup()
347 {
348     LogInfo("Step:: <<Warning Popup>>");
349     // SP-2151: If widget is not recognized (OCSP status of any of certificates
350     //          it is signed with is not recognized) WRT must notify user that
351     //          widget cannot be installed as a trusted application, and let the
352     //          user decide whether it should be installed as an untrusted
353     //          application.
354     if (!m_contextData.wacSecurity.isDistributorSigned()) {
355         std::string label = UNTRUSTED_WIDGET +
356             LABEL_NEW_LINE_2 +
357             QUESTION;
358         createInstallPopup(PopupType::WIDGET_UNRECOGNIZED, label);
359     }
360 }
361
362 std::string TaskCertify::createAuthorWidgetInfo() const
363 {
364     std::string authorInfo;
365     if (m_contextData.wacSecurity.isRecognized()) {
366         //authorInfo += _("IDS_IM_WIDGET_RECOGNISED");
367         authorInfo += _("WIDGET RECOGNISED");
368     } else {
369         //authorInfo += _("IDS_IM_WIDGET_UNRECOGNISED");
370         authorInfo += _("WIDGET UNRECOGNISED");
371     }
372
373     authorInfo += LABEL_NEW_LINE_2;
374     ValidationCore::CertificatePtr authorCert =
375         m_contextData.wacSecurity.getAuthorCertificatePtr();
376     if (!!authorCert) {
377         DPL::Optional < DPL::String > organizationName =
378             authorCert->getOrganizationName();
379
380         //authorInfo += _("IDS_IM_WIDGET_AUTHOR_ORGANIZATION_NAME");
381         authorInfo += _("AUTHOR ORGANIZATION NAME");
382         authorInfo += LABEL_NEW_LINE;
383
384         if (!organizationName.IsNull()) {
385             authorInfo += DPL::ToUTF8String(*organizationName);
386         } else {
387             //authorInfo += _("IDS_IM_WIDGET_ORGANIZATION_UNKNOWN");
388             authorInfo += _("WIDGET ORGANIZATION UNKNOWN");
389         }
390
391         authorInfo += LABEL_NEW_LINE_2;
392
393         DPL::Optional < DPL::String > countryName =
394             authorCert->getCountryName();
395
396         //authorInfo += _("IDS_IM_WIDGET_COUNTRY_NAME");
397         authorInfo += _("WIDGET COUNTRY NAME");
398         authorInfo += LABEL_NEW_LINE;
399
400         if (!countryName.IsNull()) {
401             authorInfo += DPL::ToUTF8String(*countryName);
402         } else {
403             //authorInfo += _("IDS_IM_WIDGET_COUNTRY_UNKNOWN");
404             authorInfo += _("WIDGET COUNTRY UNKNOWN");
405         }
406     } else {
407         authorInfo +=
408             //_("IDS_IM_WIDGET_DOES_NOT_CONTAIN_RECOGNIZED_AUTHOR_SIGNATURE");
409             _("Widget does not contain recognized author signature");
410     }
411     return authorInfo;
412 }
413
414 void TaskCertify::stepAuthorInfoPopup()
415 {
416     LogInfo("Step:: <<Author Popup Information>>");
417         std::string label
418             = createAuthorWidgetInfo() + LABEL_NEW_LINE_2 + QUESTION;
419         createInstallPopup(PopupType::WIDGET_AUTHOR_INFO, label);
420 }
421
422 void TaskCertify::stepFinalize()
423 {
424     LogInfo("Step: <<CERTYFYING DONE>>");
425
426     m_contextData.job->UpdateProgress(
427         InstallerContext::INSTALL_CERT_CHECK,
428         "Widget Certification Check Finished");
429 }
430
431
432 void TaskCertify::stepWarningPopupAnswer()
433 {
434     LogInfo("Step: <<Warning Popup Answer>>");
435     if (false == m_contextData.wacSecurity.isDistributorSigned() &&
436             WRT_POPUP_BUTTON_CANCEL == m_installCancel)
437     {
438         LogWarning("User does not agreed to install unsigned widgets!");
439         m_installCancel = WRT_POPUP_BUTTON;
440         destroyPopup();
441         ThrowMsg(Exceptions::NotAllowed, "Widget not allowed");
442     }
443 }
444
445 void TaskCertify::stepAuthorInfoPopupAnswer()
446 {
447     LogInfo("Step: <<Author Info Popup Answer>>");
448     if ( WRT_POPUP_BUTTON_CANCEL == m_installCancel) {
449         LogWarning("User does not agreed to install widget!");
450         m_installCancel = WRT_POPUP_BUTTON;
451         destroyPopup();
452         ThrowMsg(Exceptions::NotAllowed, "Widget not allowed");
453     }
454 }
455
456 bool TaskCertify::isTizenWebApp() const
457 {
458     bool ret = FALSE;
459     if (m_installContext.widgetConfig.webAppType.appType
460             == WrtDB::AppType::APP_TYPE_TIZENWEBAPP)
461         ret = TRUE;
462
463     return ret;
464 }
465 } //namespace WidgetInstall
466 } //namespace Jobs
467