Eric Biggers | 431c67b | 2018-06-27 15:01:06 -0700 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0+ |
Eric Biggers | 1e64b3d | 2018-03-21 17:53:20 -0700 | [diff] [blame] | 2 | /* |
| 3 | * fs-verity userspace tool |
| 4 | * |
Eric Biggers | 8387ad3 | 2018-08-21 12:37:56 -0700 | [diff] [blame] | 5 | * Copyright (C) 2018 Google LLC |
Eric Biggers | 431c67b | 2018-06-27 15:01:06 -0700 | [diff] [blame] | 6 | * |
Eric Biggers | 8387ad3 | 2018-08-21 12:37:56 -0700 | [diff] [blame] | 7 | * Written by Eric Biggers. |
Eric Biggers | 1e64b3d | 2018-03-21 17:53:20 -0700 | [diff] [blame] | 8 | */ |
| 9 | |
Eric Biggers | c67b06a | 2019-05-20 17:03:46 -0700 | [diff] [blame] | 10 | #include <limits.h> |
Eric Biggers | 1e64b3d | 2018-03-21 17:53:20 -0700 | [diff] [blame] | 11 | #include <stdlib.h> |
| 12 | #include <string.h> |
Eric Biggers | c67b06a | 2019-05-20 17:03:46 -0700 | [diff] [blame] | 13 | #include <unistd.h> |
Eric Biggers | 1e64b3d | 2018-03-21 17:53:20 -0700 | [diff] [blame] | 14 | |
Eric Biggers | 431c67b | 2018-06-27 15:01:06 -0700 | [diff] [blame] | 15 | #include "commands.h" |
| 16 | #include "hash_algs.h" |
Eric Biggers | 1e64b3d | 2018-03-21 17:53:20 -0700 | [diff] [blame] | 17 | |
Eric Biggers | 431c67b | 2018-06-27 15:01:06 -0700 | [diff] [blame] | 18 | static const struct fsverity_command { |
Eric Biggers | 1e64b3d | 2018-03-21 17:53:20 -0700 | [diff] [blame] | 19 | const char *name; |
Eric Biggers | 431c67b | 2018-06-27 15:01:06 -0700 | [diff] [blame] | 20 | int (*func)(const struct fsverity_command *cmd, int argc, char *argv[]); |
| 21 | const char *short_desc; |
| 22 | const char *usage_str; |
| 23 | } fsverity_commands[] = { |
| 24 | { |
| 25 | .name = "enable", |
| 26 | .func = fsverity_cmd_enable, |
Eric Biggers | c67b06a | 2019-05-20 17:03:46 -0700 | [diff] [blame] | 27 | .short_desc = "Enable fs-verity on a file", |
Eric Biggers | 431c67b | 2018-06-27 15:01:06 -0700 | [diff] [blame] | 28 | .usage_str = |
| 29 | " fsverity enable FILE\n" |
Eric Biggers | c67b06a | 2019-05-20 17:03:46 -0700 | [diff] [blame] | 30 | " [--hash-alg=HASH_ALG] [--block-size=BLOCK_SIZE] [--salt=SALT]\n" |
| 31 | " [--signature=SIGFILE]\n" |
Eric Biggers | 431c67b | 2018-06-27 15:01:06 -0700 | [diff] [blame] | 32 | }, { |
Eric Biggers | 25b5945 | 2018-07-27 10:47:02 -0700 | [diff] [blame] | 33 | .name = "measure", |
| 34 | .func = fsverity_cmd_measure, |
| 35 | .short_desc = |
Eric Biggers | c67b06a | 2019-05-20 17:03:46 -0700 | [diff] [blame] | 36 | "Display the measurement of the given verity file(s)", |
Eric Biggers | 25b5945 | 2018-07-27 10:47:02 -0700 | [diff] [blame] | 37 | .usage_str = |
| 38 | " fsverity measure FILE...\n" |
| 39 | }, { |
Eric Biggers | c67b06a | 2019-05-20 17:03:46 -0700 | [diff] [blame] | 40 | .name = "sign", |
| 41 | .func = fsverity_cmd_sign, |
| 42 | .short_desc = "Sign a file for fs-verity", |
Eric Biggers | 431c67b | 2018-06-27 15:01:06 -0700 | [diff] [blame] | 43 | .usage_str = |
Eric Biggers | c67b06a | 2019-05-20 17:03:46 -0700 | [diff] [blame] | 44 | " fsverity sign FILE OUT_SIGFILE --key=KEYFILE\n" |
| 45 | " [--hash-alg=HASH_ALG] [--block-size=BLOCK_SIZE] [--salt=SALT]\n" |
| 46 | " [--cert=CERTFILE]\n" |
Eric Biggers | 25b5945 | 2018-07-27 10:47:02 -0700 | [diff] [blame] | 47 | } |
Eric Biggers | 1e64b3d | 2018-03-21 17:53:20 -0700 | [diff] [blame] | 48 | }; |
| 49 | |
Eric Biggers | 431c67b | 2018-06-27 15:01:06 -0700 | [diff] [blame] | 50 | static void usage_all(FILE *fp) |
Eric Biggers | 1e64b3d | 2018-03-21 17:53:20 -0700 | [diff] [blame] | 51 | { |
Eric Biggers | 431c67b | 2018-06-27 15:01:06 -0700 | [diff] [blame] | 52 | int i; |
Eric Biggers | 1e64b3d | 2018-03-21 17:53:20 -0700 | [diff] [blame] | 53 | |
Eric Biggers | 431c67b | 2018-06-27 15:01:06 -0700 | [diff] [blame] | 54 | fputs("Usage:\n", fp); |
| 55 | for (i = 0; i < ARRAY_SIZE(fsverity_commands); i++) |
| 56 | fprintf(fp, " %s:\n%s\n", fsverity_commands[i].short_desc, |
| 57 | fsverity_commands[i].usage_str); |
| 58 | fputs( |
| 59 | " Standard options:\n" |
| 60 | " fsverity --help\n" |
| 61 | " fsverity --version\n" |
| 62 | "\n" |
| 63 | "Available hash algorithms: ", fp); |
| 64 | show_all_hash_algs(fp); |
| 65 | fputs("\nSee `man fsverity` for more details.\n", fp); |
Eric Biggers | 1e64b3d | 2018-03-21 17:53:20 -0700 | [diff] [blame] | 66 | } |
| 67 | |
Eric Biggers | 431c67b | 2018-06-27 15:01:06 -0700 | [diff] [blame] | 68 | static void usage_cmd(const struct fsverity_command *cmd, FILE *fp) |
Eric Biggers | 1e64b3d | 2018-03-21 17:53:20 -0700 | [diff] [blame] | 69 | { |
Eric Biggers | 431c67b | 2018-06-27 15:01:06 -0700 | [diff] [blame] | 70 | fprintf(fp, "Usage:\n%s", cmd->usage_str); |
| 71 | } |
Eric Biggers | 1e64b3d | 2018-03-21 17:53:20 -0700 | [diff] [blame] | 72 | |
Eric Biggers | 431c67b | 2018-06-27 15:01:06 -0700 | [diff] [blame] | 73 | void usage(const struct fsverity_command *cmd, FILE *fp) |
| 74 | { |
| 75 | if (cmd) |
| 76 | usage_cmd(cmd, fp); |
| 77 | else |
| 78 | usage_all(fp); |
| 79 | } |
| 80 | |
| 81 | #define PACKAGE_VERSION "v0.0-alpha" |
| 82 | #define PACKAGE_BUGREPORT "linux-fscrypt@vger.kernel.org" |
| 83 | |
| 84 | static void show_version(void) |
| 85 | { |
| 86 | static const char * const str = |
| 87 | "fsverity " PACKAGE_VERSION "\n" |
Eric Biggers | 8387ad3 | 2018-08-21 12:37:56 -0700 | [diff] [blame] | 88 | "Copyright (C) 2018 Google LLC\n" |
Eric Biggers | 431c67b | 2018-06-27 15:01:06 -0700 | [diff] [blame] | 89 | "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>.\n" |
| 90 | "This is free software: you are free to change and redistribute it.\n" |
| 91 | "There is NO WARRANTY, to the extent permitted by law.\n" |
| 92 | "\n" |
| 93 | "Report bugs to " PACKAGE_BUGREPORT ".\n"; |
| 94 | fputs(str, stdout); |
| 95 | } |
| 96 | |
| 97 | static void handle_common_options(int argc, char *argv[], |
| 98 | const struct fsverity_command *cmd) |
| 99 | { |
| 100 | int i; |
| 101 | |
| 102 | for (i = 1; i < argc; i++) { |
| 103 | const char *arg = argv[i]; |
| 104 | |
| 105 | if (*arg++ != '-') |
| 106 | continue; |
| 107 | if (*arg++ != '-') |
| 108 | continue; |
| 109 | if (!strcmp(arg, "help")) { |
| 110 | usage(cmd, stdout); |
| 111 | exit(0); |
| 112 | } else if (!strcmp(arg, "version")) { |
| 113 | show_version(); |
| 114 | exit(0); |
| 115 | } else if (!*arg) /* reached "--", no more options */ |
| 116 | return; |
Eric Biggers | 1e64b3d | 2018-03-21 17:53:20 -0700 | [diff] [blame] | 117 | } |
Eric Biggers | 431c67b | 2018-06-27 15:01:06 -0700 | [diff] [blame] | 118 | } |
| 119 | |
| 120 | static const struct fsverity_command *find_command(const char *name) |
| 121 | { |
| 122 | int i; |
| 123 | |
| 124 | for (i = 0; i < ARRAY_SIZE(fsverity_commands); i++) |
| 125 | if (!strcmp(name, fsverity_commands[i].name)) |
| 126 | return &fsverity_commands[i]; |
Eric Biggers | 1e64b3d | 2018-03-21 17:53:20 -0700 | [diff] [blame] | 127 | return NULL; |
| 128 | } |
| 129 | |
Eric Biggers | c67b06a | 2019-05-20 17:03:46 -0700 | [diff] [blame] | 130 | bool parse_block_size_option(const char *arg, u32 *size_ptr) |
| 131 | { |
| 132 | char *end; |
| 133 | unsigned long n = strtoul(arg, &end, 10); |
| 134 | |
| 135 | if (*size_ptr != 0) { |
| 136 | error_msg("--block-size can only be specified once"); |
| 137 | return false; |
| 138 | } |
| 139 | |
| 140 | if (n <= 0 || n >= INT_MAX || !is_power_of_2(n) || *end != '\0') { |
| 141 | error_msg("Invalid block size: %s. Must be power of 2", arg); |
| 142 | return false; |
| 143 | } |
| 144 | *size_ptr = n; |
| 145 | return true; |
| 146 | } |
| 147 | |
| 148 | bool parse_salt_option(const char *arg, u8 **salt_ptr, u32 *salt_size_ptr) |
| 149 | { |
| 150 | if (*salt_ptr != NULL) { |
| 151 | error_msg("--salt can only be specified once"); |
| 152 | return false; |
| 153 | } |
| 154 | *salt_size_ptr = strlen(arg) / 2; |
| 155 | *salt_ptr = xmalloc(*salt_size_ptr); |
| 156 | if (!hex2bin(arg, *salt_ptr, *salt_size_ptr)) { |
| 157 | error_msg("salt is not a valid hex string"); |
| 158 | return false; |
| 159 | } |
| 160 | return true; |
| 161 | } |
| 162 | |
| 163 | u32 get_default_block_size(void) |
| 164 | { |
| 165 | long n = sysconf(_SC_PAGESIZE); |
| 166 | |
| 167 | if (n <= 0 || n >= INT_MAX || !is_power_of_2(n)) { |
| 168 | fprintf(stderr, |
| 169 | "Warning: invalid _SC_PAGESIZE (%ld). Assuming 4K blocks.\n", |
| 170 | n); |
| 171 | return 4096; |
| 172 | } |
| 173 | return n; |
| 174 | } |
| 175 | |
Eric Biggers | 431c67b | 2018-06-27 15:01:06 -0700 | [diff] [blame] | 176 | int main(int argc, char *argv[]) |
Eric Biggers | 1e64b3d | 2018-03-21 17:53:20 -0700 | [diff] [blame] | 177 | { |
Eric Biggers | 431c67b | 2018-06-27 15:01:06 -0700 | [diff] [blame] | 178 | const struct fsverity_command *cmd; |
Eric Biggers | 1e64b3d | 2018-03-21 17:53:20 -0700 | [diff] [blame] | 179 | |
Eric Biggers | 431c67b | 2018-06-27 15:01:06 -0700 | [diff] [blame] | 180 | if (argc < 2) { |
| 181 | error_msg("no command specified"); |
| 182 | usage_all(stderr); |
Eric Biggers | 1e64b3d | 2018-03-21 17:53:20 -0700 | [diff] [blame] | 183 | return 2; |
| 184 | } |
| 185 | |
Eric Biggers | 431c67b | 2018-06-27 15:01:06 -0700 | [diff] [blame] | 186 | cmd = find_command(argv[1]); |
| 187 | |
| 188 | handle_common_options(argc, argv, cmd); |
| 189 | |
| 190 | if (!cmd) { |
| 191 | error_msg("unrecognized command: '%s'", argv[1]); |
| 192 | usage_all(stderr); |
| 193 | return 2; |
Eric Biggers | 1e64b3d | 2018-03-21 17:53:20 -0700 | [diff] [blame] | 194 | } |
Eric Biggers | 431c67b | 2018-06-27 15:01:06 -0700 | [diff] [blame] | 195 | return cmd->func(cmd, argc - 1, argv + 1); |
Eric Biggers | 1e64b3d | 2018-03-21 17:53:20 -0700 | [diff] [blame] | 196 | } |