From f7f69134a9bf352d3e6cfb0fa081c08f53beebc8 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Thu, 13 Apr 2017 23:37:19 +0200 Subject: sync --- orig/signify.c | 331 ++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 223 insertions(+), 108 deletions(-) (limited to 'orig/signify.c') diff --git a/orig/signify.c b/orig/signify.c index a4cb84a..5158326 100644 --- a/orig/signify.c +++ b/orig/signify.c @@ -1,4 +1,4 @@ -/* $OpenBSD: signify.c,v 1.105 2015/12/04 11:05:22 tedu Exp $ */ +/* $OpenBSD: signify.c,v 1.126 2016/10/06 22:38:25 espie Exp $ */ /* * Copyright (c) 2013 Ted Unangst * @@ -34,6 +34,7 @@ #include #include "crypto_api.h" +#include "signify.h" #define SIGBYTES crypto_sign_ed25519_BYTES #define SECRETBYTES crypto_sign_ed25519_SECRETKEYBYTES @@ -70,8 +71,6 @@ struct sig { uint8_t sig[SIGBYTES]; }; -extern char *__progname; - static void __dead usage(const char *error) { @@ -81,14 +80,14 @@ usage(const char *error) #ifndef VERIFYONLY "\t%1$s -C [-q] -p pubkey -x sigfile [file ...]\n" "\t%1$s -G [-n] [-c comment] -p pubkey -s seckey\n" - "\t%1$s -S [-e] [-x sigfile] -s seckey -m message\n" + "\t%1$s -S [-ez] [-x sigfile] -s seckey -m message\n" #endif - "\t%1$s -V [-eq] [-x sigfile] -p pubkey -m message\n", - __progname); + "\t%1$s -V [-eqz] [-p pubkey] [-t keytype] [-x sigfile] -m message\n", + getprogname()); exit(1); } -static int +int xopen(const char *fname, int oflags, mode_t mode) { struct stat sb; @@ -112,7 +111,7 @@ xopen(const char *fname, int oflags, mode_t mode) return fd; } -static void * +void * xmalloc(size_t len) { void *p; @@ -190,7 +189,7 @@ readmsg(const char *filename, unsigned long long *msglenp) errx(1, "msg too large in %s", filename); space = msglen; if (!(msg = realloc(msg, msglen + space + 1))) - errx(1, "realloc"); + err(1, "realloc"); } if ((x = read(fd, msg + msglen, space)) == -1) err(1, "read from %s", filename); @@ -207,7 +206,7 @@ readmsg(const char *filename, unsigned long long *msglenp) return msg; } -static void +void writeall(int fd, const void *buf, size_t buflen, const char *filename) { ssize_t x; @@ -221,26 +220,32 @@ writeall(int fd, const void *buf, size_t buflen, const char *filename) } #ifndef VERIFYONLY -static void -writeb64file(const char *filename, const char *comment, const void *buf, - size_t buflen, const void *msg, size_t msglen, int oflags, mode_t mode) +static char * +createheader(const char *comment, const void *buf, size_t buflen) { - char header[1024]; + char *header; char b64[1024]; - int fd, rv, nr; - fd = xopen(filename, O_CREAT|oflags|O_NOFOLLOW|O_WRONLY, mode); - if ((nr = snprintf(header, sizeof(header), "%s%s\n", - COMMENTHDR, comment)) == -1 || nr >= sizeof(header)) - errx(1, "comment too long"); - writeall(fd, header, strlen(header), filename); - if ((rv = b64_ntop(buf, buflen, b64, sizeof(b64))) == -1) + if (b64_ntop(buf, buflen, b64, sizeof(b64)) == -1) errx(1, "base64 encode failed"); - b64[rv++] = '\n'; - writeall(fd, b64, rv, filename); + if (asprintf(&header, "%s%s\n%s\n", COMMENTHDR, comment, b64) == -1) + err(1, "asprintf failed"); explicit_bzero(b64, sizeof(b64)); - if (msg) - writeall(fd, msg, msglen, filename); + return header; +} + +static void +writekeyfile(const char *filename, const char *comment, const void *buf, + size_t buflen, int oflags, mode_t mode) +{ + char *header; + int fd; + + fd = xopen(filename, O_CREAT|oflags|O_NOFOLLOW|O_WRONLY, mode); + header = createheader(comment, buf, buflen); + writeall(fd, header, strlen(header), filename); + explicit_bzero(header, strlen(header)); + free(header); close(fd); } @@ -322,39 +327,83 @@ generate(const char *pubkeyfile, const char *seckeyfile, int rounds, explicit_bzero(digest, sizeof(digest)); explicit_bzero(xorkey, sizeof(xorkey)); - if ((nr = snprintf(commentbuf, sizeof(commentbuf), "%s secret key", - comment)) == -1 || nr >= sizeof(commentbuf)) + nr = snprintf(commentbuf, sizeof(commentbuf), "%s secret key", comment); + if (nr == -1 || nr >= sizeof(commentbuf)) errx(1, "comment too long"); - writeb64file(seckeyfile, commentbuf, &enckey, - sizeof(enckey), NULL, 0, O_EXCL, 0600); + writekeyfile(seckeyfile, commentbuf, &enckey, + sizeof(enckey), O_EXCL, 0600); explicit_bzero(&enckey, sizeof(enckey)); memcpy(pubkey.pkalg, PKALG, 2); memcpy(pubkey.keynum, keynum, KEYNUMLEN); - if ((nr = snprintf(commentbuf, sizeof(commentbuf), "%s public key", - comment)) == -1 || nr >= sizeof(commentbuf)) + nr = snprintf(commentbuf, sizeof(commentbuf), "%s public key", comment); + if (nr == -1 || nr >= sizeof(commentbuf)) errx(1, "comment too long"); - writeb64file(pubkeyfile, commentbuf, &pubkey, - sizeof(pubkey), NULL, 0, O_EXCL, 0666); + writekeyfile(pubkeyfile, commentbuf, &pubkey, + sizeof(pubkey), O_EXCL, 0666); } -static void -sign(const char *seckeyfile, const char *msgfile, const char *sigfile, - int embedded) +static const char * +check_keyname_compliance(const char *pubkeyfile, const char *seckeyfile) +{ + const char *pos; + + /* basename may or may not modify input */ + pos = strrchr(seckeyfile, '/'); + if (pos != NULL) + seckeyfile = pos+1; + + size_t len; + len = strlen(seckeyfile); + if (len < 5) /* ?.key */ + goto bad; + if (strcmp(seckeyfile + len - 4, ".sec") != 0) + goto bad; + if (pubkeyfile != NULL) { + pos = strrchr(pubkeyfile, '/'); + if (pos != NULL) + pubkeyfile = pos+1; + + if (strlen(pubkeyfile) != len) + goto bad; + if (strcmp(pubkeyfile + len - 4, ".pub") != 0) + goto bad; + if (strncmp(pubkeyfile, seckeyfile, len - 4) != 0) + goto bad; + } + + return seckeyfile; +bad: + errx(1, "please use naming scheme of keyname.pub and keyname.sec"); +} + +uint8_t * +createsig(const char *seckeyfile, const char *msgfile, uint8_t *msg, + unsigned long long msglen) { - struct sig sig; - uint8_t digest[SHA512_DIGEST_LENGTH]; struct enckey enckey; uint8_t xorkey[sizeof(enckey.seckey)]; - uint8_t *msg; - char comment[COMMENTMAXLEN], sigcomment[COMMENTMAXLEN]; - char *secname; - unsigned long long msglen; - int i, rounds, nr; + struct sig sig; + char *sighdr; + uint8_t digest[SHA512_DIGEST_LENGTH]; + int i, nr, rounds; SHA2_CTX ctx; + char comment[COMMENTMAXLEN], sigcomment[COMMENTMAXLEN]; readb64file(seckeyfile, &enckey, sizeof(enckey), comment); + if (strcmp(seckeyfile, "-") == 0) { + nr = snprintf(sigcomment, sizeof(sigcomment), + "signature from %s", comment); + } else { + const char *keyname = check_keyname_compliance(NULL, + seckeyfile); + nr = snprintf(sigcomment, sizeof(sigcomment), + VERIFYWITH "%.*s.pub", (int)strlen(keyname) - 4, keyname); + } + if (nr == -1 || nr >= sizeof(sigcomment)) + errx(1, "comment too long"); + if (memcmp(enckey.kdfalg, KDFALG, 2) != 0) errx(1, "unsupported KDF"); rounds = ntohl(enckey.kdfrounds); @@ -370,29 +419,35 @@ sign(const char *seckeyfile, const char *msgfile, const char *sigfile, errx(1, "incorrect passphrase"); explicit_bzero(digest, sizeof(digest)); - msg = readmsg(msgfile, &msglen); - signmsg(enckey.seckey, msg, msglen, sig.sig); memcpy(sig.keynum, enckey.keynum, KEYNUMLEN); explicit_bzero(&enckey, sizeof(enckey)); memcpy(sig.pkalg, PKALG, 2); - secname = strstr(seckeyfile, ".sec"); - if (secname && strlen(secname) == 4) { - if ((nr = snprintf(sigcomment, sizeof(sigcomment), VERIFYWITH "%.*s.pub", - (int)strlen(seckeyfile) - 4, seckeyfile)) == -1 || nr >= sizeof(sigcomment)) - errx(1, "comment too long"); - } else { - if ((nr = snprintf(sigcomment, sizeof(sigcomment), "signature from %s", - comment)) == -1 || nr >= sizeof(sigcomment)) - errx(1, "comment too long"); - } + + sighdr = createheader(sigcomment, &sig, sizeof(sig)); + return sighdr; +} + +static void +sign(const char *seckeyfile, const char *msgfile, const char *sigfile, + int embedded) +{ + uint8_t *msg; + char *sighdr; + int fd; + unsigned long long msglen; + + msg = readmsg(msgfile, &msglen); + + sighdr = createsig(seckeyfile, msgfile, msg, msglen); + + fd = xopen(sigfile, O_CREAT|O_TRUNC|O_NOFOLLOW|O_WRONLY, 0666); + writeall(fd, sighdr, strlen(sighdr), sigfile); + free(sighdr); if (embedded) - writeb64file(sigfile, sigcomment, &sig, sizeof(sig), msg, - msglen, O_TRUNC, 0666); - else - writeb64file(sigfile, sigcomment, &sig, sizeof(sig), NULL, - 0, O_TRUNC, 0666); + writeall(fd, msg, msglen, sigfile); + close(fd); free(msg); } @@ -422,19 +477,43 @@ verifymsg(struct pubkey *pubkey, uint8_t *msg, unsigned long long msglen, free(dummybuf); } +static void +check_keytype(const char *pubkeyfile, const char *keytype) +{ + const char *p; + size_t typelen; + + if (!(p = strrchr(pubkeyfile, '-'))) + goto bad; + p++; + typelen = strlen(keytype); + if (strncmp(p, keytype, typelen) != 0) + goto bad; + if (strcmp(p + typelen, ".pub") != 0) + goto bad; + return; + +bad: + errx(1, "incorrect keytype: %s is not %s", pubkeyfile, keytype); +} + static void readpubkey(const char *pubkeyfile, struct pubkey *pubkey, - const char *sigcomment) + const char *sigcomment, const char *keytype) { - const char *safepath = "/etc/signify/"; + const char *safepath = "/etc/signify"; + char keypath[1024]; if (!pubkeyfile) { pubkeyfile = strstr(sigcomment, VERIFYWITH); - if (pubkeyfile) { + if (pubkeyfile && strchr(pubkeyfile, '/') == NULL) { pubkeyfile += strlen(VERIFYWITH); - if (strncmp(pubkeyfile, safepath, strlen(safepath)) != 0 || - strstr(pubkeyfile, "/../") != NULL) - errx(1, "untrusted path %s", pubkeyfile); + if (keytype) + check_keytype(pubkeyfile, keytype); + if (snprintf(keypath, sizeof(keypath), "%s/%s", + safepath, pubkeyfile) >= sizeof(keypath)) + errx(1, "name too long %s", pubkeyfile); + pubkeyfile = keypath; } else usage("must specify pubkey"); } @@ -443,7 +522,7 @@ readpubkey(const char *pubkeyfile, struct pubkey *pubkey, static void verifysimple(const char *pubkeyfile, const char *msgfile, const char *sigfile, - int quiet) + int quiet, const char *keytype) { char sigcomment[COMMENTMAXLEN]; struct sig sig; @@ -454,7 +533,7 @@ verifysimple(const char *pubkeyfile, const char *msgfile, const char *sigfile, msg = readmsg(msgfile, &msglen); readb64file(sigfile, &sig, sizeof(sig), sigcomment); - readpubkey(pubkeyfile, &pubkey, sigcomment); + readpubkey(pubkeyfile, &pubkey, sigcomment, keytype); verifymsg(&pubkey, msg, msglen, &sig, quiet); @@ -463,7 +542,7 @@ verifysimple(const char *pubkeyfile, const char *msgfile, const char *sigfile, static uint8_t * verifyembedded(const char *pubkeyfile, const char *sigfile, - int quiet, unsigned long long *msglenp) + int quiet, unsigned long long *msglenp, const char *keytype) { char sigcomment[COMMENTMAXLEN]; struct sig sig; @@ -474,7 +553,7 @@ verifyembedded(const char *pubkeyfile, const char *sigfile, msg = readmsg(sigfile, &msglen); siglen = parseb64file(sigfile, msg, &sig, sizeof(sig), sigcomment); - readpubkey(pubkeyfile, &pubkey, sigcomment); + readpubkey(pubkeyfile, &pubkey, sigcomment, keytype); msglen -= siglen; memmove(msg, msg + siglen, msglen); @@ -488,20 +567,21 @@ verifyembedded(const char *pubkeyfile, const char *sigfile, static void verify(const char *pubkeyfile, const char *msgfile, const char *sigfile, - int embedded, int quiet) + int embedded, int quiet, const char *keytype) { unsigned long long msglen; uint8_t *msg; int fd; if (embedded) { - msg = verifyembedded(pubkeyfile, sigfile, quiet, &msglen); + msg = verifyembedded(pubkeyfile, sigfile, quiet, &msglen, + keytype); fd = xopen(msgfile, O_CREAT|O_TRUNC|O_NOFOLLOW|O_WRONLY, 0666); writeall(fd, msg, msglen, msgfile); free(msg); close(fd); } else { - verifysimple(pubkeyfile, msgfile, sigfile, quiet); + verifysimple(pubkeyfile, msgfile, sigfile, quiet, keytype); } } @@ -513,7 +593,7 @@ struct checksum { char algo[32]; }; -static void * +static void * ecalloc(size_t s1, size_t s2, void *data) { void *p; @@ -637,11 +717,31 @@ check(const char *pubkeyfile, const char *sigfile, int quiet, int argc, unsigned long long msglen; uint8_t *msg; - msg = verifyembedded(pubkeyfile, sigfile, quiet, &msglen); + msg = verifyembedded(pubkeyfile, sigfile, quiet, &msglen, NULL); verifychecksums((char *)msg, argc, argv, quiet); free(msg); } + +void * +verifyzdata(uint8_t *zdata, unsigned long long zdatalen, + const char *filename, const char *pubkeyfile, const char *keytype) +{ + struct sig sig; + char sigcomment[COMMENTMAXLEN]; + unsigned long long siglen; + struct pubkey pubkey; + + if (zdatalen < sizeof(sig)) + errx(1, "signature too short in %s", filename); + siglen = parseb64file(filename, zdata, &sig, sizeof(sig), + sigcomment); + readpubkey(pubkeyfile, &pubkey, sigcomment, keytype); + zdata += siglen; + zdatalen -= siglen; + verifymsg(&pubkey, zdata, zdatalen, &sig, 1); + return zdata; +} #endif int @@ -651,9 +751,11 @@ main(int argc, char **argv) *sigfile = NULL; char sigfilebuf[PATH_MAX]; const char *comment = "signify"; + char *keytype = NULL; int ch, rounds; int embedded = 0; int quiet = 0; + int gzip = 0; enum { NONE, CHECK, @@ -667,7 +769,7 @@ main(int argc, char **argv) rounds = 42; - while ((ch = getopt(argc, argv, "CGSVc:em:np:qs:x:")) != -1) { + while ((ch = getopt(argc, argv, "CGSVzc:em:np:qs:t:x:")) != -1) { switch (ch) { #ifndef VERIFYONLY case 'C': @@ -685,6 +787,9 @@ main(int argc, char **argv) usage(NULL); verb = SIGN; break; + case 'z': + gzip = 1; + break; #endif case 'V': if (verb) @@ -712,6 +817,9 @@ main(int argc, char **argv) case 's': seckeyfile = optarg; break; + case 't': + keytype = optarg; + break; case 'x': sigfile = optarg; break; @@ -723,35 +831,16 @@ main(int argc, char **argv) argc -= optind; argv += optind; + if (embedded && gzip) + errx(1, "can't combine -e and -z options"); + if (setvbuf(stdout, NULL, _IOLBF, 0) != 0) err(1, "setvbuf"); - switch (verb) { - case GENERATE: - case SIGN: - /* keep it all */ - break; - case CHECK: - if (pledge("stdio rpath", NULL) == -1) - err(1, "pledge"); - break; - case VERIFY: - if (embedded && (!msgfile || strcmp(msgfile, "-") != 0)) { - if (pledge("stdio rpath wpath cpath", NULL) == -1) - err(1, "pledge"); - } else { - if (pledge("stdio rpath", NULL) == -1) - err(1, "pledge"); - } - break; - default: - if (pledge("stdio", NULL) == -1) - err(1, "pledge"); - break; - } - #ifndef VERIFYONLY if (verb == CHECK) { + if (pledge("stdio rpath", NULL) == -1) + err(1, "pledge"); if (!sigfile) usage("must specify sigfile"); check(pubkeyfile, sigfile, quiet, argc, argv); @@ -766,8 +855,9 @@ main(int argc, char **argv) int nr; if (strcmp(msgfile, "-") == 0) usage("must specify sigfile with - message"); - if ((nr = snprintf(sigfilebuf, sizeof(sigfilebuf), "%s.sig", - msgfile)) == -1 || nr >= sizeof(sigfilebuf)) + nr = snprintf(sigfilebuf, sizeof(sigfilebuf), + "%s.sig", msgfile); + if (nr == -1 || nr >= sizeof(sigfilebuf)) errx(1, "path too long"); sigfile = sigfilebuf; } @@ -775,22 +865,47 @@ main(int argc, char **argv) switch (verb) { #ifndef VERIFYONLY case GENERATE: + /* no pledge */ if (!pubkeyfile || !seckeyfile) usage("must specify pubkey and seckey"); + check_keyname_compliance(pubkeyfile, seckeyfile); generate(pubkeyfile, seckeyfile, rounds, comment); break; case SIGN: - if (!msgfile || !seckeyfile) - usage("must specify message and seckey"); - sign(seckeyfile, msgfile, sigfile, embedded); + /* no pledge */ + if (gzip) { + if (!msgfile || !seckeyfile || !sigfile) + usage("must specify message sigfile seckey"); + zsign(seckeyfile, msgfile, sigfile); + } else { + if (!msgfile || !seckeyfile) + usage("must specify message and seckey"); + sign(seckeyfile, msgfile, sigfile, embedded); + } break; #endif case VERIFY: - if (!msgfile) - usage("must specify message"); - verify(pubkeyfile, msgfile, sigfile, embedded, quiet); + if ((embedded || gzip) && + (msgfile && strcmp(msgfile, "-") != 0)) { + /* will need to create output file */ + if (pledge("stdio rpath wpath cpath", NULL) == -1) + err(1, "pledge"); + } else { + if (pledge("stdio rpath", NULL) == -1) + err(1, "pledge"); + } + if (gzip) { + zverify(pubkeyfile, msgfile, sigfile, keytype); + } else { + if (!msgfile) + usage("must specify message"); + verify(pubkeyfile, msgfile, sigfile, embedded, + quiet, keytype); + } break; default: + if (pledge("stdio", NULL) == -1) + err(1, "pledge"); usage(NULL); break; } -- cgit v1.2.3