xref: /aosp_15_r20/external/fsverity-utils/programs/cmd_sign.c (revision b13c0e4024008a1f948ee8189745cb3371f4ac04)
1*b13c0e40SEric Biggers // SPDX-License-Identifier: MIT
2*b13c0e40SEric Biggers /*
3*b13c0e40SEric Biggers  * The 'fsverity sign' command
4*b13c0e40SEric Biggers  *
5*b13c0e40SEric Biggers  * Copyright 2018 Google LLC
6*b13c0e40SEric Biggers  *
7*b13c0e40SEric Biggers  * Use of this source code is governed by an MIT-style
8*b13c0e40SEric Biggers  * license that can be found in the LICENSE file or at
9*b13c0e40SEric Biggers  * https://opensource.org/licenses/MIT.
10*b13c0e40SEric Biggers  */
11*b13c0e40SEric Biggers 
12*b13c0e40SEric Biggers #include "fsverity.h"
13*b13c0e40SEric Biggers 
14*b13c0e40SEric Biggers #include <fcntl.h>
15*b13c0e40SEric Biggers #include <getopt.h>
16*b13c0e40SEric Biggers 
write_signature(const char * filename,const u8 * sig,u32 sig_size)17*b13c0e40SEric Biggers static bool write_signature(const char *filename, const u8 *sig, u32 sig_size)
18*b13c0e40SEric Biggers {
19*b13c0e40SEric Biggers 	struct filedes file;
20*b13c0e40SEric Biggers 	bool ok;
21*b13c0e40SEric Biggers 
22*b13c0e40SEric Biggers 	if (!open_file(&file, filename, O_WRONLY|O_CREAT|O_TRUNC, 0644))
23*b13c0e40SEric Biggers 		return false;
24*b13c0e40SEric Biggers 	ok = full_write(&file, sig, sig_size);
25*b13c0e40SEric Biggers 	ok &= filedes_close(&file);
26*b13c0e40SEric Biggers 	return ok;
27*b13c0e40SEric Biggers }
28*b13c0e40SEric Biggers 
29*b13c0e40SEric Biggers static const struct option longopts[] = {
30*b13c0e40SEric Biggers 	{"key",		    required_argument, NULL, OPT_KEY},
31*b13c0e40SEric Biggers 	{"cert",	    required_argument, NULL, OPT_CERT},
32*b13c0e40SEric Biggers 	{"pkcs11-engine",   required_argument, NULL, OPT_PKCS11_ENGINE},
33*b13c0e40SEric Biggers 	{"pkcs11-module",   required_argument, NULL, OPT_PKCS11_MODULE},
34*b13c0e40SEric Biggers 	{"pkcs11-keyid",    required_argument, NULL, OPT_PKCS11_KEYID},
35*b13c0e40SEric Biggers 	{"hash-alg",	    required_argument, NULL, OPT_HASH_ALG},
36*b13c0e40SEric Biggers 	{"block-size",	    required_argument, NULL, OPT_BLOCK_SIZE},
37*b13c0e40SEric Biggers 	{"salt",	    required_argument, NULL, OPT_SALT},
38*b13c0e40SEric Biggers 	{"out-merkle-tree", required_argument, NULL, OPT_OUT_MERKLE_TREE},
39*b13c0e40SEric Biggers 	{"out-descriptor",  required_argument, NULL, OPT_OUT_DESCRIPTOR},
40*b13c0e40SEric Biggers 	{NULL, 0, NULL, 0}
41*b13c0e40SEric Biggers };
42*b13c0e40SEric Biggers 
43*b13c0e40SEric Biggers /* 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*b13c0e40SEric Biggers int fsverity_cmd_sign(const struct fsverity_command *cmd,
45*b13c0e40SEric Biggers 		      int argc, char *argv[])
46*b13c0e40SEric Biggers {
47*b13c0e40SEric Biggers 	struct filedes file = { .fd = -1 };
48*b13c0e40SEric Biggers 	struct libfsverity_merkle_tree_params tree_params = { .version = 1 };
49*b13c0e40SEric Biggers 	struct libfsverity_signature_params sig_params = {};
50*b13c0e40SEric Biggers 	struct libfsverity_digest *digest = NULL;
51*b13c0e40SEric Biggers 	char digest_hex[FS_VERITY_MAX_DIGEST_SIZE * 2 + 1];
52*b13c0e40SEric Biggers 	u8 *sig = NULL;
53*b13c0e40SEric Biggers 	size_t sig_size;
54*b13c0e40SEric Biggers 	int status;
55*b13c0e40SEric Biggers 	int c;
56*b13c0e40SEric Biggers 
57*b13c0e40SEric Biggers 	while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
58*b13c0e40SEric Biggers 		switch (c) {
59*b13c0e40SEric Biggers 		case OPT_KEY:
60*b13c0e40SEric Biggers 			if (sig_params.keyfile != NULL) {
61*b13c0e40SEric Biggers 				error_msg("--key can only be specified once");
62*b13c0e40SEric Biggers 				goto out_usage;
63*b13c0e40SEric Biggers 			}
64*b13c0e40SEric Biggers 			sig_params.keyfile = optarg;
65*b13c0e40SEric Biggers 			break;
66*b13c0e40SEric Biggers 		case OPT_CERT:
67*b13c0e40SEric Biggers 			if (sig_params.certfile != NULL) {
68*b13c0e40SEric Biggers 				error_msg("--cert can only be specified once");
69*b13c0e40SEric Biggers 				goto out_usage;
70*b13c0e40SEric Biggers 			}
71*b13c0e40SEric Biggers 			sig_params.certfile = optarg;
72*b13c0e40SEric Biggers 			break;
73*b13c0e40SEric Biggers 		case OPT_PKCS11_ENGINE:
74*b13c0e40SEric Biggers 			if (sig_params.pkcs11_engine != NULL) {
75*b13c0e40SEric Biggers 				error_msg("--pkcs11-engine can only be specified once");
76*b13c0e40SEric Biggers 				goto out_usage;
77*b13c0e40SEric Biggers 			}
78*b13c0e40SEric Biggers 			sig_params.pkcs11_engine = optarg;
79*b13c0e40SEric Biggers 			break;
80*b13c0e40SEric Biggers 		case OPT_PKCS11_MODULE:
81*b13c0e40SEric Biggers 			if (sig_params.pkcs11_module != NULL) {
82*b13c0e40SEric Biggers 				error_msg("--pkcs11-module can only be specified once");
83*b13c0e40SEric Biggers 				goto out_usage;
84*b13c0e40SEric Biggers 			}
85*b13c0e40SEric Biggers 			sig_params.pkcs11_module = optarg;
86*b13c0e40SEric Biggers 			break;
87*b13c0e40SEric Biggers 		case OPT_PKCS11_KEYID:
88*b13c0e40SEric Biggers 			if (sig_params.pkcs11_keyid != NULL) {
89*b13c0e40SEric Biggers 				error_msg("--pkcs11-keyid can only be specified once");
90*b13c0e40SEric Biggers 				goto out_usage;
91*b13c0e40SEric Biggers 			}
92*b13c0e40SEric Biggers 			sig_params.pkcs11_keyid = optarg;
93*b13c0e40SEric Biggers 			break;
94*b13c0e40SEric Biggers 		case OPT_HASH_ALG:
95*b13c0e40SEric Biggers 		case OPT_BLOCK_SIZE:
96*b13c0e40SEric Biggers 		case OPT_SALT:
97*b13c0e40SEric Biggers 		case OPT_OUT_MERKLE_TREE:
98*b13c0e40SEric Biggers 		case OPT_OUT_DESCRIPTOR:
99*b13c0e40SEric Biggers 			if (!parse_tree_param(c, optarg, &tree_params))
100*b13c0e40SEric Biggers 				goto out_usage;
101*b13c0e40SEric Biggers 			break;
102*b13c0e40SEric Biggers 		default:
103*b13c0e40SEric Biggers 			goto out_usage;
104*b13c0e40SEric Biggers 		}
105*b13c0e40SEric Biggers 	}
106*b13c0e40SEric Biggers 
107*b13c0e40SEric Biggers 	argv += optind;
108*b13c0e40SEric Biggers 	argc -= optind;
109*b13c0e40SEric Biggers 
110*b13c0e40SEric Biggers 	if (argc != 2)
111*b13c0e40SEric Biggers 		goto out_usage;
112*b13c0e40SEric Biggers 
113*b13c0e40SEric Biggers 	if (sig_params.certfile == NULL)
114*b13c0e40SEric Biggers 		sig_params.certfile = sig_params.keyfile;
115*b13c0e40SEric Biggers 
116*b13c0e40SEric Biggers 	if (!open_file(&file, argv[0], O_RDONLY, 0))
117*b13c0e40SEric Biggers 		goto out_err;
118*b13c0e40SEric Biggers 
119*b13c0e40SEric Biggers 	if (!get_file_size(&file, &tree_params.file_size))
120*b13c0e40SEric Biggers 		goto out_err;
121*b13c0e40SEric Biggers 
122*b13c0e40SEric Biggers 	if (libfsverity_compute_digest(&file, read_callback,
123*b13c0e40SEric Biggers 				       &tree_params, &digest) != 0) {
124*b13c0e40SEric Biggers 		error_msg("failed to compute digest");
125*b13c0e40SEric Biggers 		goto out_err;
126*b13c0e40SEric Biggers 	}
127*b13c0e40SEric Biggers 
128*b13c0e40SEric Biggers 	if (libfsverity_sign_digest(digest, &sig_params,
129*b13c0e40SEric Biggers 				    &sig, &sig_size) != 0) {
130*b13c0e40SEric Biggers 		error_msg("failed to sign digest");
131*b13c0e40SEric Biggers 		goto out_err;
132*b13c0e40SEric Biggers 	}
133*b13c0e40SEric Biggers 
134*b13c0e40SEric Biggers 	if (!write_signature(argv[1], sig, sig_size))
135*b13c0e40SEric Biggers 		goto out_err;
136*b13c0e40SEric Biggers 
137*b13c0e40SEric Biggers 	ASSERT(digest->digest_size <= FS_VERITY_MAX_DIGEST_SIZE);
138*b13c0e40SEric Biggers 	bin2hex(digest->digest, digest->digest_size, digest_hex);
139*b13c0e40SEric Biggers 	printf("Signed file '%s' (%s:%s)\n", argv[0],
140*b13c0e40SEric Biggers 	       libfsverity_get_hash_name(digest->digest_algorithm), digest_hex);
141*b13c0e40SEric Biggers 	status = 0;
142*b13c0e40SEric Biggers out:
143*b13c0e40SEric Biggers 	filedes_close(&file);
144*b13c0e40SEric Biggers 	if (!destroy_tree_params(&tree_params) && status == 0)
145*b13c0e40SEric Biggers 		status = 1;
146*b13c0e40SEric Biggers 	free(digest);
147*b13c0e40SEric Biggers 	free(sig);
148*b13c0e40SEric Biggers 	return status;
149*b13c0e40SEric Biggers 
150*b13c0e40SEric Biggers out_err:
151*b13c0e40SEric Biggers 	status = 1;
152*b13c0e40SEric Biggers 	goto out;
153*b13c0e40SEric Biggers 
154*b13c0e40SEric Biggers out_usage:
155*b13c0e40SEric Biggers 	usage(cmd, stderr);
156*b13c0e40SEric Biggers 	status = 2;
157*b13c0e40SEric Biggers 	goto out;
158*b13c0e40SEric Biggers }
159