sick

sign and check files using ed25519
git clone git://z3bra.org/sick
Log | Files | Refs | Submodules | README | LICENSE

commit a213aaa860eb78fb708172bbe802cd4a8fff5d07
parent ba646b3bb0828dce3e6ae91020556a740489cfcd
Author: z3bra <willyatmailoodotorg>
Date:   Mon May 16 13:32:05 2016

Crawl $KEYRING if no key is provided

When checking a stream, if the -f flag is not passed, sick(1) will crawl
the 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:
 README | 12 +++++++++-
 sick.1 | 10 ++++---
 sick.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
 3 files changed, 97 insertions(+), 18 deletions(-)

diff --git a/README b/README @@ -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: @@ -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 diff --git a/sick.1 b/sick.1 @@ -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 @@ -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: diff --git a/sick.c b/sick.c @@ -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" @@ -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(); @@ -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); @@ -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; @@ -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; @@ -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; @@ -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 @@ -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) { @@ -305,7 +367,8 @@ main(int argc, char *argv[]) } fclose(fp); - fclose(key); + if (key) + fclose(key); return ret; }