1ced56a00Sopenharmony_ci// SPDX-License-Identifier: MIT
2ced56a00Sopenharmony_ci/*
3ced56a00Sopenharmony_ci * The 'fsverity enable' command
4ced56a00Sopenharmony_ci *
5ced56a00Sopenharmony_ci * Copyright 2018 Google LLC
6ced56a00Sopenharmony_ci *
7ced56a00Sopenharmony_ci * Use of this source code is governed by an MIT-style
8ced56a00Sopenharmony_ci * license that can be found in the LICENSE file or at
9ced56a00Sopenharmony_ci * https://opensource.org/licenses/MIT.
10ced56a00Sopenharmony_ci */
11ced56a00Sopenharmony_ci
12ced56a00Sopenharmony_ci#include "fsverity.h"
13ced56a00Sopenharmony_ci
14ced56a00Sopenharmony_ci#include <fcntl.h>
15ced56a00Sopenharmony_ci#include <getopt.h>
16ced56a00Sopenharmony_ci#include <limits.h>
17ced56a00Sopenharmony_ci
18ced56a00Sopenharmony_cistatic bool read_signature(const char *filename, u8 **sig_ret,
19ced56a00Sopenharmony_ci			   u32 *sig_size_ret)
20ced56a00Sopenharmony_ci{
21ced56a00Sopenharmony_ci	struct filedes file = { .fd = -1 };
22ced56a00Sopenharmony_ci	u64 file_size;
23ced56a00Sopenharmony_ci	u8 *sig = NULL;
24ced56a00Sopenharmony_ci	bool ok = false;
25ced56a00Sopenharmony_ci
26ced56a00Sopenharmony_ci	if (!open_file(&file, filename, O_RDONLY, 0))
27ced56a00Sopenharmony_ci		goto out;
28ced56a00Sopenharmony_ci	if (!get_file_size(&file, &file_size))
29ced56a00Sopenharmony_ci		goto out;
30ced56a00Sopenharmony_ci	if (file_size <= 0) {
31ced56a00Sopenharmony_ci		error_msg("signature file '%s' is empty", filename);
32ced56a00Sopenharmony_ci		goto out;
33ced56a00Sopenharmony_ci	}
34ced56a00Sopenharmony_ci	if (file_size > 1000000) {
35ced56a00Sopenharmony_ci		error_msg("signature file '%s' is too large", filename);
36ced56a00Sopenharmony_ci		goto out;
37ced56a00Sopenharmony_ci	}
38ced56a00Sopenharmony_ci	sig = xmalloc(file_size);
39ced56a00Sopenharmony_ci	if (!full_read(&file, sig, file_size))
40ced56a00Sopenharmony_ci		goto out;
41ced56a00Sopenharmony_ci	*sig_ret = sig;
42ced56a00Sopenharmony_ci	*sig_size_ret = file_size;
43ced56a00Sopenharmony_ci	sig = NULL;
44ced56a00Sopenharmony_ci	ok = true;
45ced56a00Sopenharmony_ciout:
46ced56a00Sopenharmony_ci	filedes_close(&file);
47ced56a00Sopenharmony_ci	free(sig);
48ced56a00Sopenharmony_ci	return ok;
49ced56a00Sopenharmony_ci}
50ced56a00Sopenharmony_ci
51ced56a00Sopenharmony_cistatic const struct option longopts[] = {
52ced56a00Sopenharmony_ci	{"hash-alg",	required_argument, NULL, OPT_HASH_ALG},
53ced56a00Sopenharmony_ci	{"block-size",	required_argument, NULL, OPT_BLOCK_SIZE},
54ced56a00Sopenharmony_ci	{"salt",	required_argument, NULL, OPT_SALT},
55ced56a00Sopenharmony_ci	{"signature",	required_argument, NULL, OPT_SIGNATURE},
56ced56a00Sopenharmony_ci	{NULL, 0, NULL, 0}
57ced56a00Sopenharmony_ci};
58ced56a00Sopenharmony_ci
59ced56a00Sopenharmony_ci/* Enable fs-verity on a file. */
60ced56a00Sopenharmony_ciint fsverity_cmd_enable(const struct fsverity_command *cmd,
61ced56a00Sopenharmony_ci			int argc, char *argv[])
62ced56a00Sopenharmony_ci{
63ced56a00Sopenharmony_ci	struct libfsverity_merkle_tree_params tree_params = { .version = 1 };
64ced56a00Sopenharmony_ci	u8 *sig = NULL;
65ced56a00Sopenharmony_ci	u32 sig_size = 0;
66ced56a00Sopenharmony_ci	struct filedes file;
67ced56a00Sopenharmony_ci	int status;
68ced56a00Sopenharmony_ci	int c;
69ced56a00Sopenharmony_ci
70ced56a00Sopenharmony_ci	while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
71ced56a00Sopenharmony_ci		switch (c) {
72ced56a00Sopenharmony_ci		case OPT_HASH_ALG:
73ced56a00Sopenharmony_ci		case OPT_BLOCK_SIZE:
74ced56a00Sopenharmony_ci		case OPT_SALT:
75ced56a00Sopenharmony_ci			if (!parse_tree_param(c, optarg, &tree_params))
76ced56a00Sopenharmony_ci				goto out_usage;
77ced56a00Sopenharmony_ci			break;
78ced56a00Sopenharmony_ci		case OPT_SIGNATURE:
79ced56a00Sopenharmony_ci			if (sig != NULL) {
80ced56a00Sopenharmony_ci				error_msg("--signature can only be specified once");
81ced56a00Sopenharmony_ci				goto out_usage;
82ced56a00Sopenharmony_ci			}
83ced56a00Sopenharmony_ci			if (!read_signature(optarg, &sig, &sig_size))
84ced56a00Sopenharmony_ci				goto out_err;
85ced56a00Sopenharmony_ci			break;
86ced56a00Sopenharmony_ci		default:
87ced56a00Sopenharmony_ci			goto out_usage;
88ced56a00Sopenharmony_ci		}
89ced56a00Sopenharmony_ci	}
90ced56a00Sopenharmony_ci
91ced56a00Sopenharmony_ci	argv += optind;
92ced56a00Sopenharmony_ci	argc -= optind;
93ced56a00Sopenharmony_ci
94ced56a00Sopenharmony_ci	if (argc != 1)
95ced56a00Sopenharmony_ci		goto out_usage;
96ced56a00Sopenharmony_ci
97ced56a00Sopenharmony_ci	if (!open_file(&file, argv[0], O_RDONLY, 0))
98ced56a00Sopenharmony_ci		goto out_err;
99ced56a00Sopenharmony_ci
100ced56a00Sopenharmony_ci	if (libfsverity_enable_with_sig(file.fd, &tree_params, sig, sig_size)) {
101ced56a00Sopenharmony_ci		error_msg_errno("FS_IOC_ENABLE_VERITY failed on '%s'",
102ced56a00Sopenharmony_ci				file.name);
103ced56a00Sopenharmony_ci		filedes_close(&file);
104ced56a00Sopenharmony_ci		goto out_err;
105ced56a00Sopenharmony_ci	}
106ced56a00Sopenharmony_ci	if (!filedes_close(&file))
107ced56a00Sopenharmony_ci		goto out_err;
108ced56a00Sopenharmony_ci
109ced56a00Sopenharmony_ci	status = 0;
110ced56a00Sopenharmony_ciout:
111ced56a00Sopenharmony_ci	destroy_tree_params(&tree_params);
112ced56a00Sopenharmony_ci	free(sig);
113ced56a00Sopenharmony_ci	return status;
114ced56a00Sopenharmony_ci
115ced56a00Sopenharmony_ciout_err:
116ced56a00Sopenharmony_ci	status = 1;
117ced56a00Sopenharmony_ci	goto out;
118ced56a00Sopenharmony_ci
119ced56a00Sopenharmony_ciout_usage:
120ced56a00Sopenharmony_ci	usage(cmd, stderr);
121ced56a00Sopenharmony_ci	status = 2;
122ced56a00Sopenharmony_ci	goto out;
123ced56a00Sopenharmony_ci}
124