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