Refactor ALLOW_NO_SIGNATURE compile flag
[src/app-framework-main.git] / src / wgtpkg-digsig.c
index 6e66e38..d190d23 100644 (file)
@@ -1,5 +1,7 @@
 /*
- Copyright 2015 IoT.bzh
+ Copyright (C) 2015-2020 IoT.bzh
+
+ author: José Bollo <jose.bollo@iot.bzh>
 
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
 
 
 #include <string.h>
-#include <syslog.h>
 #include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
 
 #include <libxml/parser.h>
 #include <libxml/tree.h>
 #include <libxml/uri.h>
+#include <libxml/xmlsave.h>
 
 
 #include "verbose.h"
-#include "wgtpkg.h"
+#include "wgtpkg-files.h"
+#include "wgtpkg-workdir.h"
+#include "wgtpkg-certs.h"
+#include "wgtpkg-xmlsec.h"
+#include "wgtpkg-digsig.h"
 
 
 
@@ -80,7 +88,7 @@ static xmlNodePtr search_for(const char *attrname, const char *value)
                val = xmlGetProp(iter, attrname);
                if (val != NULL && !strcmp(val, value)) {
                        if (result != NULL) {
-                               syslog(LOG_ERR, "duplicated %s %s", attrname, value);
+                               ERROR("duplicated %s %s", attrname, value);
                                free(val);
                                return NULL;
                        }
@@ -102,7 +110,7 @@ static xmlNodePtr search_for(const char *attrname, const char *value)
                iter = next;
        }
        if (result == NULL)
-               syslog(LOG_ERR, "node of %s '%s' not found", attrname, value);
+               ERROR("node of %s '%s' not found", attrname, value);
        return result;
 }
 
@@ -127,30 +135,30 @@ static int check_one_reference(xmlNodePtr ref)
        /* get the uri */
        uri = xmlGetProp(ref, "URI");
        if (uri == NULL) {
-               syslog(LOG_ERR, "attribute URI of element <Reference> not found");
+               ERROR("attribute URI of element <Reference> not found");
                goto error;
        }
 
        /* parse the uri */
        u = xmlParseURI(uri);
        if (!u) {
-               syslog(LOG_ERR, "error while parsing URI %s", uri);
+               ERROR("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);
+               ERROR("unexpected uri component in %s", uri);
                goto error3;
        }
 
        /* check path and fragment */
        if (!u->path && !u->fragment) {
-               syslog(LOG_ERR, "invalid uri %s", uri);
+               ERROR("invalid uri %s", uri);
                goto error3;
        }
        if (u->path && u->fragment) {
-               syslog(LOG_ERR, "not allowed to sign foreign fragment in %s", uri);
+               ERROR("not allowed to sign foreign fragment in %s", uri);
                goto error3;
        }
 
@@ -158,15 +166,15 @@ static int check_one_reference(xmlNodePtr ref)
                /* 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);
+                       ERROR("reference to unknown file %s", u->path);
                        goto error3;
                }
                if (fdesc->type != type_file) {
-                       syslog(LOG_ERR, "reference to directory %s", u->path);
+                       ERROR("reference to directory %s", u->path);
                        goto error3;
                }
                if ((fdesc->flags & flag_distributor_signature) != 0) {
-                       syslog(LOG_ERR, "reference to signature %s", u->path);
+                       ERROR("reference to signature %s", u->path);
                        goto error3;
                }
                fdesc->flags |= flag_referenced;
@@ -185,18 +193,37 @@ error:
 
 static int check_references(xmlNodePtr sinfo)
 {
+       unsigned int i, n, flags;
+       struct filedesc *f;
+       int result;
        xmlNodePtr elem;
 
+       result = 0;
        elem = sinfo->children;
        while (elem != NULL) {
                if (is_element(elem, "Reference"))
                        if (check_one_reference(elem))
-                               return -1;
+                               result = -1;
                elem = elem->next;
        }
-       return 0;
+
+       n = file_count();
+       i = 0;
+       while(i < n) {
+               f = file_of_index(i++);
+               if (f->type == type_file) {
+                       flags = f->flags;
+                       if (!(flags & (flag_signature | flag_referenced))) {
+                               ERROR("file not referenced in signature: %s", f->name);
+                               result = -1;
+                       }
+               }
+       }
+
+       return result;
 }
 
+
 static int get_certificates(xmlNodePtr kinfo)
 {
        xmlNodePtr n1, n2;
@@ -211,7 +238,7 @@ static int get_certificates(xmlNodePtr kinfo)
                                if (is_element(n2, "X509Certificate")) {
                                        b = xmlNodeGetContent(n2);
                                        if (b == NULL) {
-                                               syslog(LOG_ERR, "xmlNodeGetContent of X509Certificate failed");
+                                               ERROR("xmlNodeGetContent of X509Certificate failed");
                                                return -1;
                                        }
                                        rc = add_certificate_b64(b);
@@ -237,19 +264,19 @@ static int checkdocument()
 
        rootsig = xmlDocGetRootElement(document);
        if (!is_node(rootsig, "Signature")) {
-               syslog(LOG_ERR, "root element <Signature> not found");
+               ERROR("root element <Signature> not found");
                goto error;
        }
 
        sinfo = next_element(rootsig->children);
        if (!is_node(sinfo, "SignedInfo")) {
-               syslog(LOG_ERR, "element <SignedInfo> not found");
+               ERROR("element <SignedInfo> not found");
                goto error;
        }
 
        svalue = next_element(sinfo->next);
        if (!is_node(svalue, "SignatureValue")) {
-               syslog(LOG_ERR, "element <SignatureValue> not found");
+               ERROR("element <SignatureValue> not found");
                goto error;
        }
 
@@ -278,43 +305,63 @@ error:
 /* verify the digital signature of the file described by 'fdesc' */
 int verify_digsig(struct filedesc *fdesc)
 {
-       int res;
+       int res, fd;
 
        assert ((fdesc->flags & flag_signature) != 0);
-       debug("-- checking file %s",fdesc->name);
+       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);
+       fd = openat(workdirfd, fdesc->name, O_RDONLY);
+       if (fd < 0) {
+               ERROR("cant't open file %s", fdesc->name);
+               return -1;
+       }
+       document = xmlReadFd(fd, fdesc->name, NULL, 0);
+       close(fd);
        if (document == NULL) {
-               syslog(LOG_ERR, "xml parse of file %s failed", fdesc->name);
+               ERROR("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);
+               ERROR("previous error was during check of file %s", fdesc->name);
 
        xmlFreeDoc(document);
        return res;
 }
 
 /* check all the signature files */
-int check_all_signatures()
+int check_all_signatures(int allow_none)
 {
        int rc, irc;
        unsigned int i, n;
        struct filedesc *fdesc;
 
        n = signature_count();
+       if (n == 0) {
+               if (!allow_none) {
+                       ERROR("no signature found");
+                       return -1;
+               }
+               return 0;
+       }
+
+       rc = xmlsec_init();
+       if (rc < 0) {
+               ERROR("can't check signature");
+               return rc;
+       }
+
        rc = 0;
-       for (i = n ; i-- > 0 ; ) {
-               fdesc = signature_of_index(i);
+       for (i = n ; i ; ) {
+               fdesc = signature_of_index(--i);
                irc = verify_digsig(fdesc);
-               if (!irc)
+               if (irc < 0)
                        rc = irc;
        }
 
@@ -324,11 +371,13 @@ int check_all_signatures()
 /* 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)
+int create_digsig(unsigned int index, const char *key, const char **certs)
 {
        struct filedesc *fdesc;
        xmlDocPtr doc;
-       int rc, len;
+       int rc, fd;
+       long len;
+       xmlSaveCtxtPtr ctx;
 
        rc = -1;
 
@@ -343,13 +392,27 @@ int create_digsig(int index, const char *key, const char **certs)
                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);
+       fd = openat(workdirfd, fdesc->name, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+       if (fd < 0) {
+               ERROR("cant open %s for write", fdesc->name);
                goto error2;
        }
+       ctx = xmlSaveToFd(fd, NULL, XML_SAVE_FORMAT);
+       if (!ctx) {
+               ERROR("xmlSaveToFd failed for %s", fdesc->name);
+               goto error3;
+       }
+       len = xmlSaveDoc(ctx, doc);
+       if (len < 0) {
+               ERROR("xmlSaveDoc to %s failed", fdesc->name);
+               goto error4;
+       }
 
        rc = 0;
+error4:
+       xmlSaveClose(ctx);
+error3:
+       close(fd);
 error2:
        xmlFreeDoc(doc);
 error: