From b0be99fc10e50c41b75647a2486c05f9bd47f1c3 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Tue, 17 Mar 2015 12:53:16 +0100 Subject: command: add generic digest command That can be used for digest calculation and verify Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Sascha Hauer --- commands/Kconfig | 12 +++- commands/Makefile | 1 + commands/digest.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++ commands/hashsum.c | 76 ++++---------------- commands/internal.h | 3 + crypto/digest.c | 25 +++++-- include/digest.h | 8 ++- 7 files changed, 260 insertions(+), 69 deletions(-) create mode 100644 commands/digest.c create mode 100644 commands/internal.h diff --git a/commands/Kconfig b/commands/Kconfig index 49709ded67..2618eda2f6 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -14,7 +14,7 @@ if COMMAND_SUPPORT config COMPILE_HASH tristate - select DIGEST + select CMD_DIGEST help Turns on compilation of digest.c @@ -842,6 +842,16 @@ config CMD_CMP Returns successfully if the two files are the same, return with an error if not +config CMD_DIGEST + tristate + select DIGEST + prompt "digest" + help + Usage: digest -a [-k | -K ] [-s | -S ] FILE|AREA + + Calculate a digest over a FILE or a memory area with the possibility + to checkit. + config CMD_DIRNAME tristate prompt "dirname" diff --git a/commands/Makefile b/commands/Makefile index 095e4b624e..d69e3f0b06 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_STDDEV) += stddev.o +obj-$(CONFIG_CMD_DIGEST) += digest.o obj-$(CONFIG_COMPILE_HASH) += hashsum.o obj-$(CONFIG_COMPILE_MEMORY) += mem.o obj-$(CONFIG_CMD_BOOTM) += bootm.o diff --git a/commands/digest.c b/commands/digest.c new file mode 100644 index 0000000000..ef95e94816 --- /dev/null +++ b/commands/digest.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2015 Jean-Christophe PLAGNIOL-VILLARD + * + * GPLv2 ONLY + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + +int __do_digest(struct digest *d, unsigned char *key, int keylen, + unsigned char *sig, + int argc, char *argv[]) +{ + int ret = COMMAND_ERROR_USAGE; + int i; + unsigned char *hash; + + if (argc < 1) + goto err; + + if (key) { + ret = digest_set_key(d, key, keylen); + if (ret) { + perror("set_key"); + goto err; + } + } + + hash = calloc(digest_length(d), sizeof(unsigned char)); + if (!hash) { + perror("calloc"); + goto err; + } + + while (*argv) { + char *filename = "/dev/mem"; + loff_t start = 0, size = ~0; + + /* arguments are either file, file+area or area */ + if (parse_area_spec(*argv, &start, &size)) { + filename = *argv; + if (argv[1] && !parse_area_spec(argv[1], &start, &size)) + argv++; + } + + ret = digest_file_window(d, filename, + hash, sig, start, size); + if (ret < 0) { + ret = 1; + } else { + if (!sig) { + for (i = 0; i < digest_length(d); i++) + printf("%02x", hash[i]); + + printf(" %s\t0x%08llx ... 0x%08llx\n", + filename, start, start + size); + } + } + + argv++; + } + + free(hash); +err: + digest_free(d); + + return ret; +} + +static void prints_algo_help(void) +{ + puts("\navailable algo:\n"); + digest_algo_prints("\t"); +} + +static int do_digest(int argc, char *argv[]) +{ + struct digest *d; + unsigned char *tmp_key = NULL; + unsigned char *tmp_sig = NULL; + char *sig = NULL; + char *sigfile = NULL; + size_t siglen = 0; + char *key = NULL; + char *keyfile = NULL; + size_t keylen = 0; + size_t digestlen = 0; + char *algo = NULL; + int opt; + int ret = COMMAND_ERROR; + + if (argc < 2) + return COMMAND_ERROR_USAGE; + + while((opt = getopt(argc, argv, "a:k:K:s:S:")) > 0) { + switch(opt) { + case 'k': + key = optarg; + keylen = strlen(key); + break; + case 'K': + keyfile = optarg; + break; + case 'a': + algo = optarg; + break; + case 's': + sig = optarg; + siglen = strlen(sig); + break; + case 'S': + sigfile = optarg; + break; + } + } + + if (!algo) + return COMMAND_ERROR_USAGE; + + d = digest_alloc(algo); + if (!d) { + eprintf("algo '%s' not found\n", algo); + return COMMAND_ERROR_USAGE; + } + + argc -= optind; + argv += optind; + + if (keyfile) { + tmp_key = key = read_file(keyfile, &keylen); + if (!key) { + eprintf("file '%s' not found\n", keyfile); + goto err; + } + } + + ret = digest_set_key(d, key, keylen); + free(tmp_key); + if (ret) + goto err; + + if (sigfile) { + sig = tmp_sig = read_file(sigfile, &siglen); + if (!tmp_sig) { + eprintf("file '%s' not found\n", sigfile); + goto err; + } + } + + if (sig) { + digestlen = digest_length(d); + if (siglen == 2 * digestlen) { + if (!tmp_sig) + tmp_sig = xmalloc(digestlen); + + ret = hex2bin(tmp_sig, sig, digestlen); + if (ret) + goto err; + + sig = tmp_sig; + } else if (siglen != digestlen) { + eprintf("%s wrong size %zu, expected %zu\n", + sigfile, siglen, digestlen); + goto err; + } + } + + ret = __do_digest(d, NULL, 0, sig, argc, argv); + free(tmp_sig); + return ret; + +err: + digest_free(d); + return ret; +} + +BAREBOX_CMD_HELP_START(digest) +BAREBOX_CMD_HELP_TEXT("Calculate a digest over a FILE or a memory area.") +BAREBOX_CMD_HELP_TEXT("Options:") +BAREBOX_CMD_HELP_OPT ("-a \t", "hash or signature algorithm to use") +BAREBOX_CMD_HELP_OPT ("-k \t", "use supplied (ASCII or hex) for MAC") +BAREBOX_CMD_HELP_OPT ("-K \t", "use key from (binary) for MAC") +BAREBOX_CMD_HELP_OPT ("-v \t", "verify data against supplied (hash, MAC or signature)") +BAREBOX_CMD_HELP_OPT ("-V \t", "verify data against (hash, MAC or signature)") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(digest) + .cmd = do_digest, + BAREBOX_CMD_DESC("calculate digest") + BAREBOX_CMD_OPTS("-a [-k | -K ] [-s | -S ] FILE|AREA") + BAREBOX_CMD_GROUP(CMD_GRP_FILE) + BAREBOX_CMD_HELP(cmd_digest_help) + BAREBOX_CMD_USAGE(prints_algo_help) +BAREBOX_CMD_END diff --git a/commands/hashsum.c b/commands/hashsum.c index 59c94ea2bf..dc48af53d8 100644 --- a/commands/hashsum.c +++ b/commands/hashsum.c @@ -27,12 +27,11 @@ #include #include -static int do_digest(char *algorithm, int argc, char *argv[]) +#include "internal.h" + +static int do_hash(char *algo, int argc, char *argv[]) { struct digest *d; - int ret = 0; - int i; - unsigned char *hash; unsigned char *key = NULL; size_t keylen = 0; int opt; @@ -46,71 +45,26 @@ static int do_digest(char *algorithm, int argc, char *argv[]) } } - argc -= optind; - argv += optind; - if (key) { - char *tmp = asprintf("hmac(%s)", algorithm); + char *tmp = asprintf("hmac(%s)", algo); d = digest_alloc(tmp); - BUG_ON(!d); - ret = digest_set_key(d, key, keylen); free(tmp); - if (ret) { - perror("set_key"); - goto err; - } } else { - d = digest_alloc(algorithm); - BUG_ON(!d); - } - - if (argc < 1) - return COMMAND_ERROR_USAGE; - - hash = calloc(digest_length(d), sizeof(unsigned char)); - if (!hash) { - perror("calloc"); - return COMMAND_ERROR_USAGE; - } - - while (*argv) { - char *filename = "/dev/mem"; - loff_t start = 0, size = ~0; - - /* arguments are either file, file+area or area */ - if (parse_area_spec(*argv, &start, &size)) { - filename = *argv; - if (argv[0] && !parse_area_spec(argv[0], &start, &size)) - argv++; - } - - ret = digest_file_window(d, filename, - hash, start, size); - if (ret < 0) { - ret = 1; - } else { - for (i = 0; i < digest_length(d); i++) - printf("%02x", hash[i]); - - printf(" %s\t0x%08llx ... 0x%08llx\n", - filename, start, start + size); - } - - argv++; + d = digest_alloc(algo); } + BUG_ON(!d); -err: - free(hash); - digest_free(d); + argc -= optind; + argv += optind; - return ret; + return __do_digest(d, key, keylen, NULL, argc, argv); } #ifdef CONFIG_CMD_MD5SUM static int do_md5(int argc, char *argv[]) { - return do_digest("md5", argc, argv); + return do_hash("md5", argc, argv); } BAREBOX_CMD_HELP_START(md5sum) @@ -131,7 +85,7 @@ BAREBOX_CMD_END static int do_sha1(int argc, char *argv[]) { - return do_digest("sha1", argc, argv); + return do_hash("sha1", argc, argv); } BAREBOX_CMD_HELP_START(sha1sum) @@ -152,7 +106,7 @@ BAREBOX_CMD_END static int do_sha224(int argc, char *argv[]) { - return do_digest("sha224", argc, argv); + return do_hash("sha224", argc, argv); } BAREBOX_CMD_HELP_START(sha224sum) @@ -173,7 +127,7 @@ BAREBOX_CMD_END static int do_sha256(int argc, char *argv[]) { - return do_digest("sha256", argc, argv); + return do_hash("sha256", argc, argv); } BAREBOX_CMD_HELP_START(sha256sum) @@ -194,7 +148,7 @@ BAREBOX_CMD_END static int do_sha384(int argc, char *argv[]) { - return do_digest("sha384", argc, argv); + return do_hash("sha384", argc, argv); } BAREBOX_CMD_HELP_START(sha384sum) @@ -215,7 +169,7 @@ BAREBOX_CMD_END static int do_sha512(int argc, char *argv[]) { - return do_digest("sha512", argc, argv); + return do_hash("sha512", argc, argv); } BAREBOX_CMD_HELP_START(sha512sum) diff --git a/commands/internal.h b/commands/internal.h new file mode 100644 index 0000000000..29cc656e9b --- /dev/null +++ b/commands/internal.h @@ -0,0 +1,3 @@ +int __do_digest(struct digest *d, unsigned char *key, int keylen, + unsigned char *sig, + int argc, char *argv[]); diff --git a/crypto/digest.c b/crypto/digest.c index 7670ed06b7..047131b537 100644 --- a/crypto/digest.c +++ b/crypto/digest.c @@ -124,6 +124,15 @@ static struct digest_algo *digest_algo_get_by_name(const char *name) return NULL; } +void digest_algo_prints(const char *prefix) +{ + struct digest_algo* d; + + list_for_each_entry(d, &digests, list) { + printf("%s%s\n", prefix, d->name); + } +} + struct digest *digest_alloc(const char *name) { struct digest *d; @@ -157,6 +166,7 @@ EXPORT_SYMBOL_GPL(digest_free); int digest_file_window(struct digest *d, const char *filename, unsigned char *hash, + unsigned char *sig, ulong start, ulong size) { ulong len = 0; @@ -217,7 +227,10 @@ int digest_file_window(struct digest *d, const char *filename, len += now; } - ret = digest_final(d, hash); + if (sig) + ret = digest_verify(d, sig); + else + ret = digest_final(d, hash); out_free: if (flags) @@ -230,7 +243,8 @@ out: EXPORT_SYMBOL_GPL(digest_file_window); int digest_file(struct digest *d, const char *filename, - unsigned char *hash) + unsigned char *hash, + unsigned char *sig) { struct stat st; int ret; @@ -240,12 +254,13 @@ int digest_file(struct digest *d, const char *filename, if (ret < 0) return ret; - return digest_file_window(d, filename, hash, 0, st.st_size); + return digest_file_window(d, filename, hash, sig, 0, st.st_size); } EXPORT_SYMBOL_GPL(digest_file); int digest_file_by_name(const char *algo, const char *filename, - unsigned char *hash) + unsigned char *hash, + unsigned char *sig) { struct digest *d; int ret; @@ -254,7 +269,7 @@ int digest_file_by_name(const char *algo, const char *filename, if (!d) return -EIO; - ret = digest_file(d, filename, hash); + ret = digest_file(d, filename, hash, sig); digest_free(d); return ret; } diff --git a/include/digest.h b/include/digest.h index 718793a1a7..cb579ee03d 100644 --- a/include/digest.h +++ b/include/digest.h @@ -52,17 +52,21 @@ struct digest { */ int digest_algo_register(struct digest_algo *d); void digest_algo_unregister(struct digest_algo *d); +void digest_algo_prints(const char *prefix); struct digest *digest_alloc(const char *name); void digest_free(struct digest *d); int digest_file_window(struct digest *d, const char *filename, unsigned char *hash, + unsigned char *sig, ulong start, ulong size); int digest_file(struct digest *d, const char *filename, - unsigned char *hash); + unsigned char *hash, + unsigned char *sig); int digest_file_by_name(const char *algo, const char *filename, - unsigned char *hash); + unsigned char *hash, + unsigned char *sig); static inline int digest_init(struct digest *d) { -- cgit v1.2.3