* (c) 2005 Straylight/Edgeware
*/
-/*----- Licensing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
*
* This file is part of Catacomb.
*
* 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,
#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";
#define F_BOGUS 128u
#define F_BUFFER 256u
#define F_UTC 512u
+#define F_NOCHECK 1024u
/*----- Chunk I/O ---------------------------------------------------------*/
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)
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 -------------------------------------*/
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);
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;
{ "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;
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);
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,
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;
{ "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;
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;
} 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);
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 --- */
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);
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 --- */
sig_destroy(&s);
dstr_destroy(&d);
dstr_destroy(&dd);
- return (0);
+ return (0);
}
/*----- Reformatting ------------------------------------------------------*/
{ "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);
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 --- */
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\
-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\
-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]", "\