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)
193 elem = sinfo->children;
194 while (elem != NULL) {
195 if (is_element(elem, "Reference"))
196 if (check_one_reference(elem))
203 static int get_certificates(xmlNodePtr kinfo)
209 n1 = kinfo->children;
211 if (is_element(n1, "X509Data")) {
214 if (is_element(n2, "X509Certificate")) {
215 b = xmlNodeGetContent(n2);
217 syslog(LOG_ERR, "xmlNodeGetContent of X509Certificate failed");
220 rc = add_certificate_b64(b);
233 /* checks the current document */
234 static int checkdocument()
237 xmlNodePtr sinfo, svalue, kinfo, objs, rootsig;
241 rootsig = xmlDocGetRootElement(document);
242 if (!is_node(rootsig, "Signature")) {
243 syslog(LOG_ERR, "root element <Signature> not found");
247 sinfo = next_element(rootsig->children);
248 if (!is_node(sinfo, "SignedInfo")) {
249 syslog(LOG_ERR, "element <SignedInfo> not found");
253 svalue = next_element(sinfo->next);
254 if (!is_node(svalue, "SignatureValue")) {
255 syslog(LOG_ERR, "element <SignatureValue> not found");
259 kinfo = next_element(svalue->next);
260 if (is_node(kinfo, "KeyInfo")) {
267 rc = check_references(sinfo);
271 rc = xmlsec_verify(rootsig);
275 rc = get_certificates(kinfo);
281 /* verify the digital signature of the file described by 'fdesc' */
282 int verify_digsig(struct filedesc *fdesc)
286 assert ((fdesc->flags & flag_signature) != 0);
287 debug("-- checking file %s",fdesc->name);
289 /* reset the flags */
291 clear_certificates();
293 /* reads and xml parses the signature file */
294 fd = openat(workdirfd, fdesc->name, O_RDONLY);
296 syslog(LOG_ERR, "cant't open file %s", fdesc->name);
299 document = xmlReadFd(fd, fdesc->name, NULL, 0);
301 if (document == NULL) {
302 syslog(LOG_ERR, "xml parse of file %s failed", fdesc->name);
306 res = checkdocument();
308 syslog(LOG_ERR, "previous error was during check of file %s", fdesc->name);
310 xmlFreeDoc(document);
314 /* check all the signature files */
315 int check_all_signatures()
319 struct filedesc *fdesc;
321 n = signature_count();
323 for (i = n ; i-- > 0 ; ) {
324 fdesc = signature_of_index(i);
325 irc = verify_digsig(fdesc);
333 /* create a signature of 'index' (0 for author, other values for distributors)
334 using the private 'key' (filename) and the certificates 'certs' (filenames)
336 int create_digsig(int index, const char *key, const char **certs)
338 struct filedesc *fdesc;
346 doc = xmlsec_create(index, key, certs);
350 /* instanciate the filename */
351 fdesc = create_signature(index);
355 /* save the doc as file */
356 fd = openat(workdirfd, fdesc->name, O_WRONLY|O_CREAT|O_TRUNC, 0644);
358 syslog(LOG_ERR, "cant open %s for write", fdesc->name);
361 ctx = xmlSaveToFd(fd, NULL, XML_SAVE_FORMAT);
363 syslog(LOG_ERR, "xmlSaveToFd failed for %s", fdesc->name);
366 len = xmlSaveDoc(ctx, doc);
368 syslog(LOG_ERR, "xmlSaveDoc to %s failed", fdesc->name);