From 95d9246390251adba7e6e9f0cc70bf0ebe0b2e60 Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Sun, 22 Jan 2012 13:12:15 +0000 Subject: [PATCH] dsig.c: Allow precomputed hashes to be read from a file. This lets you convert a hashsum(1) file or similar into a dsig(1) signature file. --- dsig.1 | 8 ++++++ dsig.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++---------------- hashsum.c | 7 ++++- 3 files changed, 87 insertions(+), 26 deletions(-) diff --git a/dsig.1 b/dsig.1 index 58cea8f..ad5b6fe 100644 --- a/dsig.1 +++ b/dsig.1 @@ -55,6 +55,8 @@ is one of: \h'8n' .RB [ \-f .IR file ] +.RB [ \-h +.IR file ] .RB [ \-o .IR output ] .br @@ -309,6 +311,12 @@ Read filenames from .I name instead of from standard input. .TP +.BI "\-h, \-\-hashes " name +Rather than hashing files, read precomputed hashes from the file +.IR name , +which should be in the format produced by +.BR hashsum (1). +.TP .BI "\-o, \-\-output " name Write output to .I name diff --git a/dsig.c b/dsig.c index 2707f45..5006423 100644 --- a/dsig.c +++ b/dsig.c @@ -469,14 +469,15 @@ static int sign(int argc, char *argv[]) sig *s; time_t exp = KEXP_EXPIRE; unsigned verb = 0; - const char *ifile = 0; + const char *ifile = 0, *hfile = 0; const char *ofile = 0; const char *c = 0; const char *err; FILE *ifp, *ofp; dstr d = DSTR_INIT; + hfpctx hfp; block b; - int e; + int e, hf, n; for (;;) { static struct option opts[] = { @@ -487,13 +488,15 @@ static int sign(int argc, char *argv[]) { "quiet", 0, 0, 'q' }, { "comment", OPTF_ARGREQ, 0, 'c' }, { "file", OPTF_ARGREQ, 0, 'f' }, + { "hashes", OPTF_ARGREQ, 0, 'h' }, { "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, "+0vpqbC" "c:" "f:o:" "k:e:", opts, 0, 0, 0); + int i = mdwopt(argc, argv, "+0vpqbC" "c:" "f:h:o:" "k:e:", + opts, 0, 0, 0); if (i < 0) break; switch (i) { @@ -522,6 +525,9 @@ static int sign(int argc, char *argv[]) case 'f': ifile = optarg; break; + case 'h': + hfile = optarg; + break; case 'o': ofile = optarg; break; @@ -541,6 +547,8 @@ static int sign(int argc, char *argv[]) } if (optind != argc || (f & f_bogus)) die(EXIT_FAILURE, "Usage: sign [-OPTIONS]"); + if (hfile && ifile) + die(EXIT_FAILURE, "Inconsistent options `-h' and `-f'"); /* --- Locate the signing key --- */ @@ -562,6 +570,7 @@ static int sign(int argc, char *argv[]) /* --- Open files --- */ + if (hfile) ifile = hfile; if (!ifile || strcmp(ifile, "-") == 0) ifp = stdin; else if ((ifp = fopen(ifile, (f & f_bin) ? "rb" : "r")) == 0) { @@ -605,32 +614,70 @@ static int sign(int argc, char *argv[]) /* --- Now hash the various files --- */ - for (;;) { + if (hfile) { + hfp.f = f; + hfp.fp = ifp; + hfp.ee = &encodingtab[ENC_HEX]; + hfp.gch = GH_CLASS(s->h); + hfp.dline = &d; + hfp.dfile = &b.d; + + n = 0; + for (;;) { + breset(&b); + DENSURE(&b.b, hfp.gch->hashsz); + hfp.hbuf = (octet *)b.b.buf; + if (ferror(ofp)) { f |= f_bogus; break; } + if ((hf = hfparse(&hfp)) == HF_EOF) break; + n++; + + switch (hf) { + case HF_HASH: + if (hfp.gch != GH_CLASS(s->h)) { + moan("%s:%d: incorrect hash function `%s' (should be `%s')", + hfile, n, hfp.gch->name, GH_CLASS(s->h)->name); + f |= f_bogus; + } + break; + case HF_BAD: + moan("%s:%d: invalid hash-file line", hfile, n); + f |= f_bogus; + break; + case HF_FILE: + b.tag = T_FILE; + b.b.len += hfp.gch->hashsz; + bemit(&b, ofp, s->h, f & f_bin); + break; + } + } + } else { + for (;;) { - /* --- Stop on an output error --- */ + /* --- Stop on an output error --- */ - if (ferror(ofp)) { - f |= f_bogus; - break; - } + if (ferror(ofp)) { + f |= f_bogus; + break; + } - /* --- Read the next filename to hash --- */ + /* --- Read the next filename to hash --- */ - breset(&b); - if (getstring(ifp, &b.d, GSF_FILE | f)) - break; - b.tag = T_FILE; - DENSURE(&b.b, GH_CLASS(s->h)->hashsz); - if (fhash(GH_CLASS(s->h), f | FHF_BINARY, b.d.buf, b.b.buf)) { - moan("Error reading `%s': %s", b.d.buf, strerror(errno)); - f |= f_bogus; - } else { - b.b.len += GH_CLASS(s->h)->hashsz; - if (verb) { - fhex(stderr, b.b.buf, b.b.len); - fprintf(stderr, " %s\n", b.d.buf); + breset(&b); + if (getstring(ifp, &b.d, GSF_FILE | f)) + break; + b.tag = T_FILE; + DENSURE(&b.b, GH_CLASS(s->h)->hashsz); + if (fhash(GH_CLASS(s->h), f | FHF_BINARY, b.d.buf, b.b.buf)) { + moan("error reading `%s': %s", b.d.buf, strerror(errno)); + f |= f_bogus; + } else { + b.b.len += GH_CLASS(s->h)->hashsz; + if (verb) { + fhex(stderr, b.b.buf, b.b.len); + fprintf(stderr, " %s\n", b.d.buf); + } + bemit(&b, ofp, s->h, f & f_bin); } - bemit(&b, ofp, s->h, f & f_bin); } } @@ -923,7 +970,7 @@ static cmd cmdtab[] = { { "show", cmd_show, "show [ITEM...]" }, { "sign", sign, "sign [-0bpqvC] [-c COMMENT] [-k TAG] [-e EXPIRE]\n\t\ -[-f FILE] [-o OUTPUT]", +[-f FILE] [-h FILE] [-o OUTPUT]", "\ Options:\n\ \n\ @@ -935,6 +982,7 @@ Options:\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\ +-h, --hashes=FILE Read precomputed hashes from FILE.\n\ -o, --output=FILE Write the signed result to FILE.\n\ -k, --key=TAG Use a key named by TAG.\n\ -e, --expire=TIME The signature should expire after TIME.\n\ diff --git a/hashsum.c b/hashsum.c index 23b5d56..d12c506 100644 --- a/hashsum.c +++ b/hashsum.c @@ -113,6 +113,11 @@ static int checkhash(const gchash *gch, unsigned f, } } + if (ferror(hfp.fp)) { + moan("error reading input `%s': %s", + file ? file : "", strerror(errno)); + rc = EXIT_FAILURE; + } dstr_destroy(&dl); dstr_destroy(&df); xfree(hfp.hbuf); @@ -236,7 +241,7 @@ int main(int argc, char *argv[]) { unsigned f = 0; const gchash *gch = 0; - const encodeops *e = &encodingtab[0]; + const encodeops *e = &encodingtab[ENC_HEX]; int rc; /* --- Initialization --- */ -- 2.11.0