• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: MIT
2 /*
3  * The 'fsverity sign' command
4  *
5  * Copyright 2018 Google LLC
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 
write_signature(const char * filename,const u8 * sig,u32 sig_size)17 static bool write_signature(const char *filename, const u8 *sig, u32 sig_size)
18 {
19 	struct filedes file;
20 	bool ok;
21 
22 	if (!open_file(&file, filename, O_WRONLY|O_CREAT|O_TRUNC, 0644))
23 		return false;
24 	ok = full_write(&file, sig, sig_size);
25 	ok &= filedes_close(&file);
26 	return ok;
27 }
28 
29 static const struct option longopts[] = {
30 	{"hash-alg",	required_argument, NULL, OPT_HASH_ALG},
31 	{"block-size",	required_argument, NULL, OPT_BLOCK_SIZE},
32 	{"salt",	required_argument, NULL, OPT_SALT},
33 	{"key",		required_argument, NULL, OPT_KEY},
34 	{"cert",	required_argument, NULL, OPT_CERT},
35 	{NULL, 0, NULL, 0}
36 };
37 
38 /* Sign a file for fs-verity by computing its digest, then signing it. */
fsverity_cmd_sign(const struct fsverity_command * cmd,int argc,char * argv[])39 int fsverity_cmd_sign(const struct fsverity_command *cmd,
40 		      int argc, char *argv[])
41 {
42 	struct filedes file = { .fd = -1 };
43 	struct libfsverity_merkle_tree_params tree_params = { .version = 1 };
44 	struct libfsverity_signature_params sig_params = {};
45 	struct libfsverity_digest *digest = NULL;
46 	char digest_hex[FS_VERITY_MAX_DIGEST_SIZE * 2 + 1];
47 	u8 *sig = NULL;
48 	size_t sig_size;
49 	int status;
50 	int c;
51 
52 	while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
53 		switch (c) {
54 		case OPT_HASH_ALG:
55 		case OPT_BLOCK_SIZE:
56 		case OPT_SALT:
57 			if (!parse_tree_param(c, optarg, &tree_params))
58 				goto out_usage;
59 			break;
60 		case OPT_KEY:
61 			if (sig_params.keyfile != NULL) {
62 				error_msg("--key can only be specified once");
63 				goto out_usage;
64 			}
65 			sig_params.keyfile = optarg;
66 			break;
67 		case OPT_CERT:
68 			if (sig_params.certfile != NULL) {
69 				error_msg("--cert can only be specified once");
70 				goto out_usage;
71 			}
72 			sig_params.certfile = optarg;
73 			break;
74 		default:
75 			goto out_usage;
76 		}
77 	}
78 
79 	argv += optind;
80 	argc -= optind;
81 
82 	if (argc != 2)
83 		goto out_usage;
84 
85 	if (sig_params.keyfile == NULL) {
86 		error_msg("Missing --key argument");
87 		goto out_usage;
88 	}
89 	if (sig_params.certfile == NULL)
90 		sig_params.certfile = sig_params.keyfile;
91 
92 	if (!open_file(&file, argv[0], O_RDONLY, 0))
93 		goto out_err;
94 
95 	if (!get_file_size(&file, &tree_params.file_size))
96 		goto out_err;
97 
98 	if (libfsverity_compute_digest(&file, read_callback,
99 				       &tree_params, &digest) != 0) {
100 		error_msg("failed to compute digest");
101 		goto out_err;
102 	}
103 
104 	if (libfsverity_sign_digest(digest, &sig_params,
105 				    &sig, &sig_size) != 0) {
106 		error_msg("failed to sign digest");
107 		goto out_err;
108 	}
109 
110 	if (!write_signature(argv[1], sig, sig_size))
111 		goto out_err;
112 
113 	ASSERT(digest->digest_size <= FS_VERITY_MAX_DIGEST_SIZE);
114 	bin2hex(digest->digest, digest->digest_size, digest_hex);
115 	printf("Signed file '%s' (%s:%s)\n", argv[0],
116 	       libfsverity_get_hash_name(digest->digest_algorithm), digest_hex);
117 	status = 0;
118 out:
119 	filedes_close(&file);
120 	destroy_tree_params(&tree_params);
121 	free(digest);
122 	free(sig);
123 	return status;
124 
125 out_err:
126 	status = 1;
127 	goto out;
128 
129 out_usage:
130 	usage(cmd, stderr);
131 	status = 2;
132 	goto out;
133 }
134