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