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/installer/signature_parser.h"
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"
22 const char kExpectedXmlns[] = "http://www.w3.org/2000/09/xmldsig#";
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";
42 const char kTokenAlgorithm[] = "Algorithm";
43 const char kTokenURI[] = "URI";
44 const char kTokenID[] = "Id";
47 const char kTokenAttrProfile[] = "profile";
48 const char kTokenAttrRole[] = "role";
49 const char kTokenAttrIdentifier[] = "identifier";
51 bool TagNameEquals(const xmlNodePtr node,
52 const char* expected_name, const xmlNsPtr expected_namespace) {
53 if (node->ns != expected_namespace)
56 return 0 == strcmp(expected_name, reinterpret_cast<const char*>(node->name));
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))
67 result.push_back(child);
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)) {
85 // Returns the value of a named attribute, or the empty string.
86 std::string GetAttribute(
87 const xmlNodePtr node, const char* attribute_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));
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))
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.";
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.";
130 std::string canonicalization_method =
131 GetAttribute(canonicalization_method_node, kTokenAlgorithm);
132 data->set_canonicalization_method(canonicalization_method);
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.";
141 std::string signature_method =
142 GetAttribute(signature_method_node, kTokenAlgorithm);
143 data->set_signature_method(signature_method);
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.";
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);
160 LOG(ERROR) << "Missing URI attribute.";
163 reference_set.insert(uri);
165 data->set_reference_set(reference_set);
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.";
177 std::string signature_value = XmlStringToStdString(
178 xmlNodeGetContent(sign_value_node));
179 data->set_signature_value(signature_value);
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.";
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.";
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.";
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)));
216 data->set_certificate_list(certificate_list);
220 bool ParseObjectElement(
221 const xmlNodePtr node, const xmlNsPtr ns, SignatureData* data) {
222 xmlNodePtr object_node = GetFirstChild(node, ns, kTokenObject);
224 LOG(ERROR) << "Missing Object tag.";
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.";
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;
247 LOG(ERROR) << "Failing to find " << element_name
252 if (Id.compare(kTokenAttrProfile) == 0) {
253 profile_uri = GetAttribute(child, kTokenURI);
254 data->set_profile_uri(profile_uri);
256 if (Id.compare(kTokenAttrRole) == 0) {
257 role_uri = GetAttribute(child, kTokenURI);
258 data->set_role_uri(role_uri);
265 bool ParseXML(xmlDocPtr docPtr, SignatureData* data) {
266 xmlNodePtr root = xmlDocGetRootElement(docPtr);
268 LOG(ERROR) << "Missinging root node.";
272 // Look for the required namespace declaration.
273 xmlNsPtr signature_ns = GetNamespace(root, kExpectedXmlns);
275 LOG(ERROR) << "Missinging or incorrect xmlns on signature tag.";
278 if (!TagNameEquals(root, kTokenSignature, signature_ns)) {
279 LOG(ERROR) << "Missinging Signature tag.";
283 if (!ParseSignedInfoElement(root, signature_ns, data))
286 if (!ParseSignatureValueElement(root, signature_ns, data))
289 if (!ParseKeyInfoElement(root, signature_ns, data))
292 if (!ParseObjectElement(root, signature_ns, data))
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));
306 xmlDocPtr doc = xmlParseFile(file_name.c_str());
308 LOG(ERROR) << "Opening signature " << file_name << " failed.";
309 return scoped_ptr<SignatureData>();
312 if (!ParseXML(doc, data.get())) {
313 LOG(ERROR) << "Parsering failed.";
315 return scoped_ptr<SignatureData>();
322 } // namespace application