blob: fd9f4deb035052ff547053b229035c79d771f3d9 [file] [log] [blame]
// 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},
{"out-merkle-tree", required_argument, NULL, OPT_OUT_MERKLE_TREE},
{"out-descriptor", required_argument, NULL, OPT_OUT_DESCRIPTOR},
{"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:
case OPT_OUT_MERKLE_TREE:
case OPT_OUT_DESCRIPTOR:
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:
if (!destroy_tree_params(&tree_params) && status == 0)
status = 1;
return status;
out_err:
filedes_close(&file);
status = 1;
goto out;
out_usage:
usage(cmd, stderr);
status = 2;
goto out;
}