1 // SPDX-License-Identifier: MIT
2 /*
3 * The 'fsverity digest' command
4 *
5 * Copyright 2020 Microsoft
6 *
7 * Use of this source code is governed by an MIT-style
8 * license that can be found in the LICENSE file or at
9 * https://opensource.org/licenses/MIT.
10 */
11
12 #include "fsverity.h"
13
14 #include <fcntl.h>
15 #include <getopt.h>
16
17 static const struct option longopts[] = {
18 {"hash-alg", required_argument, NULL, OPT_HASH_ALG},
19 {"block-size", required_argument, NULL, OPT_BLOCK_SIZE},
20 {"salt", required_argument, NULL, OPT_SALT},
21 {"compact", no_argument, NULL, OPT_COMPACT},
22 {"for-builtin-sig", no_argument, NULL, OPT_FOR_BUILTIN_SIG},
23 {NULL, 0, NULL, 0}
24 };
25
26 /*
27 * Compute the fs-verity digest of the given file(s), for offline signing.
28 */
fsverity_cmd_digest(const struct fsverity_command * cmd,int argc,char * argv[])29 int fsverity_cmd_digest(const struct fsverity_command *cmd,
30 int argc, char *argv[])
31 {
32 struct filedes file = { .fd = -1 };
33 struct libfsverity_merkle_tree_params tree_params = { .version = 1 };
34 bool compact = false, for_builtin_sig = false;
35 int status;
36 int c;
37
38 while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
39 switch (c) {
40 case OPT_HASH_ALG:
41 case OPT_BLOCK_SIZE:
42 case OPT_SALT:
43 if (!parse_tree_param(c, optarg, &tree_params))
44 goto out_usage;
45 break;
46 case OPT_COMPACT:
47 compact = true;
48 break;
49 case OPT_FOR_BUILTIN_SIG:
50 for_builtin_sig = true;
51 break;
52 default:
53 goto out_usage;
54 }
55 }
56
57 argv += optind;
58 argc -= optind;
59
60 if (argc < 1)
61 goto out_usage;
62
63 for (int i = 0; i < argc; i++) {
64 struct fsverity_formatted_digest *d = NULL;
65 struct libfsverity_digest *digest = NULL;
66 char digest_hex[FS_VERITY_MAX_DIGEST_SIZE * 2 +
67 sizeof(*d) * 2 + 1];
68
69 if (!open_file(&file, argv[i], O_RDONLY, 0))
70 goto out_err;
71
72 if (!get_file_size(&file, &tree_params.file_size))
73 goto out_err;
74
75 if (libfsverity_compute_digest(&file, read_callback,
76 &tree_params, &digest) != 0) {
77 error_msg("failed to compute digest");
78 goto out_err;
79 }
80
81 ASSERT(digest->digest_size <= FS_VERITY_MAX_DIGEST_SIZE);
82
83 if (for_builtin_sig) {
84 /*
85 * Format the digest for use with the built-in signature
86 * support.
87 */
88 d = xzalloc(sizeof(*d) + digest->digest_size);
89 memcpy(d->magic, "FSVerity", 8);
90 d->digest_algorithm =
91 cpu_to_le16(digest->digest_algorithm);
92 d->digest_size = cpu_to_le16(digest->digest_size);
93 memcpy(d->digest, digest->digest, digest->digest_size);
94
95 bin2hex((const u8 *)d, sizeof(*d) + digest->digest_size,
96 digest_hex);
97 } else {
98 bin2hex(digest->digest, digest->digest_size,
99 digest_hex);
100 }
101
102 if (compact)
103 printf("%s\n", digest_hex);
104 else if (for_builtin_sig)
105 printf("%s %s\n", digest_hex, argv[i]);
106 else
107 printf("%s:%s %s\n",
108 libfsverity_get_hash_name(digest->digest_algorithm),
109 digest_hex, argv[i]);
110
111 filedes_close(&file);
112 free(digest);
113 free(d);
114 }
115 status = 0;
116 out:
117 destroy_tree_params(&tree_params);
118 return status;
119
120 out_err:
121 filedes_close(&file);
122 status = 1;
123 goto out;
124
125 out_usage:
126 usage(cmd, stderr);
127 status = 2;
128 goto out;
129 }
130