tCrawl $KEYRING if no key is provided - sick - sign and check files using ed25519
 (HTM) git clone git://z3bra.org/sick
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit a213aaa860eb78fb708172bbe802cd4a8fff5d07
 (DIR) parent ba646b3bb0828dce3e6ae91020556a740489cfcd
 (HTM) Author: z3bra <willyatmailoodotorg>
       Date:   Mon, 16 May 2016 13:32:05 +0200
       
       Crawl $KEYRING if no key is provided
       
       When checking a stream, if the -f flag is not passed, sick(1) will crawl
       tthe directory pointed to by the $KEYRING environment variable and check
       all files within this directory against the signature, until all files
       have been tested, or one of these public keys match the signature.
       
       Diffstat:
         M README                              |      12 ++++++++++++
         M sick.1                              |      10 +++++++---
         M sick.c                              |      93 ++++++++++++++++++++++++++-----
       
       3 files changed, 97 insertions(+), 18 deletions(-)
       ---
 (DIR) diff --git a/README b/README
       t@@ -29,6 +29,8 @@ The whole stream will be dumped to stdout, and the signature will be appended.
        Checking streams
        ----------------
        
       +### Using a file
       +
        A signed stream can be verified against a public key with the following
        command:
        
       t@@ -36,3 +38,13 @@ command:
        
        If the signature can be verified against the public key provided, the content
        of the message will be dumped to stdout.
       +
       +### Using a keyring
       +
       +In case the `-f` flag is omited, sick(1) will check the signature against all
       +the files located in the $KEYRING directory.
       +
       +        $ export KEYRING="$HOME/.keyring"
       +        $ mkdir $KEYRING
       +        $ mv alice.pub $KEYRING/
       +        $ sick < SIGNED
 (DIR) diff --git a/sick.1 b/sick.1
       t@@ -15,9 +15,8 @@ generates key pairs, signs, checks and remove signatures for a file or stream.
        .Sh OPTIONS
        .Bl -tag -width "-g ALIAS"
        The default action is to check the signature appended to the message given on
       -stdin. A public key must be provided with the
       -.Fl f
       -flag. If the signature can be verified with the public key, the message will be written to stdout without the signature.
       +stdin. If the signature can be verified, the message will be written to stdout
       +without the signature.
        .It Fl g Ar ALIAS
        Generates an ed25519 key pairs: `ALIAS.key` and `ALIAS.pub`
        .It Fl f Ar KEY
       t@@ -42,6 +41,11 @@ two lines, as follows:
                -----END ED25519 SIGNATURE-----
        .Ed
        .El
       +.Sh ENVIRONMENT
       +.Bl -tag -width "KEYRING"
       +.It Ev KEYRING
       +Location of the keyring directory
       +.El
        .Sh EXAMPLES
        .Bd -literal
        Generating a key pair:
 (DIR) diff --git a/sick.c b/sick.c
       t@@ -1,8 +1,10 @@
        /* See LICENSE file for copyright and license details. */
       +#include <dirent.h>
        #include <limits.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
       +#include <sys/types.h>
        
        #include "arg.h"
        #include "base64.h"
       t@@ -18,9 +20,10 @@ enum {
        };
        
        enum {
       -        ERR_NOKEY = 1,
       -        ERR_NOSIG = 2,
       -        ERR_NOMSG = 3
       +        ERR_NOKEY  = 1,
       +        ERR_NOSIG  = 2,
       +        ERR_NOMSG  = 3,
       +        ERR_NORING = 4
        };
        
        static void usage();
       t@@ -28,6 +31,7 @@ static size_t bufferize(char **buf, FILE *fp);
        static size_t extractmsg(unsigned char *msg[], char *buf);
        static size_t extractsig(unsigned char *sig[], char *buf);
        static int createkeypair(const char *);
       +static int check_keyring(unsigned char *sig, unsigned char *msg, size_t len);
        static int sign(FILE *fp, FILE *key);
        static int check(FILE *fp, FILE *key);
        
       t@@ -184,6 +188,9 @@ sign(FILE *fp, FILE *key)
                char *base64, *buf = NULL;
                unsigned char sig[64], priv[64], *msg = NULL;
        
       +        if (key == NULL)
       +                return ERR_NOKEY;
       +
                if (!fread(priv, 1, 64, key))
                        return ERR_NOKEY;
        
       t@@ -219,6 +226,60 @@ sign(FILE *fp, FILE *key)
        }
        
        static int
       +check_keyring(unsigned char *sig, unsigned char *msg, size_t len)
       +{
       +        int ret = 0;
       +        size_t n = 0;
       +        DIR *dirp = NULL;
       +        FILE *key = NULL;
       +        struct dirent *dt = NULL;
       +        char *keyring = NULL, path[PATH_MAX];
       +        unsigned char pub[32];
       +
       +        keyring = getenv("KEYRING");
       +        if (keyring == NULL) {
       +                if (verbose)
       +                        fprintf(stderr, "KEYRING not set\n");
       +                return ERR_NORING;
       +        }
       +
       +        dirp = opendir(keyring);
       +        if (dirp == NULL) {
       +                perror(keyring);
       +                return ERR_NORING;
       +        }
       +
       +        while ((dt = readdir(dirp)) != NULL) {
       +                if (dt->d_type != DT_REG)
       +                        continue;
       +
       +                n = strnlen(keyring, PATH_MAX);
       +                memset(path, 0, PATH_MAX);
       +                memcpy(path, keyring, n);
       +                path[n] = '/';
       +                memcpy(path+n+1, dt->d_name, dt->d_reclen);
       +                if ((key = fopen(path, "r")) == NULL) {
       +                        perror(path);
       +                        continue;
       +                }
       +                if (fread(pub, 1, 32, key) < 32) {
       +                        perror(path);
       +                        fclose(key);
       +                        continue;
       +                }
       +                ret += ed25519_verify(sig, msg, len, pub);
       +                if (ret) {
       +                        if (verbose)
       +                                fprintf(stderr, "Key match: %s\n", path);
       +                        break;
       +                }
       +        }
       +
       +        closedir(dirp);
       +        return !ret;
       +}
       +
       +static int
        check(FILE *fp, FILE *key)
        {
                int ret = 0;
       t@@ -226,10 +287,6 @@ check(FILE *fp, FILE *key)
                char *buf = NULL;
                unsigned char *sig, *msg, pub[32];
        
       -        if (fread(pub, 1, 32, key) < 32) {
       -                return ERR_NOKEY;
       -        }
       -
                if ((len = bufferize(&buf, fp)) == 0)
                        return ERR_NOMSG;
        
       t@@ -252,19 +309,27 @@ check(FILE *fp, FILE *key)
                if (verbose)
                        fprintf(stderr, "Verifying stream (%lu bytes)\n", len);
        
       -        ret = ed25519_verify(sig, msg, len, pub);
        
       -        if (ret)
       +        if (key) {
       +                if (fread(pub, 1, 32, key) < 32)
       +                        return ERR_NOKEY;
       +
       +                ret = !ed25519_verify(sig, msg, len, pub);
       +        } else {
       +                ret = check_keyring(sig, msg, len);
       +        }
       +
       +        if (ret == 0)
                        fwrite(msg, 1, len, stdout);
        
                if (verbose)
       -                fprintf(stderr, "Stream check %s\n", ret ? "OK" : "FAILED");
       +                fprintf(stderr, "Stream check %s\n", ret ? "FAILED" : "OK");
        
                free(msg);
                free(buf);
                free(sig);
        
       -        return !ret;
       +        return ret;
        }
        
        int
       t@@ -290,9 +355,6 @@ main(int argc, char *argv[])
                        usage();
                }ARGEND;
        
       -        if (key == NULL)
       -                return ERR_NOKEY;
       -
                fp = argc ? fopen(*argv, "r") : stdin;
        
                switch (action) {
       t@@ -305,7 +367,8 @@ main(int argc, char *argv[])
                }
        
                fclose(fp);
       -        fclose(key);
       +        if (key)
       +                fclose(key);
        
                return ret;
        }