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