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.
24 #include <libxml/parser.h>
25 #include <libxml/tree.h>
26 #include <libxml/uri.h>
27 #include <libxml/xmlsave.h>
35 static const char uri_role_author[] = "http://www.w3.org/ns/widgets-digsig#role-author";
36 static const char uri_role_distributor[] = "http://www.w3.org/ns/widgets-digsig#role-distributor";
37 static const char uri_profile[] = "http://www.w3.org/ns/widgets-digsig#profile";
41 static xmlDocPtr document; /* the document */
43 /* facility to get the first element node (skip text nodes) starting with 'node' */
44 static xmlNodePtr next_element(xmlNodePtr node)
46 while (node && node->type != XML_ELEMENT_NODE)
51 /* is the 'node' an element node of 'name'? */
52 static int is_element(xmlNodePtr node, const char *name)
54 return node->type == XML_ELEMENT_NODE
55 && !strcmp(name, node->name);
58 /* is the 'node' an element node of 'name'? */
59 static int is_node(xmlNodePtr node, const char *name)
61 return node != NULL && is_element(node, name);
65 /* facility to get the first element node (skip text nodes) starting with 'node' */
66 static xmlNodePtr next_element_type(xmlNodePtr node, const char *name)
68 while (node && node->type != XML_ELEMENT_NODE && strcmp(name, node->name))
73 /* search the element node of id. NOTE : not optimized at all */
74 static xmlNodePtr search_for(const char *attrname, const char *value)
77 xmlNodePtr iter, next;
81 iter = xmlDocGetRootElement(document);
82 while (iter != NULL) {
83 val = xmlGetProp(iter, attrname);
84 if (val != NULL && !strcmp(val, value)) {
86 syslog(LOG_ERR, "duplicated %s %s", attrname, value);
93 next = next_element(iter->children);
95 /* no child, try sibling */
96 next = next_element(iter->next);
99 while (iter != NULL && next == NULL) {
100 next = next_element(iter->next);
108 syslog(LOG_ERR, "node of %s '%s' not found", attrname, value);
112 /* search the element node of id. NOTE : not optimized at all */
113 static xmlNodePtr search_id(const char *id)
115 return search_for("Id", id);
119 /* check the digest of one element */
120 static int check_one_reference(xmlNodePtr ref)
125 struct filedesc *fdesc;
131 uri = xmlGetProp(ref, "URI");
133 syslog(LOG_ERR, "attribute URI of element <Reference> not found");
138 u = xmlParseURI(uri);
140 syslog(LOG_ERR, "error while parsing URI %s", uri);
144 /* check that unexpected parts are not there */
145 if (u->scheme || u->opaque || u->authority || u->server || u->user || u->query) {
146 syslog(LOG_ERR, "unexpected uri component in %s", uri);
150 /* check path and fragment */
151 if (!u->path && !u->fragment) {
152 syslog(LOG_ERR, "invalid uri %s", uri);
155 if (u->path && u->fragment) {
156 syslog(LOG_ERR, "not allowed to sign foreign fragment in %s", uri);
161 /* check that the path is valid */
162 fdesc = file_of_name(u->path);
164 syslog(LOG_ERR, "reference to unknown file %s", u->path);
167 if (fdesc->type != type_file) {
168 syslog(LOG_ERR, "reference to directory %s", u->path);
171 if ((fdesc->flags & flag_distributor_signature) != 0) {
172 syslog(LOG_ERR, "reference to signature %s", u->path);
175 fdesc->flags |= flag_referenced;
189 static int check_references(xmlNodePtr sinfo)
191 unsigned int i, n, flags;
197 elem = sinfo->children;
198 while (elem != NULL) {
199 if (is_element(elem, "Reference"))
200 if (check_one_reference(elem))
208 f = file_of_index(i++);
209 if (f->type == type_file) {
211 if (!(flags & (flag_signature | flag_referenced))) {
212 syslog(LOG_ERR, "file not referenced in signature", f->name);
222 static int get_certificates(xmlNodePtr kinfo)
228 n1 = kinfo->children;
230 if (is_element(n1, "X509Data")) {
233 if (is_element(n2, "X509Certificate")) {
234 b = xmlNodeGetContent(n2);
236 syslog(LOG_ERR, "xmlNodeGetContent of X509Certificate failed");
239 rc = add_certificate_b64(b);
252 /* checks the current document */
253 static int checkdocument()
256 xmlNodePtr sinfo, svalue, kinfo, objs, rootsig;
260 rootsig = xmlDocGetRootElement(document);
261 if (!is_node(rootsig, "Signature")) {
262 syslog(LOG_ERR, "root element <Signature> not found");
266 sinfo = next_element(rootsig->children);
267 if (!is_node(sinfo, "SignedInfo")) {
268 syslog(LOG_ERR, "element <SignedInfo> not found");
272 svalue = next_element(sinfo->next);
273 if (!is_node(svalue, "SignatureValue")) {
274 syslog(LOG_ERR, "element <SignatureValue> not found");
278 kinfo = next_element(svalue->next);
279 if (is_node(kinfo, "KeyInfo")) {
286 rc = check_references(sinfo);
290 rc = xmlsec_verify(rootsig);
294 rc = get_certificates(kinfo);
300 /* verify the digital signature of the file described by 'fdesc' */
301 int verify_digsig(struct filedesc *fdesc)
305 assert ((fdesc->flags & flag_signature) != 0);
306 debug("-- checking file %s",fdesc->name);
308 /* reset the flags */
310 clear_certificates();
312 /* reads and xml parses the signature file */
313 fd = openat(workdirfd, fdesc->name, O_RDONLY);
315 syslog(LOG_ERR, "cant't open file %s", fdesc->name);
318 document = xmlReadFd(fd, fdesc->name, NULL, 0);
320 if (document == NULL) {
321 syslog(LOG_ERR, "xml parse of file %s failed", fdesc->name);
325 res = checkdocument();
327 syslog(LOG_ERR, "previous error was during check of file %s", fdesc->name);
329 xmlFreeDoc(document);
333 /* check all the signature files */
334 int check_all_signatures()
338 struct filedesc *fdesc;
340 n = signature_count();
342 for (i = n ; i-- > 0 ; ) {
343 fdesc = signature_of_index(i);
344 irc = verify_digsig(fdesc);
352 /* create a signature of 'index' (0 for author, other values for distributors)
353 using the private 'key' (filename) and the certificates 'certs' (filenames)
355 int create_digsig(int index, const char *key, const char **certs)
357 struct filedesc *fdesc;
365 doc = xmlsec_create(index, key, certs);
369 /* instanciate the filename */
370 fdesc = create_signature(index);
374 /* save the doc as file */
375 fd = openat(workdirfd, fdesc->name, O_WRONLY|O_CREAT|O_TRUNC, 0644);
377 syslog(LOG_ERR, "cant open %s for write", fdesc->name);
380 ctx = xmlSaveToFd(fd, NULL, XML_SAVE_FORMAT);
382 syslog(LOG_ERR, "xmlSaveToFd failed for %s", fdesc->name);
385 len = xmlSaveDoc(ctx, doc);
387 syslog(LOG_ERR, "xmlSaveDoc to %s failed", fdesc->name);