diff options
Diffstat (limited to 'programs/cmd_digest.c')
-rw-r--r-- | programs/cmd_digest.c | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/programs/cmd_digest.c b/programs/cmd_digest.c new file mode 100644 index 0000000..1a3c769 --- /dev/null +++ b/programs/cmd_digest.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: MIT +/* + * The 'fsverity digest' command + * + * Copyright 2020 Microsoft + * + * Use of this source code is governed by an MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT. + */ + +#include "fsverity.h" + +#include <fcntl.h> +#include <getopt.h> + +static const struct option longopts[] = { + {"hash-alg", required_argument, NULL, OPT_HASH_ALG}, + {"block-size", required_argument, NULL, OPT_BLOCK_SIZE}, + {"salt", required_argument, NULL, OPT_SALT}, + {"compact", no_argument, NULL, OPT_COMPACT}, + {"for-builtin-sig", no_argument, NULL, OPT_FOR_BUILTIN_SIG}, + {NULL, 0, NULL, 0} +}; + +/* + * Compute the fs-verity digest of the given file(s), for offline signing. + */ +int fsverity_cmd_digest(const struct fsverity_command *cmd, + int argc, char *argv[]) +{ + struct filedes file = { .fd = -1 }; + struct libfsverity_merkle_tree_params tree_params = { .version = 1 }; + bool compact = false, for_builtin_sig = false; + int status; + int c; + + while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) { + switch (c) { + case OPT_HASH_ALG: + case OPT_BLOCK_SIZE: + case OPT_SALT: + if (!parse_tree_param(c, optarg, &tree_params)) + goto out_usage; + break; + case OPT_COMPACT: + compact = true; + break; + case OPT_FOR_BUILTIN_SIG: + for_builtin_sig = true; + break; + default: + goto out_usage; + } + } + + argv += optind; + argc -= optind; + + if (argc < 1) + goto out_usage; + + for (int i = 0; i < argc; i++) { + struct fsverity_formatted_digest *d = NULL; + struct libfsverity_digest *digest = NULL; + char digest_hex[FS_VERITY_MAX_DIGEST_SIZE * 2 + + sizeof(*d) * 2 + 1]; + + if (!open_file(&file, argv[i], O_RDONLY, 0)) + goto out_err; + + if (!get_file_size(&file, &tree_params.file_size)) + goto out_err; + + if (libfsverity_compute_digest(&file, read_callback, + &tree_params, &digest) != 0) { + error_msg("failed to compute digest"); + goto out_err; + } + + ASSERT(digest->digest_size <= FS_VERITY_MAX_DIGEST_SIZE); + + if (for_builtin_sig) { + /* + * Format the digest for use with the built-in signature + * support. + */ + d = xzalloc(sizeof(*d) + digest->digest_size); + memcpy(d->magic, "FSVerity", 8); + d->digest_algorithm = + cpu_to_le16(digest->digest_algorithm); + d->digest_size = cpu_to_le16(digest->digest_size); + memcpy(d->digest, digest->digest, digest->digest_size); + + bin2hex((const u8 *)d, sizeof(*d) + digest->digest_size, + digest_hex); + } else { + bin2hex(digest->digest, digest->digest_size, + digest_hex); + } + + if (compact) + printf("%s\n", digest_hex); + else if (for_builtin_sig) + printf("%s %s\n", digest_hex, argv[i]); + else + printf("%s:%s %s\n", + libfsverity_get_hash_name(digest->digest_algorithm), + digest_hex, argv[i]); + + filedes_close(&file); + free(digest); + free(d); + } + status = 0; +out: + destroy_tree_params(&tree_params); + return status; + +out_err: + filedes_close(&file); + status = 1; + goto out; + +out_usage: + usage(cmd, stderr); + status = 2; + goto out; +} |