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