Upstream version 10.38.208.0
[platform/framework/web/crosswalk.git] / src / xwalk / application / common / tizen / signature_xmlsec_adaptor.cc
1 // Copyright (c) 2014 Intel Corporation. All rights reserved.
2 // Copyright (C) 2002-2003 Aleksey Sanin.  All Rights Reserved.
3 //
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
6
7 #include "xwalk/application/common/tizen/signature_xmlsec_adaptor.h"
8
9 #include <list>
10 #include <map>
11 #include <string>
12 #include <utility>
13
14 #include "base/logging.h"
15 #include "base/file_util.h"
16 #include "base/files/file_path.h"
17 #include "net/cert/x509_certificate.h"
18 #include "libxml/parser.h"
19 #include "xmlsec/crypto.h"
20 #include "xmlsec/io.h"
21 #include "xmlsec/keysmngr.h"
22 #include "xmlsec/xmlsec.h"
23 #include "xmlsec/xmltree.h"
24 #include "xmlsec/xmldsig.h"
25 #ifndef XMLSEC_NO_XSLT
26 #include "libxslt/xslt.h"
27 #endif  // XMLSEC_NO_XSLT
28
29 namespace {
30
31 // TODO(XU): Once tizen platform provide certificate manager util APIs,
32 // we should call API from system to query certificate's file path.
33 class CertificateUtil {
34  public:
35   static const std::map<std::string, std::string>& certificate_path() {
36     return certificate_path_;
37   }
38
39  private:
40   static std::map<std::string, std::string> InitCertificatePath() {
41     std::map<std::string, std::string> root_certificates;
42     root_certificates["Tizen Partner-Manufacturer Distributor Root CA"] =
43         "tizen-distributor-root-ca-partner-manufacturer.pem";
44     root_certificates["SLP WebApp Temporary CA"] =
45         "tizen.root.preproduction.cert.pem";
46     root_certificates["Tizen Test Developer Root CA"] =
47         "tizen-developer-root-ca.pem";
48     root_certificates["Tizen Developers Root"] =
49         "tizen-developers-root.pem";
50     root_certificates["Tizen Partner Distributor Root CA"] =
51         "tizen-distributor-root-ca-partner.pem";
52     root_certificates["Tizen Partner-Operator Distributor Root CA"] =
53         "tizen-distributor-root-ca-partner-operator.pem";
54     root_certificates["Tizen Public Distributor Root CA"] =
55         "tizen-distributor-root-ca-public.pem";
56     root_certificates["Partner Class Developer Root"] =
57         "tizen-partner-class-developer-root.pem";
58     root_certificates["Partner Class Root Authority"] =
59         "tizen-partner-class-root-authority.pem";
60     root_certificates["Platform Class Developer Root"] =
61         "tizen-platform-class-developer-root.pem";
62     root_certificates["Platform Class Root Authority"] =
63         "tizen-platform-class-root-authority.pem";
64     root_certificates["Public Class Developer Root"] =
65         "tizen-public-class-developer-root.pem";
66     root_certificates["Public Class Root Authority"] =
67         "tizen-public-class-root-authority.pem";
68
69     return root_certificates;
70   }
71
72   static std::map<std::string, std::string> certificate_path_;
73 };
74
75 std::map<std::string, std::string>
76     CertificateUtil::certificate_path_ = InitCertificatePath();
77
78 class XmlSecContext {
79  public:
80   static void GetExtractedPath(const xwalk::application::SignatureData& data);
81   static xmlSecKeysMngrPtr LoadTrustedCerts(
82       const xwalk::application::SignatureData& signature_data);
83   static int VerifyFile(
84       xmlSecKeysMngrPtr mngr, const xwalk::application::SignatureData& data);
85
86  private:
87   static int FileMatchCallback(const char* file_name);
88   static void* FileOpenCallback(const char* file_name);
89   static int FileReadCallback(void* context, char* buffer, int len);
90   static int FileCloseCallback(void* context);
91   static void ConvertToPemCert(std::string* cert);
92   static base::FilePath GetCertFromStore(const std::string& subject);
93
94   static std::string prefix_path_;
95   static std::pair<void*, bool> file_wrapper_;
96 };
97
98 std::string XmlSecContext::prefix_path_;
99 std::pair<void*, bool> XmlSecContext::file_wrapper_;
100
101 void XmlSecContext::GetExtractedPath(
102     const xwalk::application::SignatureData& data) {
103   XmlSecContext::prefix_path_ = data.GetExtractedWidgetPath().MaybeAsASCII();
104 }
105
106 int XmlSecContext::FileMatchCallback(const char* file_name) {
107   std::string path = XmlSecContext::prefix_path_ + std::string(file_name);
108   return xmlFileMatch(path.c_str());
109 }
110
111 void* XmlSecContext::FileOpenCallback(const char* file_name) {
112   std::string path = XmlSecContext::prefix_path_ + std::string(file_name);
113   XmlSecContext::file_wrapper_ =
114       std::make_pair(xmlFileOpen(path.c_str()), false);
115   return &(XmlSecContext::file_wrapper_);
116 }
117
118 int XmlSecContext::FileReadCallback(void* context, char* buffer, int len) {
119   std::pair<void*, bool>* file_wrapper =
120       static_cast<std::pair<void*, bool>*>(context);
121   DCHECK(file_wrapper);
122   if (file_wrapper->second)
123     return 0;
124
125   int output = xmlFileRead(file_wrapper->first, buffer, len);
126   if (output == 0) {
127     file_wrapper->second = true;
128     xmlFileClose(file_wrapper->first);
129   }
130   return output;
131 }
132
133 int XmlSecContext::FileCloseCallback(void* context) {
134   std::pair<void*, bool>* file_wrapper =
135       static_cast<std::pair<void*, bool>*>(context);
136   DCHECK(file_wrapper);
137   int output = 0;
138   if (!file_wrapper->second)
139     output = xmlFileClose(file_wrapper->first);
140
141   return output;
142 }
143
144 xmlSecKeysMngrPtr XmlSecContext::LoadTrustedCerts(
145     const xwalk::application::SignatureData& signature_data) {
146   xmlSecKeysMngrPtr mngr = xmlSecKeysMngrCreate();
147   if (!mngr) {
148     LOG(ERROR) << "Error: failed to create keys manager.";
149     return NULL;
150   }
151   if (xmlSecCryptoAppDefaultKeysMngrInit(mngr) < 0) {
152     LOG(ERROR) << "Error: failed to initialize keys manager.";
153     xmlSecKeysMngrDestroy(mngr);
154     return NULL;
155   }
156
157   std::list<std::string> certificate_list = signature_data.certificate_list();
158   std::string cert;
159   std::string issuer;
160   for (std::list<std::string>::iterator it = certificate_list.begin();
161       it != certificate_list.end(); ++it) {
162     cert = *it;
163     XmlSecContext::ConvertToPemCert(&cert);
164     net::CertificateList certs =
165         net::X509Certificate::CreateCertificateListFromBytes(
166             cert.data(), cert.length(), net::X509Certificate::FORMAT_AUTO);
167     issuer = certs[0]->issuer().GetDisplayName();
168
169     if (xmlSecCryptoAppKeysMngrCertLoadMemory(mngr,
170         reinterpret_cast<const unsigned char*>(cert.c_str()), cert.size(),
171         xmlSecKeyDataFormatCertPem, xmlSecKeyDataTypeTrusted) < 0) {
172       LOG(ERROR) << "Error: failed to load pem certificate.";
173       xmlSecKeysMngrDestroy(mngr);
174       return NULL;
175     }
176   }
177
178   const base::FilePath& root_cert_path =
179       XmlSecContext::GetCertFromStore(issuer);
180   if (!base::PathExists(root_cert_path)) {
181     LOG(ERROR) << "Failed to find root certificate.";
182     return NULL;
183   }
184
185   if (xmlSecCryptoAppKeysMngrCertLoad(mngr,
186       root_cert_path.MaybeAsASCII().c_str(), xmlSecKeyDataFormatPem,
187       xmlSecKeyDataTypeTrusted) < 0) {
188     LOG(ERROR) << "Error: failed to load root certificate";
189     xmlSecKeysMngrDestroy(mngr);
190     return NULL;
191   }
192
193   return mngr;
194 }
195
196 // Verifies XML signature in #xml_file
197 // Returns 0 on success or a negative value if an error occurs.
198 int XmlSecContext::VerifyFile(xmlSecKeysMngrPtr mngr,
199                               const xwalk::application::SignatureData& data) {
200   LOG(INFO) << "Verify " << data.signature_file_name();
201   xmlSecIOCleanupCallbacks();
202   XmlSecContext::GetExtractedPath(data);
203   xmlSecIORegisterCallbacks(
204       XmlSecContext::FileMatchCallback,
205       XmlSecContext::FileOpenCallback,
206       XmlSecContext::FileReadCallback,
207       XmlSecContext::FileCloseCallback);
208
209   xmlDocPtr doc = xmlParseFile(data.signature_file_name().c_str());
210   if (!doc) {
211     LOG(ERROR) << "Error: failed to parse " << data.signature_file_name();
212     return -1;
213   }
214
215   if (!xmlDocGetRootElement(doc)) {
216     LOG(ERROR) << "Error: unable to get root element.";
217     xmlFreeDoc(doc);
218     return -1;
219   }
220
221   xmlNodePtr node = xmlSecFindNode(
222       xmlDocGetRootElement(doc), xmlSecNodeSignature, xmlSecDSigNs);
223   if (!node) {
224     LOG(ERROR) << "Error: unable to find SecNodeSignature node.";
225     xmlFreeDoc(doc);
226     return -1;
227   }
228
229   xmlSecDSigCtxPtr dsig_ctx = xmlSecDSigCtxCreate(mngr);
230   if (!dsig_ctx) {
231     LOG(ERROR) << "Error: failed to create signature context.";
232     xmlFreeDoc(doc);
233     return -1;
234   }
235
236   if (xmlSecDSigCtxVerify(dsig_ctx, node) < 0) {
237     LOG(ERROR) << "Error: signature verify.";
238     xmlFreeDoc(doc);
239     xmlSecDSigCtxDestroy(dsig_ctx);
240     return -1;
241   }
242
243   int res = -1;
244   if (dsig_ctx->status != xmlSecDSigStatusSucceeded)
245     LOG(ERROR) << "Signature " << data.signature_file_name() <<" is INVALID";
246
247   LOG(INFO) << "Signature  "<< data.signature_file_name() << " is OK.";
248   res = 0;
249
250   xmlFreeDoc(doc);
251   xmlSecDSigCtxDestroy(dsig_ctx);
252   return res;
253 }
254
255 void XmlSecContext::ConvertToPemCert(std::string* cert) {
256   *cert = "-----BEGIN CERTIFICATE-----" + *cert;
257   *cert = *cert + "-----END CERTIFICATE-----";
258 }
259
260 base::FilePath XmlSecContext::GetCertFromStore(const std::string& subject) {
261   const char cert_prefix_path[] = "/usr/share/ca-certificates/tizen/";
262   std::map<std::string, std::string>::const_iterator iter =
263       CertificateUtil::certificate_path().find(subject);
264
265   if (iter == CertificateUtil::certificate_path().end()) {
266     LOG(ERROR) << "Failing to find root certificate.";
267     return base::FilePath("");
268   }
269   LOG(INFO) << "root cert path is " << cert_prefix_path + iter->second;
270   return base::FilePath(cert_prefix_path + iter->second);
271 }
272
273 }  // namespace
274
275 namespace xwalk {
276 namespace application {
277
278 // static
279 bool SignatureXmlSecAdaptor::ValidateFile(
280     const SignatureData& signature_data, const base::FilePath& widget_path) {
281   xmlInitParser();
282   xmlSubstituteEntitiesDefault(1);
283 #ifndef XMLSEC_NO_XSLT
284   xsltSecurityPrefsPtr xslt_sec_prefs = xsltNewSecurityPrefs();
285   xsltSetSecurityPrefs(
286       xslt_sec_prefs, XSLT_SECPREF_READ_FILE, xsltSecurityForbid);
287   xsltSetSecurityPrefs(
288       xslt_sec_prefs, XSLT_SECPREF_WRITE_FILE, xsltSecurityForbid);
289   xsltSetSecurityPrefs(
290       xslt_sec_prefs, XSLT_SECPREF_CREATE_DIRECTORY, xsltSecurityForbid);
291   xsltSetSecurityPrefs(
292       xslt_sec_prefs, XSLT_SECPREF_READ_NETWORK, xsltSecurityForbid);
293   xsltSetSecurityPrefs(
294       xslt_sec_prefs, XSLT_SECPREF_WRITE_NETWORK, xsltSecurityForbid);
295   xsltSetDefaultSecurityPrefs(xslt_sec_prefs);
296 #endif  // XMLSEC_NO_XSLT
297
298   if (xmlSecInit() < 0) {
299     LOG(ERROR) << "Error: xmlsec initialization failed.";
300     return false;
301   }
302
303   if (xmlSecCheckVersion() != 1) {
304     LOG(ERROR) << "Error: loaded xmlsec library version is not compatible.";
305     return false;
306   }
307
308 #ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING
309   if (xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) {
310     LOG(ERROR) << "Error: unable to load default xmlsec-crypto library.";
311     return false;
312   }
313 #endif  // XMLSEC_CRYPTO_DYNAMIC_LOADING
314
315   if (xmlSecCryptoAppInit(NULL) < 0) {
316     LOG(ERROR) << "Error: crypto initialization failed.";
317     return false;
318   }
319
320   if (xmlSecCryptoInit() < 0) {
321     LOG(ERROR) << "Error: xmlsec-crypto initialization failed.";
322     return false;
323   }
324
325   xmlSecKeysMngrPtr mngr = XmlSecContext::LoadTrustedCerts(signature_data);
326   if (!mngr)
327     return false;
328
329   if (XmlSecContext::VerifyFile(mngr, signature_data) < 0) {
330     xmlSecKeysMngrDestroy(mngr);
331     return false;
332   }
333
334   xmlSecKeysMngrDestroy(mngr);
335   xmlSecCryptoShutdown();
336   xmlSecCryptoAppShutdown();
337   xmlSecShutdown();
338
339 #ifndef XMLSEC_NO_XSLT
340   xsltFreeSecurityPrefs(xslt_sec_prefs);
341   xsltCleanupGlobals();
342 #endif  // XMLSEC_NO_XSLT
343   xmlCleanupParser();
344
345   return true;
346 }
347
348 }  // namespace application
349 }  // namespace xwalk