• 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 	{"key",		    required_argument, NULL, OPT_KEY},
31 	{"cert",	    required_argument, NULL, OPT_CERT},
32 	{"pkcs11-engine",   required_argument, NULL, OPT_PKCS11_ENGINE},
33 	{"pkcs11-module",   required_argument, NULL, OPT_PKCS11_MODULE},
34 	{"pkcs11-keyid",    required_argument, NULL, OPT_PKCS11_KEYID},
35 	{"hash-alg",	    required_argument, NULL, OPT_HASH_ALG},
36 	{"block-size",	    required_argument, NULL, OPT_BLOCK_SIZE},
37 	{"salt",	    required_argument, NULL, OPT_SALT},
38 	{"out-merkle-tree", required_argument, NULL, OPT_OUT_MERKLE_TREE},
39 	{"out-descriptor",  required_argument, NULL, OPT_OUT_DESCRIPTOR},
40 	{NULL, 0, NULL, 0}
41 };
42 
43 /* 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[])44 int fsverity_cmd_sign(const struct fsverity_command *cmd,
45 		      int argc, char *argv[])
46 {
47 	struct filedes file = { .fd = -1 };
48 	struct libfsverity_merkle_tree_params tree_params = { .version = 1 };
49 	struct libfsverity_signature_params sig_params = {};
50 	struct libfsverity_digest *digest = NULL;
51 	char digest_hex[FS_VERITY_MAX_DIGEST_SIZE * 2 + 1];
52 	u8 *sig = NULL;
53 	size_t sig_size;
54 	int status;
55 	int c;
56 
57 	while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
58 		switch (c) {
59 		case OPT_KEY:
60 			if (sig_params.keyfile != NULL) {
61 				error_msg("--key can only be specified once");
62 				goto out_usage;
63 			}
64 			sig_params.keyfile = optarg;
65 			break;
66 		case OPT_CERT:
67 			if (sig_params.certfile != NULL) {
68 				error_msg("--cert can only be specified once");
69 				goto out_usage;
70 			}
71 			sig_params.certfile = optarg;
72 			break;
73 		case OPT_PKCS11_ENGINE:
74 			if (sig_params.pkcs11_engine != NULL) {
75 				error_msg("--pkcs11-engine can only be specified once");
76 				goto out_usage;
77 			}
78 			sig_params.pkcs11_engine = optarg;
79 			break;
80 		case OPT_PKCS11_MODULE:
81 			if (sig_params.pkcs11_module != NULL) {
82 				error_msg("--pkcs11-module can only be specified once");
83 				goto out_usage;
84 			}
85 			sig_params.pkcs11_module = optarg;
86 			break;
87 		case OPT_PKCS11_KEYID:
88 			if (sig_params.pkcs11_keyid != NULL) {
89 				error_msg("--pkcs11-keyid can only be specified once");
90 				goto out_usage;
91 			}
92 			sig_params.pkcs11_keyid = optarg;
93 			break;
94 		case OPT_HASH_ALG:
95 		case OPT_BLOCK_SIZE:
96 		case OPT_SALT:
97 		case OPT_OUT_MERKLE_TREE:
98 		case OPT_OUT_DESCRIPTOR:
99 			if (!parse_tree_param(c, optarg, &tree_params))
100 				goto out_usage;
101 			break;
102 		default:
103 			goto out_usage;
104 		}
105 	}
106 
107 	argv += optind;
108 	argc -= optind;
109 
110 	if (argc != 2)
111 		goto out_usage;
112 
113 	if (sig_params.certfile == NULL)
114 		sig_params.certfile = sig_params.keyfile;
115 
116 	if (!open_file(&file, argv[0], O_RDONLY, 0))
117 		goto out_err;
118 
119 	if (!get_file_size(&file, &tree_params.file_size))
120 		goto out_err;
121 
122 	if (libfsverity_compute_digest(&file, read_callback,
123 				       &tree_params, &digest) != 0) {
124 		error_msg("failed to compute digest");
125 		goto out_err;
126 	}
127 
128 	if (libfsverity_sign_digest(digest, &sig_params,
129 				    &sig, &sig_size) != 0) {
130 		error_msg("failed to sign digest");
131 		goto out_err;
132 	}
133 
134 	if (!write_signature(argv[1], sig, sig_size))
135 		goto out_err;
136 
137 	ASSERT(digest->digest_size <= FS_VERITY_MAX_DIGEST_SIZE);
138 	bin2hex(digest->digest, digest->digest_size, digest_hex);
139 	printf("Signed file '%s' (%s:%s)\n", argv[0],
140 	       libfsverity_get_hash_name(digest->digest_algorithm), digest_hex);
141 	status = 0;
142 out:
143 	filedes_close(&file);
144 	if (!destroy_tree_params(&tree_params) && status == 0)
145 		status = 1;
146 	free(digest);
147 	free(sig);
148 	return status;
149 
150 out_err:
151 	status = 1;
152 	goto out;
153 
154 out_usage:
155 	usage(cmd, stderr);
156 	status = 2;
157 	goto out;
158 }
159