Popup removal
[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 <dpl/wrt-dao-ro/global_config.h>
37 #include "wac_widget_id.h"
38
39 #include <vcore/Certificate.h>
40 #include <vcore/SignatureReader.h>
41 #include <vcore/SignatureFinder.h>
42 #include <vcore/WrtSignatureValidator.h>
43 #include <dpl/utils/wrt_global_settings.h>
44 #include <dpl/wrt-dao-ro/global_dao_read_only.h>
45
46 #include <ITapiModem.h>
47 #include <tapi_common.h>
48
49 using namespace ValidationCore;
50 using namespace WrtDB;
51
52 namespace {
53 const std::string LABEL_NEW_LINE = "<br>";
54 const std::string LABEL_NEW_LINE_2 = "<br><br>";
55 const std::string UNTRUSTED_WIDGET = "It is an Untrusted Widget";
56 const char *QUESTION = "Do you wanto to install?";
57
58 WidgetCertificateData toWidgetCertificateData(const SignatureData &data,
59                                               bool root)
60 {
61     WidgetCertificateData result;
62
63     result.chainId = data.getSignatureNumber();
64     LogDebug("result.chainId : " << result.chainId);
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         Certificate::FingerprintToColonHex(
87             certificate->getFingerprint(Certificate::FINGERPRINT_MD5));
88
89     result.strSHA1Fingerprint = std::string("sha-1 ") +
90         Certificate::FingerprintToColonHex(
91             certificate->getFingerprint(Certificate::FINGERPRINT_SHA1));
92
93     return result;
94 }
95
96 CertificatePtr getOldAuthorSignerCertificate(DPL::String appid)
97 {
98     WidgetDAOReadOnly dao(appid);
99     CertificateChainList chainList = dao.getWidgetCertificate(SIGNATURE_AUTHOR);
100
101     FOREACH(it, chainList)
102     {
103         ValidationCore::CertificateCollection chain;
104         if (false == chain.load(*it)) {
105             LogError("Chain is broken");
106         }
107
108         if (!chain.sort()) {
109             LogError("Chain failed at sorting");
110         }
111
112         ValidationCore::CertificateList list = chain.getCertificateList();
113
114         FOREACH(cert, list)
115         {
116             if (!(*cert)->isRootCert() && !(*cert)->isCA()) {
117                 return *cert;
118             }
119         }
120     }
121     return CertificatePtr(NULL);
122 }
123 } // namespace anonymous
124
125 namespace Jobs {
126 namespace WidgetInstall {
127 TaskCertify::TaskCertify(InstallerContext &inCont) :
128     DPL::TaskDecl<TaskCertify>(this),
129     m_contextData(inCont)
130 {
131     AddStep(&TaskCertify::stepSignature);
132     // certi comparison determines whether the update.
133     if (true == m_contextData.isUpdateMode) {
134         AddStep(&TaskCertify::stepVerifyUpdate);
135     }
136     AddStep(&TaskCertify::stepFinalize);
137 }
138
139 void TaskCertify::processDistributorSignature(const SignatureData &data)
140 {
141     // this signature is verified -
142     // no point in check domain WAC_ROOT and WAC_RECOGNIZED
143     m_contextData.wacSecurity.setDistributorSigned(true);
144
145     CertificateCollection collection;
146     collection.load(data.getCertList());
147     Assert(collection.sort() &&
148            "Certificate collection can't sort");
149
150     Assert(collection.isChain() &&
151            "Certificate collection is not able to create chain. "
152            "It is not possible to verify this signature.");
153
154     m_contextData.wacSecurity.getCertificateChainListRef().push_back(
155         collection);
156
157     if (data.getSignatureNumber() == 1) {
158         m_contextData.wacSecurity.getCertificateListRef().push_back(
159             toWidgetCertificateData(data, true));
160         m_contextData.wacSecurity.getCertificateListRef().push_back(
161             toWidgetCertificateData(data, false));
162     }
163 }
164
165 void TaskCertify::processAuthorSignature(const SignatureData &data)
166 {
167     using namespace ValidationCore;
168     LogInfo("DNS Identity match!");
169     // this signature is verified or widget is distributor signed
170     m_contextData.wacSecurity.setAuthorCertificatePtr(data.getEndEntityCertificatePtr());
171     CertificatePtr test = m_contextData.wacSecurity.getAuthorCertificatePtr();
172
173     m_contextData.wacSecurity.getCertificateListRef().push_back(
174         toWidgetCertificateData(data, true));
175     m_contextData.wacSecurity.getCertificateListRef().push_back(
176         toWidgetCertificateData(data, false));
177
178     // match widget_id with one from dns identity set
179     WacWidgetId widgetId(m_contextData.widgetConfig.configInfo.widget_id);
180
181     CertificatePtr cert = data.getEndEntityCertificatePtr();
182     Assert(cert);
183     Certificate::AltNameSet dnsIdentity = cert->getAlternativeNameDNS();
184
185     CertificateCollection collection;
186     collection.load(data.getCertList());
187     collection.sort();
188     Assert(collection.isChain() &&
189            "Certificate collection is not able to create chain. "
190            "It is not possible to verify this signature.");
191
192     m_contextData.wacSecurity.getAuthorsCertificateChainListRef().push_back(
193         collection);
194
195     FOREACH(it, dnsIdentity){
196         if (widgetId.matchHost(*it)) {
197             m_contextData.wacSecurity.setRecognized(true);
198             return;
199         }
200     }
201 }
202
203 void TaskCertify::stepSignature()
204 {
205     LogInfo("================ Step: <<Signature>> ENTER ===============");
206
207     std::string widgetPath;
208     if (m_contextData.widgetConfig.packagingType ==
209         WrtDB::PKG_TYPE_DIRECTORY_WEB_APP)
210     {
211         widgetPath = m_contextData.locations->getSourceDir() + "/";
212     } else {
213         widgetPath = m_contextData.locations->getTemporaryPackageDir() + "/";
214     }
215
216     SignatureFileInfoSet signatureFiles;
217     SignatureFinder signatureFinder(widgetPath);
218     if (SignatureFinder::NO_ERROR != signatureFinder.find(signatureFiles)) {
219         LogError("Error in Signature Finder");
220         ThrowMsg(Exceptions::SignatureNotFound,
221                  "Error openig temporary widget directory");
222     }
223
224     SignatureFileInfoSet::reverse_iterator iter = signatureFiles.rbegin();
225     LogInfo("Number of signatures: " << signatureFiles.size());
226
227     bool complianceMode = GlobalDAOReadOnly::getComplianceMode();
228
229     for (; iter != signatureFiles.rend(); ++iter) {
230         LogInfo("Checking signature with id=" << iter->getFileNumber());
231         SignatureData data(widgetPath + iter->getFileName(),
232                            iter->getFileNumber());
233
234         Try {
235             SignatureReader xml;
236             xml.initialize(data, GlobalConfig::GetSignatureXmlSchema());
237             xml.read(data);
238
239             WrtSignatureValidator::AppType appType =
240                 WrtSignatureValidator::WAC20;
241
242             if (m_contextData.widgetConfig.webAppType ==
243                 APP_TYPE_TIZENWEBAPP)
244             {
245                 appType = WrtSignatureValidator::TIZEN;
246             }
247
248             WrtSignatureValidator::Result result;
249
250             WrtSignatureValidator validator(
251                     appType,
252                     !GlobalSettings::
253                     OCSPTestModeEnabled(),
254                     !GlobalSettings::
255                     CrlTestModeEnabled(),
256                     complianceMode);
257
258             result = validator.check(data, widgetPath);
259
260             if (m_contextData.widgetConfig.packagingType
261                 == WrtDB::PKG_TYPE_DIRECTORY_WEB_APP)
262             {
263                 // In directory installation mode, the validation is skipped.
264
265                 result = WrtSignatureValidator::SIGNATURE_VERIFIED;
266             }
267
268             if (result == WrtSignatureValidator::SIGNATURE_REVOKED) {
269                 LogWarning("Certificate is REVOKED");
270                 ThrowMsg(Exceptions::CertificateExpired,
271                          "Certificate is REVOKED");
272             }
273
274             if (result == WrtSignatureValidator::SIGNATURE_INVALID) {
275                 LogWarning("Signature is INVALID");
276                 // TODO change exception name
277                 ThrowMsg(Exceptions::SignatureInvalid,
278                          "Invalid Package");
279             }
280
281             if (data.isAuthorSignature()) {
282                 if (result == WrtSignatureValidator::SIGNATURE_VERIFIED ||
283                     m_contextData.wacSecurity.isDistributorSigned())
284                 {
285                     processAuthorSignature(data);
286                 } else if (result ==
287                            WrtSignatureValidator::SIGNATURE_DISREGARD)
288                 {
289                     continue;
290                 }
291             } else {
292                 // now signature _must_ be verified
293                 processDistributorSignature(data);
294             }
295         } Catch(ParserSchemaException::Base) {
296             LogError("Error occured in ParserSchema.");
297             ReThrowMsg(Exceptions::SignatureInvalid,
298                        "Error occured in ParserSchema.");
299         }
300     }
301
302     if (signatureFiles.empty()) {
303         LogInfo("No signature files has been found.");
304     }
305
306     LogInfo("================ Step: <<Signature>> DONE ================");
307
308     m_contextData.job->UpdateProgress(
309         InstallerContext::INSTALL_DIGSIG_CHECK,
310         "Widget Signature checked");
311 }
312
313 void TaskCertify::stepFinalize()
314 {
315     LogInfo("Step: <<CERTYFYING DONE>>");
316
317     m_contextData.job->UpdateProgress(
318         InstallerContext::INSTALL_CERT_CHECK,
319         "Widget Certification Check Finished");
320 }
321
322 bool TaskCertify::isTizenWebApp() const
323 {
324     bool ret = FALSE;
325     if (m_contextData.widgetConfig.webAppType.appType
326         == WrtDB::AppType::APP_TYPE_TIZENWEBAPP)
327     {
328         ret = TRUE;
329     }
330
331     return ret;
332 }
333
334 void TaskCertify::stepVerifyUpdate()
335 {
336     LogInfo("Step: <<Check Update>>");
337     CertificatePtr newCertificate =
338         m_contextData.wacSecurity.getAuthorCertificatePtr();
339     CertificatePtr oldCertificate =
340         getOldAuthorSignerCertificate(m_contextData.widgetConfig.tzAppid);
341
342     if (!!newCertificate && !!oldCertificate) {
343         if (0 != newCertificate->getBase64().compare(oldCertificate->getBase64())) {
344             LogDebug("old widget's author signer certificate : " <<
345                     oldCertificate->getBase64());
346             LogDebug("new widget's author signer certificate : " <<
347                     newCertificate->getBase64());
348             ThrowMsg(Exceptions::NotMatchedCertification,
349                     "Author signer certificates doesn't match \
350                     between old widget and installing widget");
351         }
352     } else {
353         if (!(NULL == newCertificate.Get() && NULL == oldCertificate.Get())) {
354             ThrowMsg(Exceptions::NotMatchedCertification,
355                     "Author signer certificates doesn't match \
356                     between old widget and installing widget");
357         }
358     }
359 }
360 } //namespace WidgetInstall
361 } //namespace Jobs
362