X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/4e6e01880ca7595d84ae87c169756a2c308a9946..2a7c52031aa0096b4f20ec1dd72e5f6e08a19aa9:/dsig.c diff --git a/dsig.c b/dsig.c index 030ad0a..c379e94 100644 --- a/dsig.c +++ b/dsig.c @@ -1,13 +1,13 @@ /* -*-c-*- * - * $Id: dsig.c,v 1.9 2004/04/08 01:02:15 mdw Exp $ + * $Id$ * * Verify signatures on distribuitions of files * * (c) 2000 Straylight/Edgeware */ -/*----- Licensing notice --------------------------------------------------* +/*----- Licensing notice --------------------------------------------------* * * This file is part of Catacomb. * @@ -15,54 +15,18 @@ * 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, * MA 02111-1307, USA. */ -/*----- Revision history --------------------------------------------------* - * - * $Log: dsig.c,v $ - * Revision 1.9 2004/04/08 01:02:15 mdw - * Incompatible change! Add new signature schemes. Key now implies - * algorithms (integrity checked by new fingerprinting rules), so don't put - * that stuff in the manifest. - * - * Revision 1.8 2004/04/04 19:42:59 mdw - * Add set -e. - * - * Revision 1.7 2001/02/23 09:04:17 mdw - * Add new hash functions. Provide full help for subcommands. Run the - * hash function over parts of the header in a canonical order. - * - * Revision 1.6 2000/12/06 20:33:27 mdw - * Make flags be macros rather than enumerations, to ensure that they're - * unsigned. - * - * Revision 1.5 2000/10/08 12:12:09 mdw - * Shut up some warnings. - * - * Revision 1.4 2000/08/04 23:23:44 mdw - * Various fixes. - * - * Revision 1.3 2000/07/15 20:53:23 mdw - * More hash functions. Bug fix in getstring. - * - * Revision 1.2 2000/07/01 11:27:22 mdw - * Use new PKCS#1 padding functions rather than rolling by hand. - * - * Revision 1.1 2000/06/17 10:54:29 mdw - * Program to generate and verify signatures on multiple files. - * - */ - /*----- Header files ------------------------------------------------------*/ #include "config.h" @@ -81,577 +45,12 @@ #include #include "getdate.h" -#include "grand.h" +#include "rand.h" #include "ghash.h" #include "key.h" #include "key-data.h" #include "noise.h" - -#include "ec.h" -#include "ec-keys.h" -#include "dh.h" -#include "gdsa.h" -#include "gkcdsa.h" -#include "rsa.h" - -#include "sha.h" -#include "has160.h" - -/*----- Algorithm choice --------------------------------------------------*/ - -/* --- Relevant type operations --- */ - -typedef struct sig { - const struct sigops *ops; - key_packdef *kp; - ghash *h; -} sig; - -typedef struct sigops { - const key_fetchdef *kf; /* Key fetching structure */ - size_t kdsz; /* Size of the key-data structure */ - sig *(*init)(key */*k*/, void */*kd*/, const gchash */*hc*/); - int (*doit)(sig */*s*/, dstr */*d*/); - void (*destroy)(sig */*s*/); -} sigops; - -/* --- RSA PKCS1 --- */ - -typedef struct rsap1_sigctx { - sig s; - rsa_privctx rp; - pkcs1 p1; -} rsap1_sigctx; - -static sig *rsap1_siginit(key *k, void *kd, const gchash *hc) -{ - rsap1_sigctx *rs = CREATE(rsap1_sigctx); - rsa_privcreate(&rs->rp, kd, &rand_global); - rs->p1.r = &rand_global; - rs->p1.ep = hc->name; - rs->p1.epsz = strlen(hc->name) + 1; - rs->s.h = 0; - return (&rs->s); -} - -static int rsap1_sigdoit(sig *s, dstr *d) -{ - rsap1_sigctx *rs = (rsap1_sigctx *)s; - size_t n; - mp *m = rsa_sign(&rs->rp, MP_NEW, - GH_DONE(s->h, 0), GH_CLASS(s->h)->hashsz, - pkcs1_sigencode, &rs->p1); - if (!m) return (-1); - n = mp_octets(rs->rp.rp->n); dstr_ensure(d, n); mp_storeb(m, d->buf, n); - d->len += n; mp_drop(m); - return (0); -} - -static void rsap1_sigdestroy(sig *s) -{ - rsap1_sigctx *rs = (rsap1_sigctx *)s; - DESTROY(rs); -} - -static const sigops rsap1_sig = { - rsa_privfetch, sizeof(rsa_priv), - rsap1_siginit, rsap1_sigdoit, rsap1_sigdestroy -}; - -typedef struct rsap1_vrfctx { - sig s; - rsa_pubctx rp; - pkcs1 p1; -} rsap1_vrfctx; - -static sig *rsap1_vrfinit(key *k, void *kd, const gchash *hc) -{ - rsap1_vrfctx *rv = CREATE(rsap1_vrfctx); - rsa_pubcreate(&rv->rp, kd); - rv->p1.r = &rand_global; - rv->p1.ep = hc->name; - rv->p1.epsz = strlen(hc->name) + 1; - rv->s.h = 0; - return (&rv->s); -} - -static int rsap1_vrfdoit(sig *s, dstr *d) -{ - rsap1_vrfctx *rv = (rsap1_vrfctx *)s; - mp *m = mp_loadb(MP_NEW, d->buf, d->len); - int rc = rsa_verify(&rv->rp, m, - GH_DONE(s->h, 0), GH_CLASS(s->h)->hashsz, - 0, pkcs1_sigdecode, &rv->p1); - mp_drop(m); - return (rc); -} - -static void rsap1_vrfdestroy(sig *s) -{ - rsap1_vrfctx *rv = (rsap1_vrfctx *)s; - DESTROY(rv); -} - -static const sigops rsap1_vrf = { - rsa_pubfetch, sizeof(rsa_pub), - rsap1_vrfinit, rsap1_vrfdoit, rsap1_vrfdestroy -}; - -/* --- RSA PSS --- */ - -static const gccipher *getmgf(key *k, const gchash *hc) -{ - dstr d = DSTR_INIT; - const gccipher *gc; - const char *mm; - - if ((mm = key_getattr(0, k, "mgf-alg")) == 0) { - dstr_putf(&d, "%s-mgf", hc->name); - mm = d.buf; - } - if ((gc = gcipher_byname(mm)) == 0) - die(EXIT_FAILURE, "unknown encryption scheme `%s'", mm); - dstr_destroy(&d); - return (gc); -} - -typedef struct rsapss_sigctx { - sig s; - rsa_privctx rp; - pss p; -} rsapss_sigctx; - -static sig *rsapss_siginit(key *k, void *kd, const gchash *hc) -{ - rsapss_sigctx *rs = CREATE(rsapss_sigctx); - rsa_privcreate(&rs->rp, kd, &rand_global); - rs->p.r = &rand_global; - rs->p.cc = getmgf(k, hc); - rs->p.ch = hc; - rs->p.ssz = hc->hashsz; - return (&rs->s); -} - -static int rsapss_sigdoit(sig *s, dstr *d) -{ - rsapss_sigctx *rs = (rsapss_sigctx *)s; - size_t n; - mp *m = rsa_sign(&rs->rp, MP_NEW, - GH_DONE(s->h, 0), GH_CLASS(s->h)->hashsz, - pss_encode, &rs->p); - if (!m) return (-1); - n = mp_octets(rs->rp.rp->n); dstr_ensure(d, n); mp_storeb(m, d->buf, n); - d->len += n; mp_drop(m); - return (0); -} - -static void rsapss_sigdestroy(sig *s) -{ - rsapss_sigctx *rs = (rsapss_sigctx *)s; - DESTROY(rs); -} - -static const sigops rsapss_sig = { - rsa_privfetch, sizeof(rsa_priv), - rsapss_siginit, rsapss_sigdoit, rsapss_sigdestroy -}; - -typedef struct rsapss_vrfctx { - sig s; - rsa_pubctx rp; - pss p; -} rsapss_vrfctx; - -static sig *rsapss_vrfinit(key *k, void *kd, const gchash *hc) -{ - rsapss_vrfctx *rv = CREATE(rsapss_vrfctx); - rsa_pubcreate(&rv->rp, kd); - rv->p.r = &rand_global; - rv->p.cc = getmgf(k, hc); - rv->p.ch = hc; - rv->p.ssz = hc->hashsz; - return (&rv->s); -} - -static int rsapss_vrfdoit(sig *s, dstr *d) -{ - rsapss_vrfctx *rv = (rsapss_vrfctx *)s; - mp *m = mp_loadb(MP_NEW, d->buf, d->len); - int rc = rsa_verify(&rv->rp, m, - GH_DONE(s->h, 0), GH_CLASS(s->h)->hashsz, - 0, pss_decode, &rv->p); - mp_drop(m); - return (rc); -} - -static void rsapss_vrfdestroy(sig *s) -{ - rsapss_vrfctx *rv = (rsapss_vrfctx *)s; - DESTROY(rv); -} - -static const sigops rsapss_vrf = { - rsa_pubfetch, sizeof(rsa_pub), - rsapss_vrfinit, rsapss_vrfdoit, rsapss_vrfdestroy -}; - -/* --- DSA and ECDSA --- */ - -typedef struct dsa_sigctx { - sig s; - gdsa g; -} dsa_sigctx; - -static dsa_sigctx *dsa_doinit(key *k, const gprime_param *gp, - mp *y, const gchash *hc) -{ - dsa_sigctx *ds = CREATE(dsa_sigctx); - dstr t = DSTR_INIT; - - key_fulltag(k, &t); - if ((ds->g.g = group_prime(gp)) == 0) - die(EXIT_FAILURE, "bad prime group in key `%s'", t.buf); - ds->g.u = MP_NEW; - ds->g.p = G_CREATE(ds->g.g); - if (G_FROMINT(ds->g.g, ds->g.p, y)) - die(EXIT_FAILURE, "bad public key in key `%s'", t.buf); - ds->g.r = &rand_global; - ds->g.h = hc; - ds->s.h = 0; - dstr_destroy(&t); - return (ds); -} - -static dsa_sigctx *ecdsa_doinit(key *k, const char *cstr, - ec *y, const gchash *hc) -{ - dsa_sigctx *ds = CREATE(dsa_sigctx); - ec_info ei; - const char *e; - dstr t = DSTR_INIT; - - key_fulltag(k, &t); - if ((e = ec_getinfo(&ei, cstr)) != 0) - die(EXIT_FAILURE, "bad curve in key `%s': %s", t.buf, e); - ds->g.g = group_ec(&ei); - ds->g.u = MP_NEW; - ds->g.p = G_CREATE(ds->g.g); - if (G_FROMEC(ds->g.g, ds->g.p, y)) - die(EXIT_FAILURE, "bad public key in key `%s'", t.buf); - ds->g.r = &rand_global; - ds->g.h = hc; - ds->s.h = 0; - dstr_destroy(&t); - return (ds); -} - -static sig *dsa_siginit(key *k, void *kd, const gchash *hc) -{ - dh_priv *dp = kd; - dsa_sigctx *ds = dsa_doinit(k, &dp->dp, dp->y, hc); - ds->g.u = MP_COPY(dp->x); - return (&ds->s); -} - -static sig *ecdsa_siginit(key *k, void *kd, const gchash *hc) -{ - ec_priv *ep = kd; - dsa_sigctx *ds = ecdsa_doinit(k, ep->cstr, &ep->p, hc); - ds->g.u = MP_COPY(ep->x); - return (&ds->s); -} - -static int dsa_sigdoit(sig *s, dstr *d) -{ - dsa_sigctx *ds = (dsa_sigctx *)s; - gdsa_sig ss = GDSA_SIG_INIT; - size_t n = mp_octets(ds->g.g->r); - - gdsa_sign(&ds->g, &ss, GH_DONE(ds->s.h, 0), 0); - dstr_ensure(d, 2 * n); - mp_storeb(ss.r, d->buf, n); - mp_storeb(ss.s, d->buf + n, n); - d->len += 2 * n; - mp_drop(ss.r); mp_drop(ss.s); - return (0); -} - -static void dsa_sigdestroy(sig *s) -{ - dsa_sigctx *ds = (dsa_sigctx *)s; - G_DESTROY(ds->g.g, ds->g.p); - mp_drop(ds->g.u); - G_DESTROYGROUP(ds->g.g); -} - -static const sigops dsa_sig = { - dh_privfetch, sizeof(dh_priv), - dsa_siginit, dsa_sigdoit, dsa_sigdestroy -}; - -static const sigops ecdsa_sig = { - ec_privfetch, sizeof(ec_priv), - ecdsa_siginit, dsa_sigdoit, dsa_sigdestroy -}; - -static sig *dsa_vrfinit(key *k, void *kd, const gchash *hc) -{ - dh_pub *dp = kd; - dsa_sigctx *ds = dsa_doinit(k, &dp->dp, dp->y, hc); - return (&ds->s); -} - -static sig *ecdsa_vrfinit(key *k, void *kd, const gchash *hc) -{ - ec_pub *ep = kd; - dsa_sigctx *ds = ecdsa_doinit(k, ep->cstr, &ep->p, hc); - return (&ds->s); -} - -static int dsa_vrfdoit(sig *s, dstr *d) -{ - dsa_sigctx *ds = (dsa_sigctx *)s; - gdsa_sig ss; - size_t n = d->len/2; - int rc; - - ss.r = mp_loadb(MP_NEW, d->buf, n); - ss.s = mp_loadb(MP_NEW, d->buf + n, d->len - n); - rc = gdsa_verify(&ds->g, &ss, GH_DONE(ds->s.h, 0)); - mp_drop(ss.r); mp_drop(ss.s); - return (rc); -} - -static const sigops dsa_vrf = { - dh_pubfetch, sizeof(dh_pub), - dsa_vrfinit, dsa_vrfdoit, dsa_sigdestroy -}; - -static const sigops ecdsa_vrf = { - ec_pubfetch, sizeof(ec_pub), - ecdsa_vrfinit, dsa_vrfdoit, dsa_sigdestroy -}; - -/* --- KCDSA and ECKCDSA --- */ - -static void kcdsa_privkey(dsa_sigctx *ds, mp *x) - { ds->g.u = mp_modinv(MP_NEW, x, ds->g.g->r); } - -static void kcdsa_sethash(dsa_sigctx *ds, const gchash *hc) - { ds->s.h = gkcdsa_beginhash(&ds->g); } - -static sig *kcdsa_siginit(key *k, void *kd, const gchash *hc) -{ - dh_priv *dp = kd; - dsa_sigctx *ds = dsa_doinit(k, &dp->dp, dp->y, hc); - kcdsa_privkey(ds, dp->x); - kcdsa_sethash(ds, hc); - return (&ds->s); -} - -static sig *eckcdsa_siginit(key *k, void *kd, const gchash *hc) -{ - ec_priv *ep = kd; - dsa_sigctx *ds = ecdsa_doinit(k, ep->cstr, &ep->p, hc); - kcdsa_privkey(ds, ep->x); - kcdsa_sethash(ds, hc); - return (&ds->s); -} - -static int kcdsa_sigdoit(sig *s, dstr *d) -{ - dsa_sigctx *ds = (dsa_sigctx *)s; - gkcdsa_sig ss = GKCDSA_SIG_INIT; - size_t hsz = ds->g.h->hashsz, n = mp_octets(ds->g.g->r); - - gkcdsa_sign(&ds->g, &ss, GH_DONE(ds->s.h, 0), 0); - dstr_ensure(d, hsz + n); - memcpy(d->buf, ss.r, hsz); - mp_storeb(ss.s, d->buf + hsz, n); - d->len += hsz + n; - xfree(ss.r); mp_drop(ss.s); - return (0); -} - -static const sigops kcdsa_sig = { - dh_privfetch, sizeof(dh_priv), - kcdsa_siginit, kcdsa_sigdoit, dsa_sigdestroy -}; - -static const sigops eckcdsa_sig = { - ec_privfetch, sizeof(ec_priv), - eckcdsa_siginit, kcdsa_sigdoit, dsa_sigdestroy -}; - -static sig *kcdsa_vrfinit(key *k, void *kd, const gchash *hc) -{ - dh_pub *dp = kd; - dsa_sigctx *ds = dsa_doinit(k, &dp->dp, dp->y, hc); - kcdsa_sethash(ds, hc); - return (&ds->s); -} - -static sig *eckcdsa_vrfinit(key *k, void *kd, const gchash *hc) -{ - ec_pub *ep = kd; - dsa_sigctx *ds = ecdsa_doinit(k, ep->cstr, &ep->p, hc); - kcdsa_sethash(ds, hc); - return (&ds->s); -} - -static int kcdsa_vrfdoit(sig *s, dstr *d) -{ - dsa_sigctx *ds = (dsa_sigctx *)s; - gkcdsa_sig ss; - size_t hsz = ds->g.h->hashsz, n = d->len - hsz; - int rc; - - if (d->len < hsz) - return (-1); - ss.r = (octet *)d->buf; - ss.s = mp_loadb(MP_NEW, d->buf + hsz, n); - rc = gkcdsa_verify(&ds->g, &ss, GH_DONE(ds->s.h, 0)); - mp_drop(ss.s); - return (rc); -} - -static const sigops kcdsa_vrf = { - dh_pubfetch, sizeof(dh_pub), - kcdsa_vrfinit, kcdsa_vrfdoit, dsa_sigdestroy -}; - -static const sigops eckcdsa_vrf = { - ec_pubfetch, sizeof(ec_pub), - eckcdsa_vrfinit, kcdsa_vrfdoit, dsa_sigdestroy -}; - -/* --- The switch table --- */ - -static const struct sigtab { - const char *name; - const sigops *signops; - const sigops *verifyops; - const gchash *ch; -} sigtab[] = { - { "rsapkcs1", &rsap1_sig, &rsap1_vrf, &sha }, - { "rsapss", &rsapss_sig, &rsapss_vrf, &sha }, - { "dsa", &dsa_sig, &dsa_vrf, &sha }, - { "ecdsa", &ecdsa_sig, &ecdsa_vrf, &sha }, - { "kcdsa", &kcdsa_sig, &kcdsa_vrf, &has160 }, - { "eckcdsa", &eckcdsa_sig, &eckcdsa_vrf, &has160 }, - { 0, 0, 0 } -}; - -/* --- @getsig@ --- * - * - * Arguments: @key *k@ = the key to load - * @int wantpriv@ = nonzero if we want to sign - * - * Returns: A signature-making thing. - * - * Use: Loads a key and starts hashing. - */ - -static sig *getsig(key *k, int wantpriv) -{ - const char *salg, *halg = 0; - dstr d = DSTR_INIT; - dstr t = DSTR_INIT; - char *p = 0; - const char *q; - sig *s; - const struct sigtab *st; - const sigops *so; - const gchash *ch; - void *kd; - int e; - key_packdef *kp; - - /* --- Setup stuff --- */ - - key_fulltag(k, &t); - - /* --- Get the signature algorithm --- * - * - * Take the attribute if it's there; otherwise use the key type. - */ - - if ((q = key_getattr(0, k, "sig-alg")) != 0) { - dstr_puts(&d, q); - p = d.buf; - } else if (strncmp(k->type, "dsig-", 5) == 0 && k->type[5]) { - dstr_puts(&d, k->type); - p = d.buf + 5; - } else - die(EXIT_FAILURE, "no signature algorithm for key `%s'", t.buf); - - /* --- Grab the hash algorithm --- * - * - * Grab it from the signature algorithm if it's there. But override that - * from the attribute. - */ - - salg = p; - if ((p = strchr(p, '-')) != 0) { - *p++ = 0; - halg = p; - } - if ((q = key_getattr(0, k, "hash-alg")) != 0) - halg = q; - - /* --- Look up the algorithms in the table --- */ - - for (st = sigtab; st->name; st++) { - if (strcmp(st->name, salg) == 0) - goto s_found; - } - die(EXIT_FAILURE, "signature algorithm `%s' not found in key `%s'", - salg, t.buf); -s_found:; - if (!halg) - ch = st->ch; - else { - if ((ch = ghash_byname(halg)) == 0) { - die(EXIT_FAILURE, "hash algorithm `%s' not found in key `%s'", - halg, t.buf); - } - } - so = wantpriv ? st->signops : st->verifyops; - - /* --- Load the key --- */ - - kd = xmalloc(so->kdsz); - kp = key_fetchinit(so->kf, 0, kd); - if ((e = key_fetch(kp, k)) != 0) - die(EXIT_FAILURE, "error fetching key `%s': %s", t.buf, key_strerror(e)); - s = so->init(k, kd, ch); - if (!s->h) - s->h = GH_INIT(ch); - s->kp = kp; - s->ops = so; - - /* --- Free stuff up --- */ - - dstr_destroy(&d); - dstr_destroy(&t); - return (s); -} - -/* --- @freesig@ --- * - * - * Arguments: @sig *s@ = signature-making thing - * - * Returns: --- - * - * Use: Frees up a signature-making thing - */ - -static void freesig(sig *s) -{ - GH_DESTROY(s->h); - key_fetchdone(s->kp); - s->ops->destroy(s); -} +#include "cc.h" /*----- Data formatting ---------------------------------------------------*/ @@ -1086,8 +485,13 @@ static void blob(block *b, dstr *d) case T_DATE: case T_EXPIRE: DENSURE(d, 8); - STORE32(d->buf + d->len, ((b->t & ~MASK32) >> 16) >> 16); - STORE32(d->buf + d->len + 4, b->t); + if (b->t == KEXP_FOREVER) { + STORE32(d->buf + d->len, 0xffffffff); + STORE32(d->buf + d->len + 4, 0xffffffff); + } else { + STORE32(d->buf + d->len, ((b->t & ~MASK32) >> 16) >> 16); + STORE32(d->buf + d->len + 4, b->t); + } d->len += 8; break; case T_KEYID: @@ -1181,30 +585,13 @@ static void bemit(block *b, FILE *fp, ghash *h, unsigned bin) if (fp && !bin) bwrite(b, fp); } - + /*----- Static variables --------------------------------------------------*/ static const char *keyring = "keyring"; /*----- Other shared functions --------------------------------------------*/ -/* --- @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); -} - /* --- @fhash@ --- * * * Arguments: @const gchash *c@ = pointer to hash class @@ -1257,9 +644,8 @@ static void fhex(FILE *fp, const void *p, size_t sz) sz--; if (!sz) break; -/* putc(' ', fp); */ } -} +} /*----- Signature generation ----------------------------------------------*/ @@ -1268,6 +654,7 @@ static int sign(int argc, char *argv[]) #define f_raw 1u #define f_bin 2u #define f_bogus 4u +#define f_nocheck 8u unsigned f = 0; const char *ki = "dsig"; @@ -1279,6 +666,7 @@ static int sign(int argc, char *argv[]) const char *ifile = 0; const char *ofile = 0; const char *c = 0; + const char *err; FILE *ifp, *ofp; dstr d = DSTR_INIT; block b; @@ -1295,9 +683,10 @@ static int sign(int argc, char *argv[]) { "output", OPTF_ARGREQ, 0, 'o' }, { "key", OPTF_ARGREQ, 0, 'k' }, { "expire", OPTF_ARGREQ, 0, 'e' }, + { "nocheck", OPTF_ARGREQ, 0, 'C' }, { 0, 0, 0, 0 } }; - int i = mdwopt(argc, argv, "+0vqb c: f:o: k:e:", opts, 0, 0, 0); + int i = mdwopt(argc, argv, "+0vqbC" "c:" "f:o:" "k:e:", opts, 0, 0, 0); if (i < 0) break; switch (i) { @@ -1314,6 +703,9 @@ static int sign(int argc, char *argv[]) if (verb > 0) verb--; break; + case 'C': + f |= f_nocheck; + break; case 'c': c = optarg; break; @@ -1338,11 +730,11 @@ static int sign(int argc, char *argv[]) } } if (optind != argc || (f & f_bogus)) - die(EXIT_FAILURE, "Usage: sign [-options]"); + die(EXIT_FAILURE, "Usage: sign [-OPTIONS]"); /* --- Locate the signing key --- */ - if (key_open(&kf, keyring, KOPEN_WRITE, keyreport, 0)) + if (key_open(&kf, keyring, KOPEN_WRITE, key_moan, 0)) die(EXIT_FAILURE, "couldn't open keyring `%s'", keyring); if ((k = key_bytag(&kf, ki)) == 0) die(EXIT_FAILURE, "couldn't find key `%s'", ki); @@ -1351,7 +743,12 @@ static int sign(int argc, char *argv[]) die(EXIT_FAILURE, "key `%s' expires: can't create nonexpiring signature", d.buf); } - s = getsig(k, 1); + s = getsig(k, "dsig", 1); + + /* --- Check the key --- */ + + if (!(f & f_nocheck) && (err = s->ops->check(s)) != 0) + moan("key `%s' fails check: %s", d.buf, err); /* --- Open files --- */ @@ -1374,7 +771,7 @@ static int sign(int argc, char *argv[]) binit(&b); b.tag = T_IDENT; dstr_putf(&b.d, "%s, Catacomb version " VERSION, QUIS); bemit(&b, ofp, 0, f & f_bin); - + breset(&b); b.tag = T_KEYID; b.k = k->id; bemit(&b, ofp, 0, f & f_bin); @@ -1472,6 +869,7 @@ static int sign(int argc, char *argv[]) #undef f_raw #undef f_bin #undef f_bogus +#undef f_nocheck } /*----- Signature verification --------------------------------------------*/ @@ -1481,6 +879,7 @@ static int verify(int argc, char *argv[]) #define f_bogus 1u #define f_bin 2u #define f_ok 4u +#define f_nocheck 8u unsigned f = 0; unsigned verb = 1; @@ -1488,6 +887,7 @@ static int verify(int argc, char *argv[]) key *k = 0; sig *s; dstr d = DSTR_INIT; + const char *err; FILE *fp; block b; int e; @@ -1498,9 +898,10 @@ static int verify(int argc, char *argv[]) static struct option opts[] = { { "verbose", 0, 0, 'v' }, { "quiet", 0, 0, 'q' }, + { "nocheck", 0, 0, 'C' }, { 0, 0, 0, 0 } }; - int i = mdwopt(argc, argv, "+vq", opts, 0, 0, 0); + int i = mdwopt(argc, argv, "+vqC", opts, 0, 0, 0); if (i < 0) break; switch (i) { @@ -1511,6 +912,9 @@ static int verify(int argc, char *argv[]) if (verb) verb--; break; + case 'C': + f |= f_nocheck; + break; default: f |= f_bogus; break; @@ -1519,11 +923,11 @@ static int verify(int argc, char *argv[]) argc -= optind; argv += optind; if ((f & f_bogus) || argc > 1) - die(EXIT_FAILURE, "Usage: verify [-qv] [file]"); + die(EXIT_FAILURE, "Usage: verify [-qvC] [FILE]"); /* --- Open the key file, and start reading the input file --- */ - if (key_open(&kf, keyring, KOPEN_READ, keyreport, 0)) + if (key_open(&kf, keyring, KOPEN_READ, key_moan, 0)) die(EXIT_FAILURE, "couldn't open keyring `%s'\n", keyring); if (argc < 1) fp = stdin; @@ -1579,14 +983,16 @@ static int verify(int argc, char *argv[]) /* --- Initialize the hash function and start reading hashed packets --- */ - s = getsig(k, 0); - if (!k) { if (verb) puts("FAIL no keyid packet found"); exit(EXIT_FAILURE); } + s = getsig(k, "dsig", 0); + if (!(f & f_nocheck) && verb && (err = s->ops->check(s)) != 0) + printf("WARN public key fails check: %s", err); + for (;;) { switch (e) { case T_COMMENT: @@ -1604,7 +1010,7 @@ static int verify(int argc, char *argv[]) break; case T_EXPIRE: { time_t now = time(0); - if (b.t < now) { + if (b.t != KEXP_FOREVER && b.t < now) { if (verb > 1) puts("BAD signature has expired"); f |= f_bogus; @@ -1677,30 +1083,42 @@ done: #undef f_bogus #undef f_bin #undef f_ok +#undef f_nocheck } /*----- Main code ---------------------------------------------------------*/ -typedef struct cmd { - const char *name; - int (*func)(int /*argc*/, char */*argv*/[]); - const char *usage; - const char *help; -} cmd; +#define LISTS(LI) \ + LI("Lists", list, \ + listtab[i].name, listtab[i].name) \ + LI("Signature schemes", sig, \ + sigtab[i].name, sigtab[i].name) \ + LI("Hash functions", hash, \ + ghashtab[i], ghashtab[i]->name) + +MAKELISTTAB(listtab, LISTS) + +int cmd_show(int argc, char *argv[]) +{ + return (displaylists(listtab, argv + 1)); +} + +static int cmd_help(int, char **); static cmd cmdtab[] = { -/* { "manifest", manifest, */ -/* "manifest [-0] [-o output]" }, */ + { "help", cmd_help, "help [COMMAND...]" }, + { "show", cmd_show, "show [ITEM...]" }, { "sign", sign, - "sign [-options]\n\ - [-0bqv] [-c comment] [-k tag] [-i keyid]\n\ - [-e expire] [-f file] [-o output]", "\ + "sign [-0bqvC] [-c COMMENT] [-k TAG] [-e EXPIRE]\n\t\ +[-f FILE] [-o OUTPUT]", + "\ Options:\n\ \n\ -0, --null Read null-terminated filenames from stdin.\n\ -b, --binary Produce a binary output file.\n\ -q, --quiet Produce fewer messages while working.\n\ -v, --verbose Produce more messages while working.\n\ +-C, --nocheck Don't check the private key.\n\ -c, --comment=COMMENT Include COMMENT in the output file.\n\ -f, --file=FILE Read filenames to hash from FILE.\n\ -o, --output=FILE Write the signed result to FILE.\n\ @@ -1708,77 +1126,46 @@ Options:\n\ -e, --expire=TIME The signature should expire after TIME.\n\ " }, { "verify", verify, - "verify [-qv] [file]", "\ + "verify [-qvC] [FILE]", "\ Options:\n\ \n\ -q, --quiet Produce fewer messages while working.\n\ -v, --verbose Produce more messages while working.\n\ +-C, --nocheck Don't check the public key.\n\ " }, { 0, 0, 0 } }; -/* --- @findcmd@ --- * - * - * Arguments: @const char *name@ = a command name - * - * Returns: Pointer to the command structure. - * - * Use: Looks up a command by name. If the command isn't found, an - * error is reported and the program is terminated. - */ - -static cmd *findcmd(const char *name) +static int cmd_help(int argc, char **argv) { - cmd *c, *chosen = 0; - size_t sz = strlen(name); - - for (c = cmdtab; c->name; c++) { - if (strncmp(name, c->name, sz) == 0) { - if (c->name[sz] == 0) { - chosen = c; - break; - } else if (chosen) - die(EXIT_FAILURE, "ambiguous command name `%s'", name); - else - chosen = c; - } - } - if (!chosen) - die(EXIT_FAILURE, "unknown command name `%s'", name); - return (chosen); + sc_help(cmdtab, stdout, argv + 1); + return (0); } -static void version(FILE *fp) +void version(FILE *fp) { pquis(fp, "$, Catacomb version " VERSION "\n"); } static void usage(FILE *fp) { - pquis(fp, "Usage: $ [-k keyring] command [args]\n"); + pquis(fp, "Usage: $ [-k KEYRING] COMMAND [ARGS]\n"); } -static void help(FILE *fp, char **argv) +void help_global(FILE *fp) { - cmd *c; - - if (*argv) { - c = findcmd(*argv); - fprintf(fp, "Usage: %s [-k keyring] %s\n", QUIS, c->usage); - if (c->help) { - fputc('\n', fp); - fputs(c->help, fp); - } - } else { - version(fp); - fputc('\n', fp); - usage(fp); - fputs("\n\ + usage(fp); + fputs("\n\ Create and verify signatures on lists of files.\n\ -\n", fp); - for (c = cmdtab; c->name; c++) - fprintf(fp, "%s\n", c->usage); - } +\n\ +Global command-line options:\n\ +\n\ +-h, --help [COMMAND...] Show this help message, or help for COMMANDs.\n\ +-v, --version Show program version number.\n\ +-u, --usage Show a terse usage message.\n\ +\n\ +-k, --keyring=FILE Read keys from FILE.\n", + fp); } /* --- @main@ --- * @@ -1820,7 +1207,7 @@ int main(int argc, char *argv[]) break; switch (i) { case 'h': - help(stdout, argv + optind); + sc_help(cmdtab, stdout, argv + optind); exit(0); break; case 'v': @@ -1849,7 +1236,7 @@ int main(int argc, char *argv[]) /* --- Dispatch to the correct subcommand handler --- */ - return (findcmd(argv[0])->func(argc, argv)); + return (findcmd(cmdtab, argv[0])->cmd(argc, argv)); #undef f_bogus }