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