• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 	{"out-merkle-tree",     required_argument, NULL, OPT_OUT_MERKLE_TREE},
22 	{"out-descriptor",      required_argument, NULL, OPT_OUT_DESCRIPTOR},
23 	{"compact",		no_argument,	   NULL, OPT_COMPACT},
24 	{"for-builtin-sig",	no_argument,	   NULL, OPT_FOR_BUILTIN_SIG},
25 	{NULL, 0, NULL, 0}
26 };
27 
28 /*
29  * Compute the fs-verity digest of the given file(s), for offline signing.
30  */
fsverity_cmd_digest(const struct fsverity_command * cmd,int argc,char * argv[])31 int fsverity_cmd_digest(const struct fsverity_command *cmd,
32 		      int argc, char *argv[])
33 {
34 	struct filedes file = { .fd = -1 };
35 	struct libfsverity_merkle_tree_params tree_params = { .version = 1 };
36 	bool compact = false, for_builtin_sig = false;
37 	int status;
38 	int c;
39 
40 	while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
41 		switch (c) {
42 		case OPT_HASH_ALG:
43 		case OPT_BLOCK_SIZE:
44 		case OPT_SALT:
45 		case OPT_OUT_MERKLE_TREE:
46 		case OPT_OUT_DESCRIPTOR:
47 			if (!parse_tree_param(c, optarg, &tree_params))
48 				goto out_usage;
49 			break;
50 		case OPT_COMPACT:
51 			compact = true;
52 			break;
53 		case OPT_FOR_BUILTIN_SIG:
54 			for_builtin_sig = true;
55 			break;
56 		default:
57 			goto out_usage;
58 		}
59 	}
60 
61 	argv += optind;
62 	argc -= optind;
63 
64 	if (argc < 1)
65 		goto out_usage;
66 
67 	for (int i = 0; i < argc; i++) {
68 		struct fsverity_formatted_digest *d = NULL;
69 		struct libfsverity_digest *digest = NULL;
70 		char digest_hex[FS_VERITY_MAX_DIGEST_SIZE * 2 +
71 				sizeof(*d) * 2 + 1];
72 
73 		if (!open_file(&file, argv[i], O_RDONLY, 0))
74 			goto out_err;
75 
76 		if (!get_file_size(&file, &tree_params.file_size))
77 			goto out_err;
78 
79 		if (libfsverity_compute_digest(&file, read_callback,
80 					       &tree_params, &digest) != 0) {
81 			error_msg("failed to compute digest");
82 			goto out_err;
83 		}
84 
85 		ASSERT(digest->digest_size <= FS_VERITY_MAX_DIGEST_SIZE);
86 
87 		if (for_builtin_sig) {
88 			/*
89 			 * Format the digest for use with the built-in signature
90 			 * support.
91 			 */
92 			d = xzalloc(sizeof(*d) + digest->digest_size);
93 			memcpy(d->magic, "FSVerity", 8);
94 			d->digest_algorithm =
95 				cpu_to_le16(digest->digest_algorithm);
96 			d->digest_size = cpu_to_le16(digest->digest_size);
97 			memcpy(d->digest, digest->digest, digest->digest_size);
98 
99 			bin2hex((const u8 *)d, sizeof(*d) + digest->digest_size,
100 				digest_hex);
101 		} else {
102 			bin2hex(digest->digest, digest->digest_size,
103 				digest_hex);
104 		}
105 
106 		if (compact)
107 			printf("%s\n", digest_hex);
108 		else if (for_builtin_sig)
109 			printf("%s %s\n", digest_hex, argv[i]);
110 		else
111 			printf("%s:%s %s\n",
112 			       libfsverity_get_hash_name(digest->digest_algorithm),
113 			       digest_hex, argv[i]);
114 
115 		filedes_close(&file);
116 		free(digest);
117 		free(d);
118 	}
119 	status = 0;
120 out:
121 	if (!destroy_tree_params(&tree_params) && status == 0)
122 		status = 1;
123 	return status;
124 
125 out_err:
126 	filedes_close(&file);
127 	status = 1;
128 	goto out;
129 
130 out_usage:
131 	usage(cmd, stderr);
132 	status = 2;
133 	goto out;
134 }
135