/*
- 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 "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"
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;
}
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;
}
/* 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;
}
/* 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;
if (f->type == type_file) {
flags = f->flags;
if (!(flags & (flag_signature | flag_referenced))) {
- syslog(LOG_ERR, "file not referenced in signature", f->name);
+ ERROR("file not referenced in signature: %s", f->name);
result = -1;
}
}
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);
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;
}
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();
/* reads and xml parses the signature file */
fd = openat(workdirfd, fdesc->name, O_RDONLY);
if (fd < 0) {
- syslog(LOG_ERR, "cant't open file %s", fdesc->name);
+ 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;
}
/* 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, fd;
+ int rc, fd;
+ long len;
xmlSaveCtxtPtr ctx;
rc = -1;
/* save the doc as file */
fd = openat(workdirfd, fdesc->name, O_WRONLY|O_CREAT|O_TRUNC, 0644);
if (fd < 0) {
- syslog(LOG_ERR, "cant open %s for write", fdesc->name);
+ ERROR("cant open %s for write", fdesc->name);
goto error2;
}
ctx = xmlSaveToFd(fd, NULL, XML_SAVE_FORMAT);
if (!ctx) {
- syslog(LOG_ERR, "xmlSaveToFd failed for %s", fdesc->name);
+ ERROR("xmlSaveToFd failed for %s", fdesc->name);
goto error3;
}
len = xmlSaveDoc(ctx, doc);
if (len < 0) {
- syslog(LOG_ERR, "xmlSaveDoc to %s failed", fdesc->name);
- goto error2;
+ ERROR("xmlSaveDoc to %s failed", fdesc->name);
+ goto error4;
}
rc = 0;
return rc;
}
+/* create a digital signature(s) from environment data */
+int create_auto_digsig()
+{
+ static const char envvar_prefix[] = "WGTPKG_AUTOSIGN_";
+ extern char **environ;
+
+ char **enviter;
+ char *var;
+ char *iter;
+ char *equal;
+ unsigned int num;
+ char *keyfile;
+ const char *certfiles[10];
+ int ncert;
+ int rc;
+ int i;
+
+ rc = 0;
+ /* enumerate environment variables */
+ enviter = environ;
+ while (rc == 0 && (var = *enviter++) != NULL) {
+ /* check the prefix */
+ if (0 != strncmp(var, envvar_prefix, sizeof(envvar_prefix) - 1))
+ continue; /* not an auto sign variable */
+ DEBUG("autosign found %s", var);
+
+ /* check the num */
+ iter = &var[sizeof(envvar_prefix) - 1];
+ if (*iter < '0' || *iter > '9') {
+ ERROR("bad autosign key found: %s", var);
+ rc = -1;
+ continue;
+ }
+
+ /* compute the number */
+ num = (unsigned int)(*iter++ - '0');
+ while (*iter >= '0' && *iter <= '9')
+ num = 10 * num + (unsigned int)(*iter++ - '0');
+
+ /* next char must be = */
+ if (*iter != '=' || !iter[1]) {
+ /* it is not an error to have an empty autosign */
+ WARNING("ignoring autosign key %.*s", (int)(iter - var), var);
+ continue;
+ }
+
+ /* auto signing with num */
+ INFO("autosign key %u found", num);
+
+ /* compute key and certificates */
+ equal = iter++;
+ keyfile = iter;
+ *equal = 0;
+ ncert = 0;
+ while (ncert < (int)((sizeof certfiles / sizeof *certfiles) - 1)
+ && (iter = strchr(iter, ':')) != NULL) {
+ *iter++ = 0;
+ certfiles[ncert++] = iter;
+ }
+ certfiles[ncert] = NULL;
+
+ /* check the parameters */
+ if (access(keyfile, R_OK) != 0) {
+ ERROR("autosign %u can't access private key %s", num, keyfile);
+ rc = -1;
+ }
+ for(i = 0 ; i < ncert ; i++) {
+ if (access(certfiles[i], R_OK) != 0) {
+ ERROR("autosign %u can't access certificate %s", num, certfiles[i]);
+ rc = -1;
+ }
+ }
+
+ /* sign now */
+ if (rc == 0) {
+ rc = xmlsec_init();
+ if (rc == 0) {
+ rc = create_digsig(num, keyfile, certfiles);
+ }
+ }
+
+ /* restore stolen chars */
+ while(ncert)
+ *(char*)(certfiles[--ncert] - 1) = ':';
+ *equal = '=';
+ }
+ return rc;
+}