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.
6 #include "xwalk/application/common/tizen/signature_parser.h"
13 #include "base/files/file_util.h"
14 #include "base/logging.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "libxml/parser.h"
18 #include "libxml/xmlschemas.h"
19 #include "libxml/xpathInternals.h"
20 #include "libxml/xmlreader.h"
21 #include "third_party/libxml/chromium/libxml_utils.h"
22 #include "url/url_util.h"
25 const char kExpectedXmlns[] = "http://www.w3.org/2000/09/xmldsig#";
27 const char kTokenSignature[] = "Signature";
28 const char kTokenSignedInfo[] = "SignedInfo";
29 const char kTokenCanonicalizationMethod[] = "CanonicalizationMethod";
30 const char kTokenSignatureMethod[] = "SignatureMethod";
31 const char kTokenReference[] = "Reference";
32 const char kTokenTransforms[] = "Transforms";
33 const char kTokenTransform[] = "Transform";
34 const char kTokenDigestMethod[] = "DigestMethod";
35 const char kTokenDigestValue[] = "DigestValue";
36 const char kTokenSignatureValue[] = "SignatureValue";
37 const char kTokenkeyInfo[] = "KeyInfo";
38 const char kTokenX509Data[] = "X509Data";
39 const char kTokenX509Certificate[] = "X509Certificate";
40 const char kTokenObject[] = "Object";
41 const char kTokenSignatureProperties[] = "SignatureProperties";
42 const char kTokenSignatureProperty[] = "SignatureProperty";
45 const char kTokenAlgorithm[] = "Algorithm";
46 const char kTokenURI[] = "URI";
47 const char kTokenID[] = "Id";
50 const char kTokenAttrProfile[] = "profile";
51 const char kTokenAttrRole[] = "role";
52 const char kTokenAttrIdentifier[] = "identifier";
54 bool TagNameEquals(const xmlNodePtr node,
55 const char* expected_name, const xmlNsPtr expected_namespace) {
56 if (node->ns != expected_namespace)
59 return 0 == strcmp(expected_name, reinterpret_cast<const char*>(node->name));
62 // Returns child nodes of |root| with name |name|.
63 std::vector<xmlNodePtr> GetChildren(
64 const xmlNodePtr root, const xmlNsPtr xml_namespace, const char* name) {
65 std::vector<xmlNodePtr> result;
66 for (xmlNodePtr child = root->children; child != NULL; child = child->next) {
67 if (!TagNameEquals(child, name, xml_namespace))
70 result.push_back(child);
75 // Returns the first child node of |root| with name |name|.
76 xmlNodePtr GetFirstChild(
77 const xmlNodePtr root, const xmlNsPtr xml_namespace, const char* name) {
78 xmlNodePtr result = NULL;
79 for (xmlNodePtr child = root->children; child != NULL; child = child->next) {
80 if (TagNameEquals(child, name, xml_namespace)) {
88 // Returns the value of a named attribute, or the empty string.
89 std::string GetAttribute(
90 const xmlNodePtr node, const char* attribute_name) {
92 reinterpret_cast<const xmlChar*>(attribute_name);
93 for (xmlAttr* attr = node->properties; attr != NULL; attr = attr->next) {
94 if (!xmlStrcmp(attr->name, name) && attr->children &&
95 attr->children->content)
96 return std::string(reinterpret_cast<const char*>(
97 attr->children->content));
102 // Returns a pointer to the xmlNs on |node| with the |expected_href|, or
103 // NULL if there isn't one with that href.
104 xmlNsPtr GetNamespace(const xmlNodePtr node, const char* expected_href) {
105 const xmlChar* href = reinterpret_cast<const xmlChar*>(expected_href);
106 for (xmlNsPtr ns = node->ns; ns != NULL; ns = ns->next) {
107 if (ns->href && !xmlStrcmp(ns->href, href))
116 namespace application {
118 bool ParseSignedInfoElement(
119 const xmlNodePtr node, const xmlNsPtr signature_ns, SignatureData* data) {
120 xmlNodePtr signed_info_node =
121 GetFirstChild(node, signature_ns, kTokenSignedInfo);
122 if (!signed_info_node) {
123 LOG(ERROR) << "Missing SignedInfo tag.";
127 // Parse <CanonicalizationMethod>
128 xmlNodePtr canonicalization_method_node =
129 GetFirstChild(signed_info_node, signature_ns, kTokenCanonicalizationMethod);
130 if (!canonicalization_method_node) {
131 LOG(ERROR) << "Missing SignedInfo tag.";
134 std::string canonicalization_method =
135 GetAttribute(canonicalization_method_node, kTokenAlgorithm);
136 data->set_canonicalization_method(canonicalization_method);
138 // Parse <SignatureMethod>
139 xmlNodePtr signature_method_node =
140 GetFirstChild(signed_info_node, signature_ns, kTokenSignatureMethod);
141 if (!signature_method_node) {
142 LOG(ERROR) << "Missing SignatureMethod tag.";
145 std::string signature_method =
146 GetAttribute(signature_method_node, kTokenAlgorithm);
147 data->set_signature_method(signature_method);
150 std::vector<xmlNodePtr> reference_vec =
151 GetChildren(signed_info_node, signature_ns, kTokenReference);
152 if (reference_vec.empty()) {
153 LOG(ERROR) << "Missing Reference tag.";
158 xmlNodePtr refer_node;
159 std::set<std::string> reference_set;
160 for (size_t i = 0; i < reference_vec.size(); ++i) {
161 refer_node = reference_vec[i];
162 uri = GetAttribute(refer_node, kTokenURI);
164 LOG(ERROR) << "Missing URI attribute.";
167 url::RawCanonOutputW<1024> decoded_uri;
168 url::DecodeURLEscapeSequences(uri.c_str(),
171 base::string16 uri16(decoded_uri.data(),
172 decoded_uri.length());
173 std::string uri8 = base::UTF16ToUTF8(uri16);
177 LOG(WARNING) << "Failing to decode URI.";
179 reference_set.insert(uri);
181 data->set_reference_set(reference_set);
186 bool ParseSignatureValueElement(
187 const xmlNodePtr node, const xmlNsPtr ns, SignatureData* data) {
188 xmlNodePtr sign_value_node = GetFirstChild(node, ns, kTokenSignatureValue);
189 if (!sign_value_node) {
190 LOG(ERROR) << "Missing SignatureValue tag.";
193 std::string signature_value = XmlStringToStdString(
194 xmlNodeGetContent(sign_value_node));
195 data->set_signature_value(signature_value);
199 bool ParseKeyInfoElement(
200 const xmlNodePtr node, const xmlNsPtr ns, SignatureData* data) {
201 xmlNodePtr key_info_node = GetFirstChild(node, ns, kTokenkeyInfo);
202 if (!key_info_node) {
203 LOG(INFO) << "Missing KeyInfo tag, it is allowed by schema.xsd.";
207 // KeyInfo may contain keys, names, certificates and other public key
208 // management. Now I only handle X509 certifcates which is commonly used.
209 // TODO(Xu): Other types of element
210 xmlNodePtr X509_data_node =
211 GetFirstChild(key_info_node, ns, kTokenX509Data);
212 if (!X509_data_node) {
213 LOG(INFO) << "Missing X509Data tag.";
217 // Parse <X509Certificate>
218 std::vector<xmlNodePtr> cert_vec =
219 GetChildren(X509_data_node, ns, kTokenX509Certificate);
220 if (cert_vec.empty()) {
221 LOG(ERROR) << "Missing X509Certificate tag.";
225 std::list<std::string> certificate_list;
226 for (std::vector<xmlNode*>::iterator it = cert_vec.begin();
227 it != cert_vec.end(); ++it) {
228 xmlNodePtr certificate_node = *it;
229 certificate_list.push_back(
230 XmlStringToStdString(xmlNodeGetContent(certificate_node)));
232 data->set_certificate_list(certificate_list);
236 bool ParseObjectElement(
237 const xmlNodePtr node, const xmlNsPtr ns, SignatureData* data) {
238 xmlNodePtr object_node = GetFirstChild(node, ns, kTokenObject);
240 LOG(ERROR) << "Missing Object tag.";
244 std::string object_id = GetAttribute(object_node, kTokenID);
245 data->set_object_id(object_id);
246 // Parse <SignatureProperties>
247 xmlNodePtr properties_node =
248 GetFirstChild(object_node, ns, kTokenSignatureProperties);
249 if (!properties_node) {
250 LOG(ERROR) << "Missing Object tag.";
254 std::vector<xmlNodePtr> prop_vec =
255 GetChildren(properties_node, ns, kTokenSignatureProperty);
256 std::string Id, uri, element_name, profile_uri, role_uri;
257 xmlNodePtr sign_property_node, child;
258 for (size_t i = 0; i < prop_vec.size(); i++) {
259 sign_property_node = prop_vec[i];
260 Id = GetAttribute(sign_property_node, kTokenID);
261 child = sign_property_node->children;
263 LOG(ERROR) << "Failing to find " << element_name
268 if (Id.compare(kTokenAttrProfile) == 0) {
269 profile_uri = GetAttribute(child, kTokenURI);
270 data->set_profile_uri(profile_uri);
272 if (Id.compare(kTokenAttrRole) == 0) {
273 role_uri = GetAttribute(child, kTokenURI);
274 data->set_role_uri(role_uri);
281 bool ParseXML(xmlDocPtr docPtr, SignatureData* data) {
282 xmlNodePtr root = xmlDocGetRootElement(docPtr);
284 LOG(ERROR) << "Missinging root node.";
288 // Look for the required namespace declaration.
289 xmlNsPtr signature_ns = GetNamespace(root, kExpectedXmlns);
291 LOG(ERROR) << "Missinging or incorrect xmlns on signature tag.";
294 if (!TagNameEquals(root, kTokenSignature, signature_ns)) {
295 LOG(ERROR) << "Missinging Signature tag.";
299 if (!ParseSignedInfoElement(root, signature_ns, data))
302 if (!ParseSignatureValueElement(root, signature_ns, data))
305 if (!ParseKeyInfoElement(root, signature_ns, data))
308 if (!ParseObjectElement(root, signature_ns, data))
315 scoped_ptr<SignatureData> SignatureParser::CreateSignatureData(
316 const base::FilePath& signature_path, int signature_number) {
317 std::string file_name = signature_path.MaybeAsASCII();
318 scoped_ptr<SignatureData>
319 data(new SignatureData(file_name, signature_number));
322 xmlDocPtr doc = xmlParseFile(file_name.c_str());
324 LOG(ERROR) << "Opening signature " << file_name << " failed.";
325 return scoped_ptr<SignatureData>();
328 if (!ParseXML(doc, data.get())) {
329 LOG(ERROR) << "Parsering failed.";
331 return scoped_ptr<SignatureData>();
338 } // namespace application