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.
23 #include <libxml/parser.h>
24 #include <libxml/tree.h>
25 #include <libxml/uri.h>
26 #include <libxml/xmlsave.h>
34 static const char uri_role_author[] = "http://www.w3.org/ns/widgets-digsig#role-author";
35 static const char uri_role_distributor[] = "http://www.w3.org/ns/widgets-digsig#role-distributor";
36 static const char uri_profile[] = "http://www.w3.org/ns/widgets-digsig#profile";
40 static xmlDocPtr document; /* the document */
42 /* facility to get the first element node (skip text nodes) starting with 'node' */
43 static xmlNodePtr next_element(xmlNodePtr node)
45 while (node && node->type != XML_ELEMENT_NODE)
50 /* is the 'node' an element node of 'name'? */
51 static int is_element(xmlNodePtr node, const char *name)
53 return node->type == XML_ELEMENT_NODE
54 && !strcmp(name, node->name);
57 /* is the 'node' an element node of 'name'? */
58 static int is_node(xmlNodePtr node, const char *name)
60 return node != NULL && is_element(node, name);
64 /* facility to get the first element node (skip text nodes) starting with 'node' */
65 static xmlNodePtr next_element_type(xmlNodePtr node, const char *name)
67 while (node && node->type != XML_ELEMENT_NODE && strcmp(name, node->name))
72 /* search the element node of id. NOTE : not optimized at all */
73 static xmlNodePtr search_for(const char *attrname, const char *value)
76 xmlNodePtr iter, next;
80 iter = xmlDocGetRootElement(document);
81 while (iter != NULL) {
82 val = xmlGetProp(iter, attrname);
83 if (val != NULL && !strcmp(val, value)) {
85 ERROR("duplicated %s %s", attrname, value);
92 next = next_element(iter->children);
94 /* no child, try sibling */
95 next = next_element(iter->next);
98 while (iter != NULL && next == NULL) {
99 next = next_element(iter->next);
107 ERROR("node of %s '%s' not found", attrname, value);
111 /* search the element node of id. NOTE : not optimized at all */
112 static xmlNodePtr search_id(const char *id)
114 return search_for("Id", id);
118 /* check the digest of one element */
119 static int check_one_reference(xmlNodePtr ref)
124 struct filedesc *fdesc;
130 uri = xmlGetProp(ref, "URI");
132 ERROR("attribute URI of element <Reference> not found");
137 u = xmlParseURI(uri);
139 ERROR("error while parsing URI %s", uri);
143 /* check that unexpected parts are not there */
144 if (u->scheme || u->opaque || u->authority || u->server || u->user || u->query) {
145 ERROR("unexpected uri component in %s", uri);
149 /* check path and fragment */
150 if (!u->path && !u->fragment) {
151 ERROR("invalid uri %s", uri);
154 if (u->path && u->fragment) {
155 ERROR("not allowed to sign foreign fragment in %s", uri);
160 /* check that the path is valid */
161 fdesc = file_of_name(u->path);
163 ERROR("reference to unknown file %s", u->path);
166 if (fdesc->type != type_file) {
167 ERROR("reference to directory %s", u->path);
170 if ((fdesc->flags & flag_distributor_signature) != 0) {
171 ERROR("reference to signature %s", u->path);
174 fdesc->flags |= flag_referenced;
188 static int check_references(xmlNodePtr sinfo)
190 unsigned int i, n, flags;
196 elem = sinfo->children;
197 while (elem != NULL) {
198 if (is_element(elem, "Reference"))
199 if (check_one_reference(elem))
207 f = file_of_index(i++);
208 if (f->type == type_file) {
210 if (!(flags & (flag_signature | flag_referenced))) {
211 ERROR("file not referenced in signature: %s", f->name);
221 static int get_certificates(xmlNodePtr kinfo)
227 n1 = kinfo->children;
229 if (is_element(n1, "X509Data")) {
232 if (is_element(n2, "X509Certificate")) {
233 b = xmlNodeGetContent(n2);
235 ERROR("xmlNodeGetContent of X509Certificate failed");
238 rc = add_certificate_b64(b);
251 /* checks the current document */
252 static int checkdocument()
255 xmlNodePtr sinfo, svalue, kinfo, objs, rootsig;
259 rootsig = xmlDocGetRootElement(document);
260 if (!is_node(rootsig, "Signature")) {
261 ERROR("root element <Signature> not found");
265 sinfo = next_element(rootsig->children);
266 if (!is_node(sinfo, "SignedInfo")) {
267 ERROR("element <SignedInfo> not found");
271 svalue = next_element(sinfo->next);
272 if (!is_node(svalue, "SignatureValue")) {
273 ERROR("element <SignatureValue> not found");
277 kinfo = next_element(svalue->next);
278 if (is_node(kinfo, "KeyInfo")) {
285 rc = check_references(sinfo);
289 rc = xmlsec_verify(rootsig);
293 rc = get_certificates(kinfo);
299 /* verify the digital signature of the file described by 'fdesc' */
300 int verify_digsig(struct filedesc *fdesc)
304 assert ((fdesc->flags & flag_signature) != 0);
305 DEBUG("-- checking file %s",fdesc->name);
307 /* reset the flags */
309 clear_certificates();
311 /* reads and xml parses the signature file */
312 fd = openat(workdirfd, fdesc->name, O_RDONLY);
314 ERROR("cant't open file %s", fdesc->name);
317 document = xmlReadFd(fd, fdesc->name, NULL, 0);
319 if (document == NULL) {
320 ERROR("xml parse of file %s failed", fdesc->name);
324 res = checkdocument();
326 ERROR("previous error was during check of file %s", fdesc->name);
328 xmlFreeDoc(document);
332 /* check all the signature files */
333 int check_all_signatures()
337 struct filedesc *fdesc;
339 n = signature_count();
341 for (i = n ; i-- > 0 ; ) {
342 fdesc = signature_of_index(i);
343 irc = verify_digsig(fdesc);
351 /* create a signature of 'index' (0 for author, other values for distributors)
352 using the private 'key' (filename) and the certificates 'certs' (filenames)
354 int create_digsig(int index, const char *key, const char **certs)
356 struct filedesc *fdesc;
364 doc = xmlsec_create(index, key, certs);
368 /* instanciate the filename */
369 fdesc = create_signature(index);
373 /* save the doc as file */
374 fd = openat(workdirfd, fdesc->name, O_WRONLY|O_CREAT|O_TRUNC, 0644);
376 ERROR("cant open %s for write", fdesc->name);
379 ctx = xmlSaveToFd(fd, NULL, XML_SAVE_FORMAT);
381 ERROR("xmlSaveToFd failed for %s", fdesc->name);
384 len = xmlSaveDoc(ctx, doc);
386 ERROR("xmlSaveDoc to %s failed", fdesc->name);