Upstream version 9.38.204.0
[platform/framework/web/crosswalk.git] / src / xwalk / application / common / tizen / signature_parser.cc
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Copyright (c) 2014 Intel Corporation.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5
6 #include "xwalk/application/common/tizen/signature_parser.h"
7
8 #include <list>
9 #include <set>
10 #include <string>
11 #include <utility>
12 #include <vector>
13 #include "base/file_util.h"
14 #include "base/logging.h"
15 #include "libxml/parser.h"
16 #include "libxml/xmlschemas.h"
17 #include "libxml/xpathInternals.h"
18 #include "libxml/xmlreader.h"
19 #include "third_party/libxml/chromium/libxml_utils.h"
20
21 namespace {
22 const char kExpectedXmlns[] = "http://www.w3.org/2000/09/xmldsig#";
23 // TAG TOKENS
24 const char kTokenSignature[] = "Signature";
25 const char kTokenSignedInfo[] = "SignedInfo";
26 const char kTokenCanonicalizationMethod[] = "CanonicalizationMethod";
27 const char kTokenSignatureMethod[] = "SignatureMethod";
28 const char kTokenReference[] = "Reference";
29 const char kTokenTransforms[] = "Transforms";
30 const char kTokenTransform[] = "Transform";
31 const char kTokenDigestMethod[] = "DigestMethod";
32 const char kTokenDigestValue[] = "DigestValue";
33 const char kTokenSignatureValue[] = "SignatureValue";
34 const char kTokenkeyInfo[] = "KeyInfo";
35 const char kTokenX509Data[] = "X509Data";
36 const char kTokenX509Certificate[] = "X509Certificate";
37 const char kTokenObject[] = "Object";
38 const char kTokenSignatureProperties[] = "SignatureProperties";
39 const char kTokenSignatureProperty[] = "SignatureProperty";
40
41 // ATTRIBUTE TOKENS
42 const char kTokenAlgorithm[] = "Algorithm";
43 const char kTokenURI[] = "URI";
44 const char kTokenID[] = "Id";
45
46 // ATTRIBUTE VALUES
47 const char kTokenAttrProfile[] = "profile";
48 const char kTokenAttrRole[] = "role";
49 const char kTokenAttrIdentifier[] = "identifier";
50
51 bool TagNameEquals(const xmlNodePtr node,
52     const char* expected_name, const xmlNsPtr expected_namespace) {
53   if (node->ns != expected_namespace)
54     return false;
55
56   return 0 == strcmp(expected_name, reinterpret_cast<const char*>(node->name));
57 }
58
59 // Returns child nodes of |root| with name |name|.
60 std::vector<xmlNodePtr> GetChildren(
61     const xmlNodePtr root, const xmlNsPtr xml_namespace, const char* name) {
62   std::vector<xmlNodePtr> result;
63   for (xmlNodePtr child = root->children; child != NULL; child = child->next) {
64     if (!TagNameEquals(child, name, xml_namespace))
65       continue;
66
67     result.push_back(child);
68   }
69   return result;
70 }
71
72 // Returns the first child node of |root| with name |name|.
73 xmlNodePtr GetFirstChild(
74     const xmlNodePtr root, const xmlNsPtr xml_namespace, const char* name) {
75   xmlNodePtr result = NULL;
76   for (xmlNodePtr child = root->children; child != NULL; child = child->next) {
77     if (TagNameEquals(child, name, xml_namespace)) {
78       result = child;
79       break;
80     }
81   }
82   return result;
83 }
84
85 // Returns the value of a named attribute, or the empty string.
86 std::string GetAttribute(
87     const xmlNodePtr node, const char* attribute_name) {
88   const xmlChar* name =
89     reinterpret_cast<const xmlChar*>(attribute_name);
90   for (xmlAttr* attr = node->properties; attr != NULL; attr = attr->next) {
91     if (!xmlStrcmp(attr->name, name) && attr->children &&
92         attr->children->content)
93       return std::string(reinterpret_cast<const char*>(
94             attr->children->content));
95   }
96   return std::string();
97 }
98
99 // Returns a pointer to the xmlNs on |node| with the |expected_href|, or
100 // NULL if there isn't one with that href.
101 xmlNsPtr GetNamespace(const xmlNodePtr node, const char* expected_href) {
102   const xmlChar* href = reinterpret_cast<const xmlChar*>(expected_href);
103   for (xmlNsPtr ns = node->ns; ns != NULL; ns = ns->next) {
104     if (ns->href && !xmlStrcmp(ns->href, href))
105       return ns;
106   }
107   return NULL;
108 }
109
110 }  // namespace
111
112 namespace xwalk {
113 namespace application {
114 bool ParseSignedInfoElement(
115     const xmlNodePtr node, const xmlNsPtr signature_ns, SignatureData* data) {
116   xmlNodePtr signed_info_node =
117     GetFirstChild(node, signature_ns, kTokenSignedInfo);
118   if (!signed_info_node) {
119     LOG(ERROR) << "Missing SignedInfo tag.";
120     return false;
121   }
122
123   // Parse <CanonicalizationMethod>
124   xmlNodePtr canonicalization_method_node =
125     GetFirstChild(signed_info_node, signature_ns, kTokenCanonicalizationMethod);
126   if (!canonicalization_method_node) {
127     LOG(ERROR) << "Missing SignedInfo tag.";
128     return false;
129   }
130   std::string canonicalization_method =
131     GetAttribute(canonicalization_method_node, kTokenAlgorithm);
132   data->set_canonicalization_method(canonicalization_method);
133
134   // Parse <SignatureMethod>
135   xmlNodePtr signature_method_node =
136     GetFirstChild(signed_info_node, signature_ns, kTokenSignatureMethod);
137   if (!signature_method_node) {
138     LOG(ERROR) << "Missing SignatureMethod tag.";
139     return false;
140   }
141   std::string signature_method =
142     GetAttribute(signature_method_node, kTokenAlgorithm);
143   data->set_signature_method(signature_method);
144
145   // Parse <Reference>
146   std::vector<xmlNodePtr> reference_vec =
147     GetChildren(signed_info_node, signature_ns, kTokenReference);
148   if (reference_vec.empty()) {
149     LOG(ERROR) << "Missing Reference tag.";
150     return false;
151   }
152
153   std::string uri;
154   xmlNodePtr refer_node;
155   std::set<std::string> reference_set;
156   for (size_t i = 0; i < reference_vec.size(); ++i) {
157     refer_node = reference_vec[i];
158     uri = GetAttribute(refer_node, kTokenURI);
159     if (uri.empty()) {
160       LOG(ERROR) << "Missing URI attribute.";
161       return false;
162     }
163     reference_set.insert(uri);
164   }
165   data->set_reference_set(reference_set);
166
167   return true;
168 }
169
170 bool ParseSignatureValueElement(
171     const xmlNodePtr node, const xmlNsPtr ns, SignatureData* data) {
172   xmlNodePtr sign_value_node = GetFirstChild(node, ns, kTokenSignatureValue);
173   if (!sign_value_node) {
174     LOG(ERROR) << "Missing SignatureValue tag.";
175     return false;
176   }
177   std::string signature_value = XmlStringToStdString(
178       xmlNodeGetContent(sign_value_node));
179   data->set_signature_value(signature_value);
180   return true;
181 }
182
183 bool ParseKeyInfoElement(
184     const xmlNodePtr node, const xmlNsPtr ns, SignatureData* data) {
185   xmlNodePtr key_info_node = GetFirstChild(node, ns, kTokenkeyInfo);
186   if (!key_info_node) {
187     LOG(INFO) << "Missing KeyInfo tag, it is allowed by schema.xsd.";
188     return true;
189   }
190
191   // KeyInfo may contain keys, names, certificates and other public key
192   // management. Now I only handle X509 certifcates which is commonly used.
193   // TODO(Xu): Other types of element
194   xmlNodePtr X509_data_node =
195     GetFirstChild(key_info_node, ns, kTokenX509Data);
196   if (!X509_data_node) {
197     LOG(INFO) << "Missing X509Data tag.";
198     return true;
199   }
200
201   // Parse <X509Certificate>
202   std::vector<xmlNodePtr> cert_vec =
203     GetChildren(X509_data_node, ns, kTokenX509Certificate);
204   if (cert_vec.empty()) {
205     LOG(ERROR) << "Missing X509Certificate tag.";
206     return false;
207   }
208
209   std::list<std::string> certificate_list;
210   for (std::vector<xmlNode*>::iterator it = cert_vec.begin();
211       it != cert_vec.end(); ++it) {
212     xmlNodePtr certificate_node = *it;
213     certificate_list.push_back(
214         XmlStringToStdString(xmlNodeGetContent(certificate_node)));
215   }
216   data->set_certificate_list(certificate_list);
217   return true;
218 }
219
220 bool ParseObjectElement(
221     const xmlNodePtr node, const xmlNsPtr ns, SignatureData* data) {
222   xmlNodePtr object_node = GetFirstChild(node, ns, kTokenObject);
223   if (!object_node) {
224     LOG(ERROR) << "Missing Object tag.";
225     return false;
226   }
227
228   std::string object_id = GetAttribute(object_node, kTokenID);
229   data->set_object_id(object_id);
230   // Parse <SignatureProperties>
231   xmlNodePtr properties_node =
232     GetFirstChild(object_node, ns, kTokenSignatureProperties);
233   if (!properties_node) {
234     LOG(ERROR) << "Missing Object tag.";
235     return false;
236   }
237
238   std::vector<xmlNodePtr> prop_vec =
239     GetChildren(properties_node, ns, kTokenSignatureProperty);
240   std::string Id, uri, element_name, profile_uri, role_uri;
241   xmlNodePtr sign_property_node, child;
242   for (size_t i = 0; i < prop_vec.size(); i++) {
243     sign_property_node = prop_vec[i];
244     Id = GetAttribute(sign_property_node, kTokenID);
245     child = sign_property_node->children;
246     if (!child) {
247       LOG(ERROR) << "Failing to find " << element_name
248         << "  element.";
249       return false;
250     }
251
252     if (Id.compare(kTokenAttrProfile) == 0) {
253       profile_uri = GetAttribute(child, kTokenURI);
254       data->set_profile_uri(profile_uri);
255     }
256     if (Id.compare(kTokenAttrRole) == 0) {
257       role_uri = GetAttribute(child, kTokenURI);
258       data->set_role_uri(role_uri);
259     }
260   }
261
262   return true;
263 }
264
265 bool ParseXML(xmlDocPtr docPtr, SignatureData* data) {
266   xmlNodePtr root = xmlDocGetRootElement(docPtr);
267   if (!root) {
268     LOG(ERROR) << "Missinging root node.";
269     return false;
270   }
271
272   // Look for the required namespace declaration.
273   xmlNsPtr signature_ns = GetNamespace(root, kExpectedXmlns);
274   if (!signature_ns) {
275     LOG(ERROR) << "Missinging or incorrect xmlns on signature tag.";
276     return false;
277   }
278   if (!TagNameEquals(root, kTokenSignature, signature_ns)) {
279     LOG(ERROR) << "Missinging Signature tag.";
280     return false;
281   }
282
283   if (!ParseSignedInfoElement(root, signature_ns, data))
284     return false;
285
286   if (!ParseSignatureValueElement(root, signature_ns, data))
287     return false;
288
289   if (!ParseKeyInfoElement(root, signature_ns, data))
290     return false;
291
292   if (!ParseObjectElement(root, signature_ns, data))
293     return false;
294
295   return true;
296 }
297
298 // static
299 scoped_ptr<SignatureData> SignatureParser::CreateSignatureData(
300     const base::FilePath& signature_path, int signature_number) {
301   std::string file_name = signature_path.MaybeAsASCII();
302   scoped_ptr<SignatureData>
303     data(new SignatureData(file_name, signature_number));
304
305   xmlInitParser();
306   xmlDocPtr doc = xmlParseFile(file_name.c_str());
307   if (!doc) {
308     LOG(ERROR) << "Opening signature " << file_name << " failed.";
309     return scoped_ptr<SignatureData>();
310   }
311
312   if (!ParseXML(doc, data.get())) {
313     LOG(ERROR) << "Parsering failed.";
314     xmlFreeDoc(doc);
315     return scoped_ptr<SignatureData>();
316   }
317
318   xmlFreeDoc(doc);
319   xmlCleanupParser();
320   return data.Pass();
321 }
322 }  // namespace application
323 }  // namespace xwalk