From 58507325768f8f0a6cef7ba37de4f8492b92fc3b Mon Sep 17 00:00:00 2001 From: mdw Date: Tue, 13 Sep 2005 15:25:39 +0000 Subject: [PATCH] Verify key fingerprints. --- key.1 | 38 ++++++++++++++++++++--- keyutil.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+), 5 deletions(-) diff --git a/key.1 b/key.1 index 07237a7..785021e 100644 --- a/key.1 +++ b/key.1 @@ -117,6 +117,14 @@ is one of: .IR hash ] .RI [ tag ...] .br +.B verify +.RB [ \-f +.IR filter ] +.RB [ \-a +.IR hash ] +.I tag +.I fingerprint +.br .B tidy .br .B extract @@ -301,7 +309,9 @@ command. .B hash The hash functions which can be used with the .B fingerprint -command. +and +.B verify +commands. .TP .B ec The built-in elliptic curves which can be used with the @@ -613,7 +623,7 @@ Finally, the option can be given, in which case the parameters are taken directly from the provided group specification, which may either be the the name of one of the built-in groups (say -.B "key add \-a dh\-param \-C list 42" +.B "key show dh" for a list) or a triple .RI ( p ,\ q ,\ g ). separated by commas. No random generation is done in this case: the @@ -715,7 +725,7 @@ A can be given explicitly (in which case .RB ` \-b ' is ignored). It can either be the name of a built-in curve (say -.B "key add \-a ec\-param \-C list 42" +.B "key show ec" for a list of curve names) or a full specification. The curve is checked for correctness and security according to the SEC1 specification: failed checks cause a warning to be issued to standard @@ -868,7 +878,7 @@ decrypt locked keys. Make sure nobody is looking over your shoulder when you do this! .SS "fingerprint" Reports a fingerprint (secure hash) on components of requested keys. -The following option is supported: +The following options are supported: .TP .BI "\-f, \-\-filter " filter Specifies a filter. Only keys and key components which match the filter @@ -877,7 +887,7 @@ components. .TP .BI "\-a, \-\-algorithm " hash Names the hashing algorithm. Run -.B hashsum -a list +.B key show hash for a list of hashing algorithms. The default is .BR rmd160 . .PP @@ -886,6 +896,24 @@ command line arguments. If no key tags are given, all keys which match the filter are fingerprinted. See .BR keyring (5) for a description of how key fingerprints are computed. +.SS "verify" +Check a key's fingerprint against a reference copy. The following +options are supported: +.TP +.BI "\-f, \-\-filter " filter +Specifies a filter. Only key components which match the filter are +hashed. The default is to only fingerprint nonsecret components. An +error is reported if no part of the key matches. +.TP +.BI "\-a, \-\-algorithm " hash +Names the hashing algorithm. Run +.B key show hash +for a list of hashing algorithms. The default is +.BR rmd160 . +.PP +The reference fingerprint is given as hex, in upper or lower case. The +hash may contain hyphens, colons and whitespace. Other characters are +not permitted. .SS "tidy" Simply reads the keyring from file and writes it back again. This has the effect of removing any deleted keys from the file. diff --git a/keyutil.c b/keyutil.c index 5e1fa66..1ead08d 100644 --- a/keyutil.c +++ b/keyutil.c @@ -31,6 +31,7 @@ #include "config.h" +#include #include #include #include @@ -1695,6 +1696,101 @@ static int cmd_finger(int argc, char *argv[]) return (rc); } +/* --- @cmd_verify@ --- */ + +static unsigned xdigit(char c) +{ + if ('A' <= c && c <= 'Z') return (c + 10 - 'A'); + if ('a' <= c && c <= 'z') return (c + 10 - 'a'); + if ('0' <= c && c <= '9') return (c - '0'); + return (~0u); +} + +static void unhexify(octet *q, char *p, size_t n) +{ + unsigned a = 0; + int i = 0; + + for (;;) { + if (*p == '-' || *p == ':' || isspace((unsigned char)*p)) { + p++; + continue; + } + if (!n && !*p) + break; + if (!*p) + die(EXIT_FAILURE, "hex string too short"); + if (!isxdigit((unsigned char)*p)) + die(EXIT_FAILURE, "bad hex string"); + if (!n) + die(EXIT_FAILURE, "hex string too long"); + a = (a << 4) | xdigit(*p++); + i++; + if (i == 2) { + *q++ = U8(a); + a = 0; + i = 0; + n--; + } + } +} + +static int cmd_verify(int argc, char *argv[]) +{ + key_file f; + int rc = 0; + const gchash *ch = &rmd160; + ghash *h; + key *k; + octet *buf; + const octet *fpr; + key_filter kf = { KF_NONSECRET, KF_NONSECRET }; + + for (;;) { + static struct option opt[] = { + { "filter", OPTF_ARGREQ, 0, 'f' }, + { "algorithm", OPTF_ARGREQ, 0, 'a' }, + { 0, 0, 0, 0 } + }; + int i = mdwopt(argc, argv, "+f:a:", opt, 0, 0, 0); + if (i < 0) + break; + switch (i) { + case 'f': { + char *p; + int err = key_readflags(optarg, &p, &kf.f, &kf.m); + if (err || *p) + die(EXIT_FAILURE, "bad filter string `%s'", optarg); + } break; + case 'a': + if ((ch = ghash_byname(optarg)) == 0) + die(EXIT_FAILURE, "unknown hash algorithm `%s'", optarg); + break; + default: + rc = 1; + break; + } + } + + argv += optind; argc -= optind; + if (rc || argc != 2) + die(EXIT_FAILURE, "Usage: verify [-f FILTER] TAG FINGERPRINT"); + + doopen(&f, KOPEN_READ); + + if ((k = key_bytag(&f, argv[0])) == 0) + die(EXIT_FAILURE, "key `%s' not found", argv[0]); + buf = xmalloc(ch->hashsz); + unhexify(buf, argv[1], ch->hashsz); + h = GH_INIT(ch); + if (!key_fingerprint(k, h, &kf)) + die(EXIT_FAILURE, "key has no fingerprintable components (as filtered)"); + fpr = GH_DONE(h, 0); + if (memcmp(fpr, buf, ch->hashsz) != 0) + die(EXIT_FAILURE, "key fingerprint mismatch"); + return (0); +} + /* --- @cmd_comment@ --- */ static int cmd_comment(int argc, char *argv[]) @@ -1949,6 +2045,13 @@ Options:\n\ -a, --algorithm=HASH Use the named HASH algorithm.\n\ ($ show hash for list.)\n\ " }, + { "verify", cmd_verify, "verify [-f FILTER] TAG FINGERPRINT", "\ +Options:\n\ +\n\ +-f, --filter=FILT Only hash key components matching FILT.\n\ +-a, --algorithm=HASH Use the named HASH algorithm.\n\ + ($ show hash for list.)\n\ +" }, { "extract", cmd_extract, "extract [-f FILTER] FILE [TAG...]", "\ Options:\n\ \n\ -- 2.11.0