Logs fixed
[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 <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/SignatureReader.h>
41 #include <vcore/SignatureFinder.h>
42 #include <vcore/SignatureValidator.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         SignatureValidator::FingerprintToColonHex(
87             certificate->getFingerprint(Certificate::FINGERPRINT_MD5));
88
89     result.strSHA1Fingerprint = std::string("sha-1 ") +
90         SignatureValidator::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     m_contextData(inCont),
102     WidgetInstallPopup(inCont)
103 {
104     /* This is temporary comment for certi error
105        After security-server, cert-svc release, should remove comment
106     AddStep(&TaskCertify::stepSignature);
107     */
108
109     // Block until fixed popup issues
110     if (!GlobalSettings::PopupsTestModeEnabled()
111             && !m_installContext.m_quiet && !isTizenWebApp()) {
112         AddStep(&TaskCertify::stepWarningPopup);
113         AddStep(&TaskCertify::stepWarningPopupAnswer);
114         AddStep(&TaskCertify::stepAuthorInfoPopup);
115         AddStep(&TaskCertify::stepAuthorInfoPopupAnswer);
116         AddStep(&TaskCertify::StepDeletePopupWin);
117     }
118     AddStep(&TaskCertify::stepFinalize);
119 }
120
121 void TaskCertify::processDistributorSignature(const SignatureData &data,
122                                               bool first)
123 {
124     // this signature is verified -
125     // no point in check domain WAC_ROOT and WAC_RECOGNIZED
126     m_contextData.wacSecurity.setDistributorSigned(true);
127
128     if (data.getStorageType().contains(CertStoreId::WAC_ROOT)) {
129         m_contextData.wacSecurity.setWacSigned(true);
130     }
131
132     CertificateCollection collection;
133     collection.load(data.getCertList());
134     collection.sort();
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("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("No 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             SignatureValidator validator(!GlobalSettings::OCSPTestModeEnabled(),
220                                          !GlobalSettings::CrlTestModeEnabled(),
221                                          complianceMode);
222             SignatureValidator::Result result =
223                 validator.check(data, widgetPath);
224
225             if (result == SignatureValidator::SIGNATURE_REVOKED) {
226                 LogWarning("Certificate is REVOKED");
227                 ThrowMsg(Exceptions::InvalidPackage,
228                          "Certificate is REVOKED");
229             }
230
231             if (result == SignatureValidator::SIGNATURE_INVALID) {
232                 LogWarning("Signature is INVALID");
233                 // TODO change exception name
234                 ThrowMsg(Exceptions::InvalidPackage,
235                          "Invalid Package");
236             }
237
238             if (data.isAuthorSignature()) {
239                 if (result == SignatureValidator::SIGNATURE_VERIFIED ||
240                     m_contextData.wacSecurity.isDistributorSigned())
241                 {
242                     processAuthorSignature(data);
243                 } else if (result == SignatureValidator::SIGNATURE_DISREGARD) {
244                     continue;
245                 }
246             } else {
247                 if (result == SignatureValidator::SIGNATURE_DISREGARD) {
248                     continue;
249                 }
250                 // now signature _must_ be verified
251                 processDistributorSignature(data, firstDistributorSignature);
252                 firstDistributorSignature = false;
253             }
254
255             bool developerMode = GlobalDAOReadOnly::GetDeveloperMode();
256
257             std::string realMEID;
258             TapiHandle *tapiHandle = tel_init(NULL);
259             char *meid = tel_get_misc_me_sn_sync(tapiHandle);
260             if (meid)
261             {
262                 realMEID = meid;
263                 free(meid);
264             }
265             tel_deinit(tapiHandle);
266
267             DeveloperModeValidator developerModeValidator(
268                 complianceMode,
269                 developerMode,
270                 GlobalDAOReadOnly::getComplianceFakeImei(),
271                 GlobalDAOReadOnly::getComplianceFakeMeid(),
272                 realMEID);
273
274             developerModeValidator.check(data);
275
276             testCertificate |=
277                 data.getStorageType().contains(CertStoreId::DEVELOPER);
278
279             if (testCertificate && !developerMode) {
280                 LogError("Widget signed by test certificate, "
281                          "but developer mode is off.");
282                 ThrowMsg(Exceptions::InvalidPackage,
283                          "Widget signed by test certificate, "
284                          "but developer mode is off.");
285             }
286             m_contextData.widgetConfig.isTestWidget = testCertificate;
287         } Catch(ParserSchemaException::Base) {
288             LogError("Error occured in ParserSchema.");
289             ReThrowMsg(Exceptions::InvalidPackage,
290                        "Error occured in ParserSchema.");
291         }
292         Catch(DeveloperModeValidator::Exception::Base) {
293             LogError("Cannot validate developer certificate.");
294             ReThrowMsg(Exceptions::InvalidPackage,
295                        "Cannot validate developer certificate.");
296         }
297     }
298
299     if (signatureFiles.empty()) {
300         LogInfo("No signature files has been found.");
301     }
302
303     LogInfo("================ Step: <<CSignature>> DONE ================");
304
305     m_contextData.job->UpdateProgress(
306         InstallerContext::INSTALL_DIGSIG_CHECK,
307         "Widget Signature checked");
308 }
309
310 void TaskCertify::createInstallPopup(PopupType type, const std::string &label)
311 {
312     m_contextData.job->Pause();
313     if(m_popup)
314         destroyPopup();
315     bool ret = createPopup();
316     if(ret)
317     {
318         loadPopup(type, label);
319         showPopup();
320     }
321 }
322 void TaskCertify::StepDeletePopupWin()
323 {
324     destroyPopup();
325 }
326
327 void TaskCertify::stepWarningPopup()
328 {
329     LogInfo("Step:: <<Warning Popup>>");
330     // SP-2151: If widget is not recognized (OCSP status of any of certificates
331     //          it is signed with is not recognized) WRT must notify user that
332     //          widget cannot be installed as a trusted application, and let the
333     //          user decide whether it should be installed as an untrusted
334     //          application.
335     if (!m_contextData.wacSecurity.isDistributorSigned()) {
336         std::string label = UNTRUSTED_WIDGET +
337             LABEL_NEW_LINE_2 +
338             QUESTION;
339         createInstallPopup(PopupType::WIDGET_UNRECOGNIZED, label);
340     }
341 }
342
343 std::string TaskCertify::createAuthorWidgetInfo() const
344 {
345     std::string authorInfo;
346     if (m_contextData.wacSecurity.isRecognized()) {
347         //authorInfo += _("IDS_IM_WIDGET_RECOGNISED");
348         authorInfo += _("WIDGET RECOGNISED");
349     } else {
350         //authorInfo += _("IDS_IM_WIDGET_UNRECOGNISED");
351         authorInfo += _("WIDGET UNRECOGNISED");
352     }
353
354     authorInfo += LABEL_NEW_LINE_2;
355     ValidationCore::CertificatePtr authorCert =
356         m_contextData.wacSecurity.getAuthorCertificatePtr();
357     if (!!authorCert) {
358         DPL::Optional < DPL::String > organizationName =
359             authorCert->getOrganizationName();
360
361         //authorInfo += _("IDS_IM_WIDGET_AUTHOR_ORGANIZATION_NAME");
362         authorInfo += _("AUTHOR ORGANIZATION NAME");
363         authorInfo += LABEL_NEW_LINE;
364
365         if (!organizationName.IsNull()) {
366             authorInfo += DPL::ToUTF8String(*organizationName);
367         } else {
368             //authorInfo += _("IDS_IM_WIDGET_ORGANIZATION_UNKNOWN");
369             authorInfo += _("WIDGET ORGANIZATION UNKNOWN");
370         }
371
372         authorInfo += LABEL_NEW_LINE_2;
373
374         DPL::Optional < DPL::String > countryName =
375             authorCert->getCountryName();
376
377         //authorInfo += _("IDS_IM_WIDGET_COUNTRY_NAME");
378         authorInfo += _("WIDGET COUNTRY NAME");
379         authorInfo += LABEL_NEW_LINE;
380
381         if (!countryName.IsNull()) {
382             authorInfo += DPL::ToUTF8String(*countryName);
383         } else {
384             //authorInfo += _("IDS_IM_WIDGET_COUNTRY_UNKNOWN");
385             authorInfo += _("WIDGET COUNTRY UNKNOWN");
386         }
387     } else {
388         authorInfo +=
389             //_("IDS_IM_WIDGET_DOES_NOT_CONTAIN_RECOGNIZED_AUTHOR_SIGNATURE");
390             _("Widget does not contain recognized author signature");
391     }
392     return authorInfo;
393 }
394
395 void TaskCertify::stepAuthorInfoPopup()
396 {
397     LogInfo("Step:: <<Author Popup Information>>");
398         std::string label
399             = createAuthorWidgetInfo() + LABEL_NEW_LINE_2 + QUESTION;
400         createInstallPopup(PopupType::WIDGET_AUTHOR_INFO, label);
401 }
402
403 void TaskCertify::stepFinalize()
404 {
405     LogInfo("Step: <<CERTYFYING DONE>>");
406
407     m_contextData.job->UpdateProgress(
408         InstallerContext::INSTALL_CERT_CHECK,
409         "Widget Certification Check Finished");
410 }
411
412
413 void TaskCertify::stepWarningPopupAnswer()
414 {
415     LogInfo("Step: <<Warning Popup Answer>>");
416     if (false == m_contextData.wacSecurity.isDistributorSigned() &&
417             WRT_POPUP_BUTTON_CANCEL == m_installCancel)
418     {
419         LogWarning("User does not agreed to install unsigned widgets!");
420         m_installCancel = WRT_POPUP_BUTTON;
421         destroyPopup();
422         ThrowMsg(Exceptions::NotAllowed, "Widget not allowed");
423     }
424 }
425
426 void TaskCertify::stepAuthorInfoPopupAnswer()
427 {
428     LogInfo("Step: <<Author Info Popup Answer>>");
429     if ( WRT_POPUP_BUTTON_CANCEL == m_installCancel) {
430         LogWarning("User does not agreed to install widget!");
431         m_installCancel = WRT_POPUP_BUTTON;
432         destroyPopup();
433         ThrowMsg(Exceptions::NotAllowed, "Widget not allowed");
434     }
435 }
436
437 bool TaskCertify::isTizenWebApp() const
438 {
439     bool ret = FALSE;
440     if (m_installContext.widgetConfig.type.appType
441             == WrtDB::AppType::APP_TYPE_TIZENWEBAPP)
442         ret = TRUE;
443
444     return ret;
445 }
446 } //namespace WidgetInstall
447 } //namespace Jobs
448