X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/f387fcb17a980fe165218d217b0187a8c279508a..f52f2db067dc1388b16ab00ddb53e26a381a6e3e:/catsign.c diff --git a/catsign.c b/catsign.c index dc96e55..8171404 100644 --- a/catsign.c +++ b/catsign.c @@ -7,7 +7,7 @@ * (c) 2005 Straylight/Edgeware */ -/*----- Licensing notice --------------------------------------------------* +/*----- Licensing notice --------------------------------------------------* * * This file is part of Catacomb. * @@ -15,12 +15,12 @@ * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - * + * * Catacomb is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. - * + * * You should have received a copy of the GNU Library General Public * License along with Catacomb; if not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, @@ -50,30 +50,12 @@ #include "noise.h" #include "mprand.h" #include "key.h" +#include "getdate.h" #include "cc.h" #include "ectab.h" #include "ptab.h" -/*----- Utilities ---------------------------------------------------------*/ - -/* --- @keyreport@ --- * - * - * Arguments: @const char *file@ = filename containing the error - * @int line@ = line number in file - * @const char *err@ = error text message - * @void *p@ = unimportant pointer - * - * Returns: --- - * - * Use: Reports errors during the opening of a key file. - */ - -static void keyreport(const char *file, int line, const char *err, void *p) -{ - moan("error in keyring `%s' at line `%s': %s", file, line, err); -} - /*----- Static variables --------------------------------------------------*/ static const char *keyring = "keyring"; @@ -109,6 +91,7 @@ typedef struct sigmsg { #define F_BOGUS 128u #define F_BUFFER 256u #define F_UTC 512u +#define F_NOCHECK 1024u /*----- Chunk I/O ---------------------------------------------------------*/ @@ -216,7 +199,7 @@ static void textwrite(msgcanon *m, const void *bp, size_t n) static size_t binreadembed(msgcanon *m, void *bp) { return (chunk_read(m->e, bp)); } static size_t binreaddetach(msgcanon *m, void *bp) - { return (fread(bp, 1, MSGBUFSZ, m->fp)); } + { return (fread(bp, 1, MSGBUFSZ - 1, m->fp)); } static void binwriteembed(msgcanon *m, const void *bp, size_t n) { chunk_write(m->e, bp, n); } @@ -309,7 +292,7 @@ static void mc_endread(msgcanon *m, const encops *eops, enc **ee) if (m->fp && !(m->f & F_NOCLOSE)) { if (ferror(m->fp) || fclose(m->fp)) die(EXIT_FAILURE, "error closing message file: %s", strerror(errno)); - } + } } static void mc_endwrite(msgcanon *m, const encops *eops, enc **ee) @@ -327,7 +310,7 @@ static void mc_endwrite(msgcanon *m, const encops *eops, enc **ee) if (m->fp && !(m->f & F_NOCLOSE)) { if (fflush(m->fp) || ferror(m->fp) || fclose(m->fp)) die(EXIT_FAILURE, "error closing message file: %s", strerror(errno)); - } + } } /*----- Signature reading and writing -------------------------------------*/ @@ -384,7 +367,7 @@ static void keyhash(key *k, sig *s, dstr *d) ghash *h; key_filter kf; - h = GH_INIT(GH_CLASS(s->h)); + h = GH_INIT(s->ch); kf.f = KCAT_PUB; kf.m = KF_CATMASK; key_fingerprint(k, h, &kf); @@ -456,7 +439,7 @@ static int sign(int argc, char *argv[]) int i; char bb[MSGBUFSZ]; size_t n; - dstr d = DSTR_INIT; + dstr d = DSTR_INIT; const encops *eo; msgcanon mc_in = MC_INIT, mc_out = MC_INIT; enc *e; @@ -471,9 +454,10 @@ static int sign(int argc, char *argv[]) { "format", OPTF_ARGREQ, 0, 'f' }, { "output", OPTF_ARGREQ, 0, 'o' }, { "text", 0, 0, 't' }, + { "nocheck", 0, 0, 'C' }, { 0, 0, 0, 0 } }; - i = mdwopt(argc, argv, "k:f:o:abdt", opt, 0, 0, 0); + i = mdwopt(argc, argv, "k:f:o:abdtC", opt, 0, 0, 0); if (i < 0) break; switch (i) { case 'k': kn = optarg; break; @@ -483,13 +467,14 @@ static int sign(int argc, char *argv[]) case 't': f &= ~F_BINARY; break; case 'b': f |= F_BINARY; break; case 'd': f |= F_DETACH; break; + case 'C': f |= F_NOCHECK; break; default: f |= F_BOGUS; break; } } if (argc - optind > 1 || (f & F_BOGUS)) die(EXIT_FAILURE, "Usage: sign [-OPTIONS] [FILE]"); - if (key_open(&kf, keyring, KOPEN_READ, keyreport, 0)) + if (key_open(&kf, keyring, KOPEN_READ, key_moan, 0)) die(EXIT_FAILURE, "can't open keyring `%s'", keyring); if ((k = key_bytag(&kf, kn)) == 0) die(EXIT_FAILURE, "key `%s' not found", kn); @@ -512,7 +497,7 @@ static int sign(int argc, char *argv[]) dstr_reset(&d); key_fulltag(k, &d); s.s = getsig(k, "ccsig", 1); - if ((err = s.s->ops->check(s.s)) != 0) + if (!(f & F_NOCHECK) && (err = s.s->ops->check(s.s)) != 0) moan("key %s fails check: %s", d.buf, err); keyhash(k, s.s, &s.kh); e = initenc(eo, ofp, @@ -599,6 +584,7 @@ static int verify(int argc, char *argv[]) int i; char bb[MSGBUFSZ]; size_t n; + time_t t_fresh = 0; dstr d = DSTR_INIT, dd = DSTR_INIT; const encops *eo; msgcanon mc_in = MC_INIT; @@ -614,11 +600,13 @@ static int verify(int argc, char *argv[]) { "output", OPTF_ARGREQ, 0, 'o' }, { "quiet", 0, 0, 'q' }, { "utc", 0, 0, 'u' }, + { "fresh-time", 0, 0, 't' }, { "gmt", 0, 0, 'u' }, { "verbose", 0, 0, 'v' }, + { "nocheck", 0, 0, 'C' }, { 0, 0, 0, 0 } }; - i = mdwopt(argc, argv, "k:f:o:abquv", opt, 0, 0, 0); + i = mdwopt(argc, argv, "k:f:o:abqt:uvC", opt, 0, 0, 0); if (i < 0) break; switch (i) { case 'a': ef = "pem"; break; @@ -627,6 +615,12 @@ static int verify(int argc, char *argv[]) case 'f': ef = optarg; break; case 'o': of = optarg; break; case 'u': v.f |= F_UTC; break; + case 'C': v.f |= F_NOCHECK; break; + case 't': + if (strcmp(optarg, "always") == 0) t_fresh = 0; + else if ((t_fresh = get_date(optarg, 0)) < 0) + die(EXIT_FAILURE, "bad freshness time"); + break; case 'q': if (v.verb > 0) v.verb--; break; case 'v': if (v.verb < 10) v.verb++; break; default: v.f |= F_BOGUS; break; @@ -649,7 +643,7 @@ static int verify(int argc, char *argv[]) } else optind++; - if (key_open(&kf, keyring, KOPEN_READ, keyreport, 0)) + if (key_open(&kf, keyring, KOPEN_READ, key_moan, 0)) die(EXIT_FAILURE, "can't open keyring `%s'", keyring); if (kn && (kk = key_bytag(&kf, kn)) == 0) die(EXIT_FAILURE, "key `%s' not found", kn); @@ -683,14 +677,14 @@ static int verify(int argc, char *argv[]) s.s = getsig(k, "ccsig", 0); dstr_reset(&d); key_fulltag(k, &d); - if (v.verb && (err = s.s->ops->check(s.s)) != 0) + if (!(v.f & F_NOCHECK) && v.verb && (err = s.s->ops->check(s.s)) != 0) printf("WARN verification key %s fails check: %s\n", d.buf, err); dstr_reset(&dd); keyhash(k, s.s, &dd); if (dd.len != s.kh.len || memcmp(dd.buf, s.kh.buf, dd.len) != 0) { if (v.verb) printf("FAIL key hash mismatch\n"); exit(EXIT_FAILURE); - } + } /* --- Now a merry dance --- */ @@ -739,6 +733,14 @@ static int verify(int argc, char *argv[]) if (v.verb) printf("FAIL signature verification failed\n"); exit(EXIT_FAILURE); } + if (t_fresh && s.t < t_fresh) { + if (v.verb) printf("FAIL signature is stale\n"); + exit(EXIT_FAILURE); + } + if (s.t > time(0)) { + if (v.verb) printf("FAIL signature timestamp in the future\n"); + exit(EXIT_FAILURE); + } if (v.verb) { tm = (v.f & F_UTC) ? gmtime(&s.t) : localtime(&s.t); strftime(bb, sizeof(bb), "%Y-%m-%d %H:%M:%S %Z", tm); @@ -765,7 +767,7 @@ static int verify(int argc, char *argv[]) die(EXIT_FAILURE, "error unbuffering output: %s", strerror(errno)); } if (ofp && (fflush(ofp) || ferror(ofp) || fclose(ofp))) - die(EXIT_FAILURE, "error writing output: %s", strerror(errno)); + die(EXIT_FAILURE, "error writing output: %s", strerror(errno)); /* --- Tidy up --- */ @@ -777,7 +779,7 @@ static int verify(int argc, char *argv[]) sig_destroy(&s); dstr_destroy(&d); dstr_destroy(&dd); - return (0); + return (0); } /*----- Reformatting ------------------------------------------------------*/ @@ -807,8 +809,8 @@ static int format(int argc, char *argv[]) { "embed", 0, 0, 'E' }, { "format-in", OPTF_ARGREQ, 0, 'f' }, { "format-out", OPTF_ARGREQ, 0, 'F' }, - { "message", OPTF_ARGREQ, 0, 'm' }, - { "output", OPTF_ARGREQ, 0, 'o' }, + { "message", OPTF_ARGREQ, 0, 'm' }, + { "output", OPTF_ARGREQ, 0, 'o' }, { 0, 0, 0, 0 } }; i = mdwopt(argc, argv, "f:F:m:o:aADE", opt, 0, 0, 0); @@ -856,7 +858,7 @@ static int format(int argc, char *argv[]) if (((s.f ^ v.f) & v.m) != 0) moan("boundary string inconsistent with contents (ignoring)"); - + mcsetup_read(&mc_in, s.f, &ie, dfn); /* --- Prepare the output stuff --- */ @@ -1056,7 +1058,7 @@ static cmd cmdtab[] = { CMD_ENCODE, CMD_DECODE, { "sign", sign, - "sign [-adt] [-k TAG] [-f FORMAT] [-o OUTPUT] [FILE]", "\ + "sign [-adtC] [-k TAG] [-f FORMAT] [-o OUTPUT] [FILE]", "\ Options:\n\ \n\ -a, --armour Same as `-f pem'.\n\ @@ -1066,9 +1068,10 @@ Options:\n\ -k, --key=TAG Use public encryption key named by TAG.\n\ -o, --output=FILE Write output to FILE.\n\ -t, --text Canonify input message as a text file.\n\ +-C, --nocheck Don't check the private key.\n\ " }, { "verify", verify, - "verify [-abquv] [-f FORMAT] [-k TAG] [-o OUTPUT]\n\t\ + "verify [-abquvC] [-f FORMAT] [-k TAG] [-o OUTPUT]\n\t\ [FILE [MESSAGE]]", "\ Options:\n\ \n\ @@ -1078,8 +1081,10 @@ Options:\n\ -k, --key=TAG Require that the message be signed by key TAG.\n\ -o, --output=FILE Write message to FILE.\n\ -q, --quiet Produce fewer messages.\n\ +-t, --freshtime=TIME Only accept signatures made after this time.\n\ -u, --utc Show dates in UTC rather than local time.\n\ -v, --verbose Produce more verbose messages.\n\ +-C, --nocheck Don't check the public key.\n\ " }, { "info", info, "info [-au] [-f FORMAT] [FILE]", "\