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