• 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 	{"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