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