Initialize Tizen 2.3
[framework/web/wrt-installer.git] / src_mobile / 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 <sstream>
27 #include <unistd.h>
28 #include <dpl/assert.h>
29 #include <pcrecpp.h>
30
31 //WRT INCLUDES
32 #include <widget_install/task_certify.h>
33 #include <widget_install/job_widget_install.h>
34 #include <widget_install/widget_install_errors.h>
35 #include <widget_install/widget_install_context.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
45 #include <ITapiModem.h>
46 #include <tapi_common.h>
47
48 #include <installer_log.h>
49
50 using namespace ValidationCore;
51 using namespace WrtDB;
52
53 namespace {
54
55 WidgetCertificateData toWidgetCertificateData(const SignatureData &data,
56                                               bool root)
57 {
58     WidgetCertificateData result;
59
60     result.chainId = data.getSignatureNumber();
61     _D("result.chainId : %d", result.chainId);
62
63     result.owner = data.isAuthorSignature() ?
64         WidgetCertificateData::AUTHOR : WidgetCertificateData::DISTRIBUTOR;
65
66     result.type = root ?
67         WidgetCertificateData::ROOT : WidgetCertificateData::ENDENTITY;
68
69     CertificatePtr certificate;
70
71     if (root) {
72         certificate = data.getRootCaCertificatePtr();
73     } else {
74         certificate = data.getEndEntityCertificatePtr();
75     }
76
77     Assert(certificate && !certificate->getCommonName().IsNull() &&
78            "CommonName is Null");
79
80     result.strCommonName = *certificate->getCommonName();
81
82     result.strMD5Fingerprint = std::string("md5 ") +
83         Certificate::FingerprintToColonHex(
84             certificate->getFingerprint(Certificate::FINGERPRINT_MD5));
85
86     result.strSHA1Fingerprint = std::string("sha-1 ") +
87         Certificate::FingerprintToColonHex(
88             certificate->getFingerprint(Certificate::FINGERPRINT_SHA1));
89
90     return result;
91 }
92
93 CertificatePtr getOldAuthorSignerCertificate(DPL::String appid)
94 {
95     WidgetDAOReadOnly dao(appid);
96     CertificateChainList chainList = dao.getWidgetCertificate(SIGNATURE_AUTHOR);
97
98     FOREACH(it, chainList)
99     {
100         ValidationCore::CertificateCollection chain;
101         if (false == chain.load(*it)) {
102             _E("Chain is broken");
103         }
104
105         if (!chain.sort()) {
106             _E("Chain failed at sorting");
107         }
108
109         ValidationCore::CertificateList list = chain.getCertificateList();
110
111         FOREACH(cert, list)
112         {
113             if (!(*cert)->isRootCert() && !(*cert)->isCA()) {
114                 return *cert;
115             }
116         }
117     }
118     return CertificatePtr(NULL);
119 }
120 } // namespace anonymous
121
122 namespace Jobs {
123 namespace WidgetInstall {
124 TaskCertify::TaskCertify(InstallerContext &inCont) :
125     DPL::TaskDecl<TaskCertify>(this),
126     m_contextData(inCont)
127 {
128     AddStep(&TaskCertify::StartStep);
129     AddStep(&TaskCertify::stepSignature);
130     // certi comparison determines whether the update.
131     if (true == m_contextData.isUpdateMode) {
132         AddStep(&TaskCertify::stepVerifyUpdate);
133     }
134     AddStep(&TaskCertify::EndStep);
135 }
136
137 void TaskCertify::processDistributorSignature(const SignatureData &data)
138 {
139     // this signature is verified -
140     // no point in check domain WAC_ROOT and WAC_RECOGNIZED
141     m_contextData.widgetSecurity.setDistributorSigned(true);
142
143     CertificateCollection collection;
144     collection.load(data.getCertList());
145     Assert(collection.sort() &&
146            "Certificate collection can't sort");
147
148     Assert(collection.isChain() &&
149            "Certificate collection is not able to create chain. "
150            "It is not possible to verify this signature.");
151
152     m_contextData.widgetSecurity.getCertificateChainListRef().push_back(
153         collection);
154
155     if (data.getSignatureNumber() == 1) {
156         m_contextData.widgetSecurity.getCertificateListRef().push_back(
157             toWidgetCertificateData(data, true));
158         m_contextData.widgetSecurity.getCertificateListRef().push_back(
159             toWidgetCertificateData(data, false));
160     }
161 }
162
163 void TaskCertify::processAuthorSignature(const SignatureData &data)
164 {
165     using namespace ValidationCore;
166     _D("DNS Identity match!");
167     // this signature is verified or widget is distributor signed
168     m_contextData.widgetSecurity.setAuthorCertificatePtr(data.getEndEntityCertificatePtr());
169     CertificatePtr test = m_contextData.widgetSecurity.getAuthorCertificatePtr();
170
171     m_contextData.widgetSecurity.getCertificateListRef().push_back(
172         toWidgetCertificateData(data, true));
173     m_contextData.widgetSecurity.getCertificateListRef().push_back(
174         toWidgetCertificateData(data, false));
175
176     // match widget_id with one from dns identity set
177     WacWidgetId widgetId(m_contextData.widgetConfig.configInfo.widget_id);
178
179     CertificatePtr cert = data.getEndEntityCertificatePtr();
180     Assert(cert);
181     Certificate::AltNameSet dnsIdentity = cert->getAlternativeNameDNS();
182
183     CertificateCollection collection;
184     collection.load(data.getCertList());
185     collection.sort();
186     Assert(collection.isChain() &&
187            "Certificate collection is not able to create chain. "
188            "It is not possible to verify this signature.");
189
190     m_contextData.widgetSecurity.getAuthorsCertificateChainListRef().push_back(
191         collection);
192
193     FOREACH(it, dnsIdentity){
194         if (widgetId.matchHost(*it)) {
195             m_contextData.widgetSecurity.setRecognized(true);
196             return;
197         }
198     }
199 }
200
201 void TaskCertify::getSignatureFiles(std::string path, SignatureFileInfoSet& file)
202 {
203     _D("path : %s", path.c_str());
204     SignatureFileInfoSet signatureFiles;
205     SignatureFinder signatureFinder(path);
206     if (SignatureFinder::NO_ERROR != signatureFinder.find(file)) {
207         _E("Error in Signature Finder : %s", path.c_str());
208         ThrowMsg(Exceptions::SignatureNotFound,
209                 "Error openig temporary widget directory");
210     }
211 }
212
213 void TaskCertify::stepSignature()
214 {
215     _D("================ Step: <<Signature>> ENTER ===============");
216
217     std::string widgetPath;
218     widgetPath = m_contextData.locations->getPackageInstallationDir() + "/";
219
220     SignatureFileInfoSet signatureFiles;
221
222     Try {
223         getSignatureFiles(widgetPath, signatureFiles);
224
225         if (signatureFiles.size() <= 0) {
226             widgetPath += std::string(WrtDB::GlobalConfig::GetWidgetSrcPath())
227                 + "/";
228             if (0 == access(widgetPath.c_str(), F_OK)) {
229                 getSignatureFiles(widgetPath, signatureFiles);
230             }
231         }
232     } Catch(Exceptions::SignatureNotFound) {
233         ReThrowMsg(Exceptions::SignatureNotFound, widgetPath);
234     }
235
236     SignatureFileInfoSet::reverse_iterator iter = signatureFiles.rbegin();
237     _D("Number of signatures: %d", signatureFiles.size());
238
239     for (; iter != signatureFiles.rend(); ++iter) {
240         _D("Checking signature with id=%d", iter->getFileNumber());
241         SignatureData data(widgetPath + iter->getFileName(),
242                            iter->getFileNumber());
243
244         Try {
245             SignatureReader xml;
246             xml.initialize(data, GlobalConfig::GetSignatureXmlSchema());
247             xml.read(data);
248
249             WrtSignatureValidator::Result result;
250
251             WrtSignatureValidator validator(
252                     WrtSignatureValidator::TIZEN,
253                     !GlobalSettings::
254                     OCSPTestModeEnabled(),
255                     !GlobalSettings::
256                     CrlTestModeEnabled(),
257                     false);
258
259             result = validator.check(data, widgetPath);
260
261             if (m_contextData.mode.installTime
262                 ==  InstallMode::InstallTime::PRELOAD)
263             {
264                 result = WrtSignatureValidator::SIGNATURE_VERIFIED;
265             }
266
267             if (result == WrtSignatureValidator::SIGNATURE_REVOKED) {
268                 _W("Certificate is REVOKED");
269                 ThrowMsg(Exceptions::CertificateExpired,
270                          "Certificate is REVOKED");
271             }
272
273             if (result == WrtSignatureValidator::SIGNATURE_INVALID &&
274                     iter->getFileNumber() <= 1) {
275                 _W("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                     processAuthorSignature(data);
284                 }
285             } else {
286                 if (result != WrtSignatureValidator::SIGNATURE_INVALID) {
287                     processDistributorSignature(data);
288                 }
289             }
290         } Catch(ParserSchemaException::Base) {
291             _E("Error occured in ParserSchema.");
292             ReThrowMsg(Exceptions::SignatureInvalid,
293                        "Error occured in ParserSchema.");
294         }
295     }
296
297     if (signatureFiles.empty()) {
298         _D("No signature files has been found.");
299     }
300
301     _D("================ Step: <<Signature>> DONE ================");
302
303     m_contextData.job->UpdateProgress(
304         InstallerContext::INSTALL_DIGSIG_CHECK,
305         "Widget Signature checked");
306 }
307
308 bool TaskCertify::isTizenWebApp() const
309 {
310     bool ret = FALSE;
311     if (m_contextData.widgetConfig.webAppType.appType
312         == WrtDB::AppType::APP_TYPE_TIZENWEBAPP)
313     {
314         ret = TRUE;
315     }
316
317     return ret;
318 }
319
320 void TaskCertify::stepVerifyUpdate()
321 {
322     _D("Step: <<Check Update>>");
323     CertificatePtr newCertificate =
324         m_contextData.widgetSecurity.getAuthorCertificatePtr();
325     CertificatePtr oldCertificate =
326         getOldAuthorSignerCertificate(m_contextData.widgetConfig.tzAppid);
327
328     if (!!newCertificate && !!oldCertificate) {
329         if (0 != newCertificate->getBase64().compare(oldCertificate->getBase64())) {
330             _D("old widget's author signer certificate : %s", (oldCertificate->getBase64()).c_str());
331             _D("new widget's author signer certificate : %s", (newCertificate->getBase64()).c_str());
332             ThrowMsg(Exceptions::NotMatchedCertification,
333                     "Author signer certificates doesn't match \
334                     between old widget and installing widget");
335         }
336     } else {
337         if (!(NULL == newCertificate.Get() && NULL == oldCertificate.Get())) {
338             ThrowMsg(Exceptions::NotMatchedCertification,
339                     "Author signer certificates doesn't match \
340                     between old widget and installing widget");
341         }
342     }
343 }
344
345 void TaskCertify::StartStep()
346 {
347     _D("--------- <TaskCertify> : START ----------");
348 }
349
350 void TaskCertify::EndStep()
351 {
352     _D("Step: <<CERTYFYING DONE>>");
353
354     m_contextData.job->UpdateProgress(
355         InstallerContext::INSTALL_CERT_CHECK,
356         "Widget Certification Check Finished");
357
358     _D("--------- <TaskCertify> : END ----------");
359 }
360 } //namespace WidgetInstall
361 } //namespace Jobs
362