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
8 http://www.apache.org/licenses/LICENSE-2.0
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.
22 #include <libxml/parser.h>
23 #include <libxml/tree.h>
24 #include <libxml/uri.h>
32 static const char uri_role_author[] = "http://www.w3.org/ns/widgets-digsig#role-author";
33 static const char uri_role_distributor[] = "http://www.w3.org/ns/widgets-digsig#role-distributor";
34 static const char uri_profile[] = "http://www.w3.org/ns/widgets-digsig#profile";
38 static xmlDocPtr document; /* the document */
40 /* facility to get the first element node (skip text nodes) starting with 'node' */
41 static xmlNodePtr next_element(xmlNodePtr node)
43 while (node && node->type != XML_ELEMENT_NODE)
48 /* is the 'node' an element node of 'name'? */
49 static int is_element(xmlNodePtr node, const char *name)
51 return node->type == XML_ELEMENT_NODE
52 && !strcmp(name, node->name);
55 /* is the 'node' an element node of 'name'? */
56 static int is_node(xmlNodePtr node, const char *name)
58 return node != NULL && is_element(node, name);
62 /* facility to get the first element node (skip text nodes) starting with 'node' */
63 static xmlNodePtr next_element_type(xmlNodePtr node, const char *name)
65 while (node && node->type != XML_ELEMENT_NODE && strcmp(name, node->name))
70 /* search the element node of id. NOTE : not optimized at all */
71 static xmlNodePtr search_for(const char *attrname, const char *value)
74 xmlNodePtr iter, next;
78 iter = xmlDocGetRootElement(document);
79 while (iter != NULL) {
80 val = xmlGetProp(iter, attrname);
81 if (val != NULL && !strcmp(val, value)) {
83 syslog(LOG_ERR, "duplicated %s %s", attrname, value);
90 next = next_element(iter->children);
92 /* no child, try sibling */
93 next = next_element(iter->next);
96 while (iter != NULL && next == NULL) {
97 next = next_element(iter->next);
105 syslog(LOG_ERR, "node of %s '%s' not found", attrname, value);
109 /* search the element node of id. NOTE : not optimized at all */
110 static xmlNodePtr search_id(const char *id)
112 return search_for("Id", id);
116 /* check the digest of one element */
117 static int check_one_reference(xmlNodePtr ref)
122 struct filedesc *fdesc;
128 uri = xmlGetProp(ref, "URI");
130 syslog(LOG_ERR, "attribute URI of element <Reference> not found");
135 u = xmlParseURI(uri);
137 syslog(LOG_ERR, "error while parsing URI %s", uri);
141 /* check that unexpected parts are not there */
142 if (u->scheme || u->opaque || u->authority || u->server || u->user || u->query) {
143 syslog(LOG_ERR, "unexpected uri component in %s", uri);
147 /* check path and fragment */
148 if (!u->path && !u->fragment) {
149 syslog(LOG_ERR, "invalid uri %s", uri);
152 if (u->path && u->fragment) {
153 syslog(LOG_ERR, "not allowed to sign foreign fragment in %s", uri);
158 /* check that the path is valid */
159 fdesc = file_of_name(u->path);
161 syslog(LOG_ERR, "reference to unknown file %s", u->path);
164 if (fdesc->type != type_file) {
165 syslog(LOG_ERR, "reference to directory %s", u->path);
168 if ((fdesc->flags & flag_distributor_signature) != 0) {
169 syslog(LOG_ERR, "reference to signature %s", u->path);
172 fdesc->flags |= flag_referenced;
186 static int check_references(xmlNodePtr sinfo)
190 elem = sinfo->children;
191 while (elem != NULL) {
192 if (is_element(elem, "Reference"))
193 if (check_one_reference(elem))
200 static int get_certificates(xmlNodePtr kinfo)
206 n1 = kinfo->children;
208 if (is_element(n1, "X509Data")) {
211 if (is_element(n2, "X509Certificate")) {
212 b = xmlNodeGetContent(n2);
214 syslog(LOG_ERR, "xmlNodeGetContent of X509Certificate failed");
217 rc = add_certificate_b64(b);
230 /* checks the current document */
231 static int checkdocument()
234 xmlNodePtr sinfo, svalue, kinfo, objs, rootsig;
238 rootsig = xmlDocGetRootElement(document);
239 if (!is_node(rootsig, "Signature")) {
240 syslog(LOG_ERR, "root element <Signature> not found");
244 sinfo = next_element(rootsig->children);
245 if (!is_node(sinfo, "SignedInfo")) {
246 syslog(LOG_ERR, "element <SignedInfo> not found");
250 svalue = next_element(sinfo->next);
251 if (!is_node(svalue, "SignatureValue")) {
252 syslog(LOG_ERR, "element <SignatureValue> not found");
256 kinfo = next_element(svalue->next);
257 if (is_node(kinfo, "KeyInfo")) {
264 rc = check_references(sinfo);
268 rc = xmlsec_verify(rootsig);
272 rc = get_certificates(kinfo);
278 /* verify the digital signature of the file described by 'fdesc' */
279 int verify_digsig(struct filedesc *fdesc)
283 assert ((fdesc->flags & flag_signature) != 0);
284 debug("-- checking file %s",fdesc->name);
286 /* reset the flags */
288 clear_certificates();
290 /* reads and xml parses the signature file */
291 document = xmlReadFile(fdesc->name, NULL, 0);
292 if (document == NULL) {
293 syslog(LOG_ERR, "xml parse of file %s failed", fdesc->name);
297 res = checkdocument();
299 syslog(LOG_ERR, "previous error was during check of file %s", fdesc->name);
301 xmlFreeDoc(document);
305 /* check all the signature files */
306 int check_all_signatures()
310 struct filedesc *fdesc;
312 n = signature_count();
314 for (i = n ; i-- > 0 ; ) {
315 fdesc = signature_of_index(i);
316 irc = verify_digsig(fdesc);
324 /* create a signature of 'index' (0 for author, other values for distributors)
325 using the private 'key' (filename) and the certificates 'certs' (filenames)
327 int create_digsig(int index, const char *key, const char **certs)
329 struct filedesc *fdesc;
336 doc = xmlsec_create(index, key, certs);
340 /* instanciate the filename */
341 fdesc = create_signature(index);
345 /* save the doc as file */
346 len = xmlSaveFormatFileEnc(fdesc->name, doc, NULL, 0);
348 syslog(LOG_ERR, "xmlSaveFormatFileEnc to %s failed", fdesc->name);