spliting search id
[src/app-framework-main.git] / wgtpkg-digsig.c
1 /*
2  Copyright 2015 IoT.bzh
3
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
7
8      http://www.apache.org/licenses/LICENSE-2.0
9
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.
15 */
16
17
18 #include <string.h>
19 #include <syslog.h>
20 #include <assert.h>
21
22 #include <libxml/parser.h>
23 #include <libxml/tree.h>
24 #include <libxml/uri.h>
25
26
27 #include "wgtpkg.h"
28
29
30
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";
34
35
36 /* global data */
37 static xmlDocPtr document;  /* the document */
38
39 /* facility to get the first element node (skip text nodes) starting with 'node' */
40 static xmlNodePtr next_element(xmlNodePtr node)
41 {
42         while (node && node->type != XML_ELEMENT_NODE)
43                 node = node->next;
44         return node;
45 }
46
47 /* is the 'node' an element node of 'name'? */
48 static int is_element(xmlNodePtr node, const char *name)
49 {
50         return node->type == XML_ELEMENT_NODE
51                 && !strcmp(name, node->name);
52 }
53
54 /* is the 'node' an element node of 'name'? */
55 static int is_node(xmlNodePtr node, const char *name)
56 {
57         return node != NULL && is_element(node, name);
58 }
59
60 #if 0
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)
63 {
64         while (node && node->type != XML_ELEMENT_NODE && strcmp(name, node->name))
65                 node = node->next;
66         return node;
67 }
68
69 /* search the element node of id. NOTE : not optimized at all */
70 static xmlNodePtr search_for(const char *attrname, const char *value)
71 {
72         char *val;
73         xmlNodePtr iter, next;
74         xmlNodePtr result;
75
76         result = NULL;
77         iter = xmlDocGetRootElement(document);
78         while (iter != NULL) {
79                 val = xmlGetProp(iter, attrname);
80                 if (val != NULL && !strcmp(val, value)) {
81                         if (result != NULL) {
82                                 syslog(LOG_ERR, "duplicated %s %s", attrname, value);
83                                 free(val);
84                                 return NULL;
85                         }
86                         result = iter;
87                 }
88                 free(val);
89                 next = next_element(iter->children);
90                 if (next == NULL) {
91                         /* no child, try sibling */
92                         next = next_element(iter->next);
93                         if (next == NULL) {
94                                 iter = iter->parent;
95                                 while (iter != NULL && next == NULL) {
96                                         next = next_element(iter->next);
97                                         iter = iter->parent;
98                                 }
99                         }
100                 }
101                 iter = next;
102         }
103         if (result == NULL)
104                 syslog(LOG_ERR, "node of %s '%s' not found", attrname, value);
105         return result;
106 }
107
108 /* search the element node of id. NOTE : not optimized at all */
109 static xmlNodePtr search_id(const char *id)
110 {
111         return search_for("Id", id);
112 }
113 #endif
114
115 /* check the digest of one element */
116 static int check_one_reference(xmlNodePtr ref)
117 {
118         int rc;
119         char *uri;
120         xmlURIPtr u;
121         struct filedesc *fdesc;
122
123         /* start */
124         rc = -1;
125
126         /* get the uri */
127         uri = xmlGetProp(ref, "URI");
128         if (uri == NULL) {
129                 syslog(LOG_ERR, "attribute URI of element <Reference> not found");
130                 goto error;
131         }
132
133         /* parse the uri */
134         u = xmlParseURI(uri);
135         if (u == NULL) {
136                 syslog(LOG_ERR, "error while parsing URI %s", uri);
137                 goto error2;
138         }
139
140         if (u->scheme || u->opaque || u->authority || u->server || u->user || u->query) {
141                 syslog(LOG_ERR, "unexpected uri component in %s", uri);
142                 goto error3;
143         }
144
145         if (u->path && u->fragment) {
146                 syslog(LOG_ERR, "not allowed to sign foreign fragment in %s", uri);
147                 goto error3;
148         }
149
150         if (u->path) {
151                 fdesc = file_of_name(u->path);
152                 if (fdesc == NULL) {
153                         syslog(LOG_ERR, "reference to unknown file %s", u->path);
154                         goto error3;
155                 }
156                 if (fdesc->type != type_file) {
157                         syslog(LOG_ERR, "reference to directory %s", u->path);
158                         goto error3;
159                 }
160                 if ((fdesc->flags & flag_distributor_signature) != 0) {
161                         syslog(LOG_ERR, "reference to signature %s", u->path);
162                         goto error3;
163                 }
164                 fdesc->flags |= flag_referenced;
165                 rc = 0;
166         } else {
167                 rc = 0;
168         }
169
170 error3:
171         xmlFreeURI(u);
172 error2:
173         xmlFree(uri);
174 error:
175         return rc;
176 }
177
178 static int check_references(xmlNodePtr sinfo)
179 {
180         xmlNodePtr elem;
181
182         elem = sinfo->children;
183         while (elem != NULL) {
184                 if (is_element(elem, "Reference"))
185                         if (check_one_reference(elem))
186                                 return -1;
187                 elem = elem->next;
188         }
189         return 0;
190 }
191
192 static int get_certificates(xmlNodePtr kinfo)
193 {
194         xmlNodePtr n1, n2;
195         char *b;
196         int rc;
197
198         n1 = kinfo->children;
199         while (n1) {
200                 if (is_element(n1, "X509Data")) {
201                         n2 = n1->children;
202                         while (n2) {
203                                 if (is_element(n2, "X509Certificate")) {
204                                         b = xmlNodeGetContent(n2);
205                                         if (b == NULL) {
206                                                 syslog(LOG_ERR, "xmlNodeGetContent of X509Certificate failed");
207                                                 return -1;
208                                         }
209                                         rc = add_certificate_b64(b);
210                                         xmlFree(b);
211                                         if (rc)
212                                                 return rc;
213                                 }
214                                 n2 = n2->next;
215                         }
216                 }
217                 n1 = n1->next;
218         }
219         return 0;
220 }
221
222 static int checkdocument()
223 {
224         int rc;
225         xmlNodePtr sinfo, svalue, kinfo, objs, rootsig;
226
227         rc = -1;
228
229         rootsig = xmlDocGetRootElement(document);
230         if (!is_node(rootsig, "Signature")) {
231                 syslog(LOG_ERR, "root element <Signature> not found");
232                 goto error;
233         }
234
235         sinfo = next_element(rootsig->children);
236         if (!is_node(sinfo, "SignedInfo")) {
237                 syslog(LOG_ERR, "element <SignedInfo> not found");
238                 goto error;
239         }
240
241         svalue = next_element(sinfo->next);
242         if (!is_node(svalue, "SignatureValue")) {
243                 syslog(LOG_ERR, "element <SignatureValue> not found");
244                 goto error;
245         }
246
247         kinfo = next_element(svalue->next);
248         if (is_node(kinfo, "KeyInfo")) {
249                 objs = kinfo->next;
250         } else {
251                 objs = kinfo;
252                 kinfo = NULL;
253         }
254
255         rc = check_references(sinfo);
256         if (rc)
257                 goto error;
258
259         rc = xmlsec_verify(rootsig);
260         if (rc)
261                 goto error;
262
263         rc = get_certificates(kinfo);
264
265 error:
266         return rc;
267 }
268
269 int verify_digsig(struct filedesc *fdesc)
270 {
271         int res;
272
273         assert ((fdesc->flags & flag_signature) != 0);
274 printf("\n\nchecking file %s\n\n",fdesc->name);
275
276         /* reset the flags */
277         file_clear_flags();
278         clear_certificates();
279
280         /* reads and xml parses the signature file */
281         document = xmlReadFile(fdesc->name, NULL, 0);
282         if (document == NULL) {
283                 syslog(LOG_ERR, "xml parse of file %s failed", fdesc->name);
284                 return -1;
285         }
286
287         res = checkdocument();
288         if (res)
289                 syslog(LOG_ERR, "previous error was during check of file %s", fdesc->name);
290
291         xmlFreeDoc(document);
292         return res;
293 }
294
295 int check_all_signatures()
296 {
297         int rc, irc;
298         unsigned int i, n;
299         struct filedesc *fdesc;
300
301         n = signature_count();
302         rc = 0;
303         for (i = n ; i-- > 0 ; ) {
304                 fdesc = signature_of_index(i);
305                 assert ((fdesc->flags & flag_signature) != 0);
306                 irc = verify_digsig(fdesc);
307                 if (!irc)
308                         rc = irc;
309         }
310
311         return rc;
312 }
313
314 int create_digsig(int index, const char *key, const char **certs)
315 {
316         struct filedesc *fdesc;
317         xmlDocPtr doc;
318         int rc, len;
319
320         rc = -1;
321         doc = xmlsec_create(index, key, certs);
322         if (doc == NULL)
323                 goto error;
324
325         fdesc = create_signature(index);
326         if (fdesc == NULL)
327                 goto error2;
328
329         len = xmlSaveFormatFileEnc(fdesc->name, doc, NULL, 0);
330         if (len < 0) {
331                 syslog(LOG_ERR, "xmlSaveFormatFileEnc to %s failed", fdesc->name);
332                 goto error2;
333         }
334
335         rc = 0;
336 error2:
337         xmlFreeDoc(doc);
338 error:
339         return rc;
340 }
341
342