X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fwgtpkg-digsig.c;fp=src%2Fwgtpkg-digsig.c;h=284acd13f8704f8525d0aad4d41ad8f931afb29f;hb=bf7b5918fcc07713a29b9ca32f766b65b15a4ec2;hp=0000000000000000000000000000000000000000;hpb=0270b7281b783cbea5c1f0ebb4440d2be1bd79fa;p=src%2Fapp-framework-main.git diff --git a/src/wgtpkg-digsig.c b/src/wgtpkg-digsig.c new file mode 100644 index 0000000..284acd1 --- /dev/null +++ b/src/wgtpkg-digsig.c @@ -0,0 +1,358 @@ +/* + Copyright 2015 IoT.bzh + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + + +#include +#include +#include + +#include +#include +#include + + +#include "wgtpkg.h" + + + +static const char uri_role_author[] = "http://www.w3.org/ns/widgets-digsig#role-author"; +static const char uri_role_distributor[] = "http://www.w3.org/ns/widgets-digsig#role-distributor"; +static const char uri_profile[] = "http://www.w3.org/ns/widgets-digsig#profile"; + + +/* global data */ +static xmlDocPtr document; /* the document */ + +/* facility to get the first element node (skip text nodes) starting with 'node' */ +static xmlNodePtr next_element(xmlNodePtr node) +{ + while (node && node->type != XML_ELEMENT_NODE) + node = node->next; + return node; +} + +/* is the 'node' an element node of 'name'? */ +static int is_element(xmlNodePtr node, const char *name) +{ + return node->type == XML_ELEMENT_NODE + && !strcmp(name, node->name); +} + +/* is the 'node' an element node of 'name'? */ +static int is_node(xmlNodePtr node, const char *name) +{ + return node != NULL && is_element(node, name); +} + +#if 0 +/* facility to get the first element node (skip text nodes) starting with 'node' */ +static xmlNodePtr next_element_type(xmlNodePtr node, const char *name) +{ + while (node && node->type != XML_ELEMENT_NODE && strcmp(name, node->name)) + node = node->next; + return node; +} + +/* search the element node of id. NOTE : not optimized at all */ +static xmlNodePtr search_for(const char *attrname, const char *value) +{ + char *val; + xmlNodePtr iter, next; + xmlNodePtr result; + + result = NULL; + iter = xmlDocGetRootElement(document); + while (iter != NULL) { + val = xmlGetProp(iter, attrname); + if (val != NULL && !strcmp(val, value)) { + if (result != NULL) { + syslog(LOG_ERR, "duplicated %s %s", attrname, value); + free(val); + return NULL; + } + result = iter; + } + free(val); + next = next_element(iter->children); + if (next == NULL) { + /* no child, try sibling */ + next = next_element(iter->next); + if (next == NULL) { + iter = iter->parent; + while (iter != NULL && next == NULL) { + next = next_element(iter->next); + iter = iter->parent; + } + } + } + iter = next; + } + if (result == NULL) + syslog(LOG_ERR, "node of %s '%s' not found", attrname, value); + return result; +} + +/* search the element node of id. NOTE : not optimized at all */ +static xmlNodePtr search_id(const char *id) +{ + return search_for("Id", id); +} +#endif + +/* check the digest of one element */ +static int check_one_reference(xmlNodePtr ref) +{ + int rc; + char *uri; + xmlURIPtr u; + struct filedesc *fdesc; + + /* start */ + rc = -1; + + /* get the uri */ + uri = xmlGetProp(ref, "URI"); + if (uri == NULL) { + syslog(LOG_ERR, "attribute URI of element not found"); + goto error; + } + + /* parse the uri */ + u = xmlParseURI(uri); + if (!u) { + syslog(LOG_ERR, "error while parsing URI %s", uri); + goto error2; + } + + /* check that unexpected parts are not there */ + if (u->scheme || u->opaque || u->authority || u->server || u->user || u->query) { + syslog(LOG_ERR, "unexpected uri component in %s", uri); + goto error3; + } + + /* check path and fragment */ + if (!u->path && !u->fragment) { + syslog(LOG_ERR, "invalid uri %s", uri); + goto error3; + } + if (u->path && u->fragment) { + syslog(LOG_ERR, "not allowed to sign foreign fragment in %s", uri); + goto error3; + } + + if (u->path) { + /* check that the path is valid */ + fdesc = file_of_name(u->path); + if (fdesc == NULL) { + syslog(LOG_ERR, "reference to unknown file %s", u->path); + goto error3; + } + if (fdesc->type != type_file) { + syslog(LOG_ERR, "reference to directory %s", u->path); + goto error3; + } + if ((fdesc->flags & flag_distributor_signature) != 0) { + syslog(LOG_ERR, "reference to signature %s", u->path); + goto error3; + } + fdesc->flags |= flag_referenced; + rc = 0; + } else { + rc = 0; + } + +error3: + xmlFreeURI(u); +error2: + xmlFree(uri); +error: + return rc; +} + +static int check_references(xmlNodePtr sinfo) +{ + xmlNodePtr elem; + + elem = sinfo->children; + while (elem != NULL) { + if (is_element(elem, "Reference")) + if (check_one_reference(elem)) + return -1; + elem = elem->next; + } + return 0; +} + +static int get_certificates(xmlNodePtr kinfo) +{ + xmlNodePtr n1, n2; + char *b; + int rc; + + n1 = kinfo->children; + while (n1) { + if (is_element(n1, "X509Data")) { + n2 = n1->children; + while (n2) { + if (is_element(n2, "X509Certificate")) { + b = xmlNodeGetContent(n2); + if (b == NULL) { + syslog(LOG_ERR, "xmlNodeGetContent of X509Certificate failed"); + return -1; + } + rc = add_certificate_b64(b); + xmlFree(b); + if (rc) + return rc; + } + n2 = n2->next; + } + } + n1 = n1->next; + } + return 0; +} + +/* checks the current document */ +static int checkdocument() +{ + int rc; + xmlNodePtr sinfo, svalue, kinfo, objs, rootsig; + + rc = -1; + + rootsig = xmlDocGetRootElement(document); + if (!is_node(rootsig, "Signature")) { + syslog(LOG_ERR, "root element not found"); + goto error; + } + + sinfo = next_element(rootsig->children); + if (!is_node(sinfo, "SignedInfo")) { + syslog(LOG_ERR, "element not found"); + goto error; + } + + svalue = next_element(sinfo->next); + if (!is_node(svalue, "SignatureValue")) { + syslog(LOG_ERR, "element not found"); + goto error; + } + + kinfo = next_element(svalue->next); + if (is_node(kinfo, "KeyInfo")) { + objs = kinfo->next; + } else { + objs = kinfo; + kinfo = NULL; + } + + rc = check_references(sinfo); + if (rc) + goto error; + + rc = xmlsec_verify(rootsig); + if (rc) + goto error; + + rc = get_certificates(kinfo); + +error: + return rc; +} + +/* verify the digital signature of the file described by 'fdesc' */ +int verify_digsig(struct filedesc *fdesc) +{ + int res; + + assert ((fdesc->flags & flag_signature) != 0); + debug("-- checking file %s",fdesc->name); + + /* reset the flags */ + file_clear_flags(); + clear_certificates(); + + /* reads and xml parses the signature file */ + document = xmlReadFile(fdesc->name, NULL, 0); + if (document == NULL) { + syslog(LOG_ERR, "xml parse of file %s failed", fdesc->name); + return -1; + } + + res = checkdocument(); + if (res) + syslog(LOG_ERR, "previous error was during check of file %s", fdesc->name); + + xmlFreeDoc(document); + return res; +} + +/* check all the signature files */ +int check_all_signatures() +{ + int rc, irc; + unsigned int i, n; + struct filedesc *fdesc; + + n = signature_count(); + rc = 0; + for (i = n ; i-- > 0 ; ) { + fdesc = signature_of_index(i); + irc = verify_digsig(fdesc); + if (!irc) + rc = irc; + } + + return rc; +} + +/* create a signature of 'index' (0 for author, other values for distributors) +using the private 'key' (filename) and the certificates 'certs' (filenames) +as trusted chain */ +int create_digsig(int index, const char *key, const char **certs) +{ + struct filedesc *fdesc; + xmlDocPtr doc; + int rc, len; + + rc = -1; + + /* create the doc */ + doc = xmlsec_create(index, key, certs); + if (doc == NULL) + goto error; + + /* instanciate the filename */ + fdesc = create_signature(index); + if (fdesc == NULL) + goto error2; + + /* save the doc as file */ + len = xmlSaveFormatFileEnc(fdesc->name, doc, NULL, 0); + if (len < 0) { + syslog(LOG_ERR, "xmlSaveFormatFileEnc to %s failed", fdesc->name); + goto error2; + } + + rc = 0; +error2: + xmlFreeDoc(doc); +error: + return rc; +} + +