/* -*-c-*-
*
- * $Id: dsig.c,v 1.2 2000/07/01 11:27:22 mdw Exp $
+ * $Id: dsig.c,v 1.7 2001/02/23 09:04:17 mdw Exp $
*
* Verify signatures on distribuitions of files
*
/*----- Revision history --------------------------------------------------*
*
* $Log: dsig.c,v $
+ * 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 <ctype.h> 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.
*
#include <mLib/report.h>
#include <mLib/sub.h>
-#include "dsa.h"
#include "getdate.h"
#include "grand.h"
#include "ghash.h"
#include "key.h"
#include "key-data.h"
-#include "md5.h"
#include "noise.h"
+
+#include "dsa.h"
+#include "rsa.h"
#include "pkcs1.h"
+
+#include "md2.h"
+#include "md4.h"
+#include "md5.h"
+#include "rmd128.h"
#include "rmd160.h"
-#include "rsa.h"
+#include "rmd256.h"
+#include "rmd320.h"
#include "sha.h"
+#include "sha256.h"
+#include "sha384.h"
+#include "sha512.h"
+#include "tiger.h"
/*----- Digital signature algorithm ---------------------------------------*/
return (e);
}
sz = mp_octets(dp.dp.q);
+ if (sz < msz)
+ die(EXIT_FAILURE, "hash function too wide for this signing key");
DENSURE(d, sz * 2);
- p = d->buf + d->len;
+ p = (octet *)d->buf + d->len;
rand_get(RAND_GLOBAL, p, sz);
dsa_sign(&dp.dp, dp.x, m, msz, p, sz, p, sz, p + sz, sz);
d->len += sz * 2;
key_packstruct ks[DSA_PUBFETCHSZ];
key_packdef *kp;
size_t sz;
+ const octet *p = s;
int e;
kp = key_fetchinit(dsa_pubfetch, ks, &dp);
return (e);
}
sz = ssz / 2;
- e = dsa_verify(&dp.dp, dp.y, m, msz, s, sz, s + sz, sz);
+ e = dsa_verify(&dp.dp, dp.y, m, msz, p, sz, p + sz, sz);
key_fetchdone(kp);
return (e);
}
const void */*s*/, size_t /*ssz*/);
} sig;
-static const gchash *hashtab[] = { &rmd160, &sha, &md5, 0 };
+static const gchash *hashtab[] = {
+ &rmd160, &tiger, &sha, &sha256, &sha384, &sha512,
+ &rmd128, &rmd256, &rmd320, &md5, &md4, &md2, 0 };
static sig sigtab[] = {
{ "dsa", "dsig-dsa", dsasign, dsaverify },
{ "rsa", "dsig-rsa", rsasign, rsaverify },
again:
ch = getc(fp);
- while (isspace((unsigned char)ch))
+ while (isspace(ch))
ch = getc(fp);
if (ch == '#') {
do ch = getc(fp); while (ch != '\n' && ch != EOF);
if (ch == EOF)
break;
switch (ch) {
- case 'a': ch = '\n'; break;
+ case 'a': ch = '\a'; break;
case 'b': ch = '\b'; break;
case 'f': ch = '\f'; break;
case 'n': ch = '\n'; break;
case 'v': ch = '\v'; break;
}
DPUTC(d, ch);
+ ch = getc(fp);
continue;
}
*
* Arguments: @const gchash *c@ = pointer to hash class
* @const char *file@ = file to hash
- * @octet *b@ = pointer to output buffer
+ * @void *b@ = pointer to output buffer
*
* Returns: Zero if it worked, or nonzero for a system error.
*
* Use: Hashes a file.
*/
-static int fhash(const gchash *c, const char *file, octet *b)
+static int fhash(const gchash *c, const char *file, void *b)
{
FILE *fp = fopen(file, "rb");
ghash *h = c->init();
static int sign(int argc, char *argv[])
{
- enum {
- f_raw = 1,
- f_bin = 2,
- f_bogus = 4
- };
+#define f_raw 1u
+#define f_bin 2u
+#define f_bogus 4u
unsigned f = 0;
const char *kt = 0;
ofile, strerror(errno));
}
+ h = gch->init();
+
/* --- Emit the start of the output --- */
binit(&b); b.tag = T_IDENT;
bemit(&b, ofp, 0, f & f_bin);
breset(&b); b.tag = T_SIGALG; DPUTS(&b.d, s->name);
- bemit(&b, ofp, 0, f & f_bin);
+ bemit(&b, ofp, h, f & f_bin);
breset(&b); b.tag = T_HASHALG; DPUTS(&b.d, gch->name);
- bemit(&b, ofp, 0, f & f_bin);
+ bemit(&b, ofp, h, f & f_bin);
breset(&b); b.tag = T_KEYID; b.k = k->id;
- bemit(&b, ofp, 0, f & f_bin);
+ bemit(&b, ofp, h, f & f_bin);
/* --- Start hashing, and emit the datestamps and things --- */
{
time_t now = time(0);
- h = gch->init();
breset(&b); b.tag = T_DATE; b.t = now; bemit(&b, ofp, h, f & f_bin);
if (exp == KEXP_EXPIRE)
exp = now + 86400 * 28;
if (f & f_bogus)
die(EXIT_FAILURE, "error(s) occurred while creating signature");
return (EXIT_SUCCESS);
+
+#undef f_raw
+#undef f_bin
+#undef f_bogus
}
/*----- Signature verification --------------------------------------------*/
static int verify(int argc, char *argv[])
{
- enum {
- f_bogus = 1,
- f_bin = 2,
- f_ok = 4
- };
+#define f_bogus 1u
+#define f_bin 2u
+#define f_ok 4u
unsigned f = 0;
unsigned verb = 1;
sig *s = sigtab;
const gchash *gch = &rmd160;
dstr d = DSTR_INIT;
- ghash *h;
+ ghash *h = 0;
FILE *fp;
block b;
int e;
/* --- Initialize the hash function and start reading hashed packets --- */
h = gch->init();
+
if (!k) {
if (verb)
puts("FAIL no keyid packet found");
exit(EXIT_FAILURE);
}
+
+ {
+ block bb;
+ binit(&bb);
+ breset(&bb); bb.tag = T_SIGALG; DPUTS(&bb.d, s->name);
+ bemit(&bb, 0, h, 0);
+ breset(&bb); bb.tag = T_HASHALG; DPUTS(&bb.d, gch->name);
+ bemit(&bb, 0, h, 0);
+ breset(&bb); bb.tag = T_KEYID; bb.k = k->id;
+ bemit(&bb, 0, h, 0);
+ bdestroy(&bb);
+ }
+
for (;;) {
switch (e) {
case T_COMMENT:
puts("OK signature verified");
}
return (f & f_bogus ? EXIT_FAILURE : EXIT_SUCCESS);
+
+#undef f_bogus
+#undef f_bin
+#undef f_ok
}
/*----- Main code ---------------------------------------------------------*/
typedef struct cmd {
const char *name;
int (*func)(int /*argc*/, char */*argv*/[]);
+ const char *usage;
const char *help;
} cmd;
/* "manifest [-0] [-o output]" }, */
{ "sign", sign,
"sign [-options]\n\
- [-0v] [-a alg] [-h hash] [-t keytype] [-i keyid]\n\
- [-e expire] [-f file] [-o output]" },
+ [-0bqv] [-a alg] [-h hash] [-t keytype] [-i keyid]\n\
+ [-e expire] [-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\
+-a, --algorithm=SIGALG Use the SIGALG signature algorithm.\n\
+-h, --hash=HASHASL Use the HASHALG message digest algorithm.\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\
+-t, --keytype=TYPE Use a key with type TYPE to do the signing.\n\
+-i, --keyid=ID Use the key with the given ID to do the signing.\n\
+-e, --expire=TIME The signature should expire after TIME.\n\
+" },
{ "verify", verify,
- "verify [-qv] [file]" },
+ "verify [-qv] [file]", "\
+Options:\n\
+\n\
+-q, --quiet Produce fewer messages while working.\n\
+-v, --verbose Produce more messages while working.\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)
+{
+ 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);
+}
+
static void version(FILE *fp)
{
pquis(fp, "$, Catacomb version " VERSION "\n");
pquis(fp, "Usage: $ [-k keyring] command [args]\n");
}
-static void help(FILE *fp)
+static void help(FILE *fp, char **argv)
{
cmd *c;
- version(fp);
- fputc('\n', fp);
- usage(fp);
- fputs("\n\
+
+ 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\
Create and verify signatures on lists of files.\n\
\n", fp);
- for (c = cmdtab; c->name; c++)
- fprintf(fp, "%s\n", c->help);
+ for (c = cmdtab; c->name; c++)
+ fprintf(fp, "%s\n", c->usage);
+ }
}
/* --- @main@ --- *
int main(int argc, char *argv[])
{
unsigned f = 0;
- cmd *c = 0, *cc = 0;
- size_t n;
- enum {
- f_bogus = 1
- };
+#define f_bogus 1u
/* --- Initialize the library --- */
break;
switch (i) {
case 'h':
- help(stdout);
+ help(stdout, argv + optind);
exit(0);
break;
case 'v':
/* --- Dispatch to the correct subcommand handler --- */
- n = strlen(argv[0]);
- for (c = cmdtab; c->name; c++) {
- if (strncmp(argv[0], c->name, n) == 0) {
- if (c->name[n] == 0) {
- cc = c;
- break;
- } else if (cc)
- die(EXIT_FAILURE, "ambiguous command name `%s'", argv[0]);
- else
- cc = c;
- }
- }
- if (!cc)
- die(EXIT_FAILURE, "unknown command `%s'", argv[0]);
- return (cc->func(argc, argv));
+ return (findcmd(argv[0])->func(argc, argv));
+
+#undef f_bogus
}
/*----- That's all, folks -------------------------------------------------*/