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>
31 static const char uri_role_author[] = "http://www.w3.org/ns/widgets-digsig#role-author";
32 static const char uri_role_distributor[] = "http://www.w3.org/ns/widgets-digsig#role-distributor";
33 static const char uri_profile[] = "http://www.w3.org/ns/widgets-digsig#profile";
37 static xmlDocPtr document; /* the document */
39 /* facility to get the first element node (skip text nodes) starting with 'node' */
40 static xmlNodePtr next_element(xmlNodePtr node)
42 while (node && node->type != XML_ELEMENT_NODE)
47 /* is the 'node' an element node of 'name'? */
48 static int is_element(xmlNodePtr node, const char *name)
50 return node->type == XML_ELEMENT_NODE
51 && !strcmp(name, node->name);
54 /* is the 'node' an element node of 'name'? */
55 static int is_node(xmlNodePtr node, const char *name)
57 return node != NULL && is_element(node, name);
61 /* facility to get the first element node (skip text nodes) starting with 'node' */
62 static xmlNodePtr next_element_type(xmlNodePtr node, const char *name)
64 while (node && node->type != XML_ELEMENT_NODE && strcmp(name, node->name))
69 /* search the element node of id. NOTE : not optimized at all */
70 static xmlNodePtr search_for(const char *attrname, const char *value)
73 xmlNodePtr iter, next;
77 iter = xmlDocGetRootElement(document);
78 while (iter != NULL) {
79 val = xmlGetProp(iter, attrname);
80 if (val != NULL && !strcmp(val, value)) {
82 syslog(LOG_ERR, "duplicated %s %s", attrname, value);
89 next = next_element(iter->children);
91 /* no child, try sibling */
92 next = next_element(iter->next);
95 while (iter != NULL && next == NULL) {
96 next = next_element(iter->next);
104 syslog(LOG_ERR, "node of %s '%s' not found", attrname, value);
108 /* search the element node of id. NOTE : not optimized at all */
109 static xmlNodePtr search_id(const char *id)
111 return search_for("Id", id);
115 /* check the digest of one element */
116 static int check_one_reference(xmlNodePtr ref)
121 struct filedesc *fdesc;
127 uri = xmlGetProp(ref, "URI");
129 syslog(LOG_ERR, "attribute URI of element <Reference> not found");
134 u = xmlParseURI(uri);
136 syslog(LOG_ERR, "error while parsing URI %s", uri);
140 /* check that unexpected parts are not there */
141 if (u->scheme || u->opaque || u->authority || u->server || u->user || u->query) {
142 syslog(LOG_ERR, "unexpected uri component in %s", uri);
146 /* check path and fragment */
147 if (!u->path && !u->fragment) {
148 syslog(LOG_ERR, "invalid uri %s", uri);
151 if (u->path && u->fragment) {
152 syslog(LOG_ERR, "not allowed to sign foreign fragment in %s", uri);
157 /* check that the path is valid */
158 fdesc = file_of_name(u->path);
160 syslog(LOG_ERR, "reference to unknown file %s", u->path);
163 if (fdesc->type != type_file) {
164 syslog(LOG_ERR, "reference to directory %s", u->path);
167 if ((fdesc->flags & flag_distributor_signature) != 0) {
168 syslog(LOG_ERR, "reference to signature %s", u->path);
171 fdesc->flags |= flag_referenced;
185 static int check_references(xmlNodePtr sinfo)
189 elem = sinfo->children;
190 while (elem != NULL) {
191 if (is_element(elem, "Reference"))
192 if (check_one_reference(elem))
199 static int get_certificates(xmlNodePtr kinfo)
205 n1 = kinfo->children;
207 if (is_element(n1, "X509Data")) {
210 if (is_element(n2, "X509Certificate")) {
211 b = xmlNodeGetContent(n2);
213 syslog(LOG_ERR, "xmlNodeGetContent of X509Certificate failed");
216 rc = add_certificate_b64(b);
229 /* checks the current document */
230 static int checkdocument()
233 xmlNodePtr sinfo, svalue, kinfo, objs, rootsig;
237 rootsig = xmlDocGetRootElement(document);
238 if (!is_node(rootsig, "Signature")) {
239 syslog(LOG_ERR, "root element <Signature> not found");
243 sinfo = next_element(rootsig->children);
244 if (!is_node(sinfo, "SignedInfo")) {
245 syslog(LOG_ERR, "element <SignedInfo> not found");
249 svalue = next_element(sinfo->next);
250 if (!is_node(svalue, "SignatureValue")) {
251 syslog(LOG_ERR, "element <SignatureValue> not found");
255 kinfo = next_element(svalue->next);
256 if (is_node(kinfo, "KeyInfo")) {
263 rc = check_references(sinfo);
267 rc = xmlsec_verify(rootsig);
271 rc = get_certificates(kinfo);
277 /* verify the digital signature of the file described by 'fdesc' */
278 int verify_digsig(struct filedesc *fdesc)
282 assert ((fdesc->flags & flag_signature) != 0);
283 debug("-- checking file %s",fdesc->name);
285 /* reset the flags */
287 clear_certificates();
289 /* reads and xml parses the signature file */
290 document = xmlReadFile(fdesc->name, NULL, 0);
291 if (document == NULL) {
292 syslog(LOG_ERR, "xml parse of file %s failed", fdesc->name);
296 res = checkdocument();
298 syslog(LOG_ERR, "previous error was during check of file %s", fdesc->name);
300 xmlFreeDoc(document);
304 /* check all the signature files */
305 int check_all_signatures()
309 struct filedesc *fdesc;
311 n = signature_count();
313 for (i = n ; i-- > 0 ; ) {
314 fdesc = signature_of_index(i);
315 irc = verify_digsig(fdesc);
323 /* create a signature of 'index' (0 for author, other values for distributors)
324 using the private 'key' (filename) and the certificates 'certs' (filenames)
326 int create_digsig(int index, const char *key, const char **certs)
328 struct filedesc *fdesc;
335 doc = xmlsec_create(index, key, certs);
339 /* instanciate the filename */
340 fdesc = create_signature(index);
344 /* save the doc as file */
345 len = xmlSaveFormatFileEnc(fdesc->name, doc, NULL, 0);
347 syslog(LOG_ERR, "xmlSaveFormatFileEnc to %s failed", fdesc->name);