Fix some strings, fix sb_offset.
[platform/upstream/cryptsetup.git] / src / veritysetup.c
1 /*
2  * veritysetup - setup cryptographic volumes for dm-verity
3  *
4  * Copyright (C) 2012, Red Hat, Inc. All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * version 2 as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19
20 /* TODO:
21  * - init_by_name()
22  * - support device without superblock
23  * - audit alloc errors / error path
24  * - change command names (cryptsetup style)
25  * - extend superblock (UUID)
26  * - warn if block_size > PAGE_SIZE
27  * - configure.in/config.h defaults
28  */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #include <errno.h>
34 #include <string.h>
35 #include <popt.h>
36
37 #include "cryptsetup.h"
38
39 #define PACKAGE_VERITY "veritysetup"
40
41 #define MODE_VERIFY     0
42 #define MODE_CREATE     1
43 #define MODE_ACTIVATE   2
44 #define MODE_DUMP       3
45
46 static int mode = -1;
47 static int use_superblock = 1; /* FIXME: no superblock not supported */
48
49 static const char *dm_device = NULL;
50 static const char *data_device = NULL;
51 static const char *hash_device = NULL;
52 static const char *hash_algorithm = NULL;
53 static const char *root_hash = NULL;
54
55 static int version = 1;
56 static int data_block_size = 4096;
57 static int hash_block_size = 4096;
58 static char *data_blocks_string = NULL;
59 static uint64_t data_blocks = 0;
60 static char *hash_start_string = NULL;
61 static const char *salt_string = NULL;
62 static unsigned salt_size = 32;
63 static uint64_t hash_start = 0;
64
65 static int opt_verbose = 0;
66 static int opt_debug = 0;
67 static int opt_version_mode = 0;
68
69 static int hex_to_bytes(const char *hex, char *result)
70 {
71         char buf[3] = "xx\0", *endp;
72         int i, len;
73
74         len = strlen(hex) / 2;
75         for (i = 0; i < len; i++) {
76                 memcpy(buf, &hex[i * 2], 2);
77                 result[i] = strtoul(buf, &endp, 16);
78                 if (endp != &buf[2])
79                         return -EINVAL;
80         }
81         return i;
82 }
83
84 __attribute__((format(printf, 5, 6)))
85 static void clogger(struct crypt_device *cd, int level, const char *file,
86                    int line, const char *format, ...)
87 {
88         va_list argp;
89         char *target = NULL;
90
91         va_start(argp, format);
92
93         if (vasprintf(&target, format, argp) > 0) {
94                 if (level >= 0) {
95                         crypt_log(cd, level, target);
96 #ifdef CRYPT_DEBUG
97                 } else if (opt_debug)
98                         printf("# %s:%d %s\n", file ?: "?", line, target);
99 #else
100                 } else if (opt_debug)
101                         printf("# %s\n", target);
102 #endif
103         }
104
105         va_end(argp);
106         free(target);
107 }
108
109 static void _log(int level, const char *msg, void *usrptr __attribute__((unused)))
110 {
111         switch(level) {
112
113         case CRYPT_LOG_NORMAL:
114                 fputs(msg, stdout);
115                 break;
116         case CRYPT_LOG_VERBOSE:
117                 if (opt_verbose)
118                         fputs(msg, stdout);
119                 break;
120         case CRYPT_LOG_ERROR:
121                 fputs(msg, stderr);
122                 break;
123         case CRYPT_LOG_DEBUG:
124                 if (opt_debug)
125                         printf("# %s\n", msg);
126                 break;
127         default:
128                 fprintf(stderr, "Internal error on logging class for msg: %s", msg);
129                 break;
130         }
131 }
132
133 static int action_dump(void)
134 {
135         struct crypt_device *cd = NULL;
136         struct crypt_params_verity params = {};
137         int r;
138
139         if ((r = crypt_init(&cd, hash_device)))
140                 return r;
141
142         params.hash_area_offset = hash_start;
143         r = crypt_load(cd, CRYPT_VERITY, &params);
144         if (!r)
145                 crypt_dump(cd);
146         crypt_free(cd);
147         return r;
148 }
149
150 static int action_activate(int verify)
151 {
152         struct crypt_device *cd = NULL;
153         struct crypt_params_verity params = {};
154         uint32_t activate_flags = CRYPT_ACTIVATE_READONLY;
155         char root_hash_bytes[128];
156         int r;
157
158         if ((r = crypt_init(&cd, hash_device)))
159                 goto out;
160
161         if (verify)
162                 params.flags |= CRYPT_VERITY_CHECK_HASH;
163
164         if (use_superblock) {
165                 params.hash_area_offset = hash_start;
166                 r = crypt_load(cd, CRYPT_VERITY, &params);
167         } else {/*
168                 params.hash_name = hash_algorithm;
169                 params.salt = salt_bytes;
170                 params.salt_size = salt_size;
171                 params.data_block_size = data_block_size;
172                 params.hash_block_size = hash_block_size;
173
174                 params.data_size = data_blocks * data_block_size / 512;
175                 params.version = version;
176                 params.flags |= CRYPT_VERITY_NO_HEADER;
177                 r = crypt_load(cd, CRYPT_VERITY, &params);
178                 crypt_format(); */
179                 r = -EINVAL;
180                 goto out;
181         }
182         if (r < 0)
183                 goto out;
184         r = crypt_set_data_device(cd, data_device);
185         if (r < 0)
186                 goto out;
187
188         if (hex_to_bytes(root_hash, root_hash_bytes) !=
189             crypt_get_volume_key_size(cd)) {
190                 r = -EINVAL;
191                 goto out;
192         }
193         r = crypt_activate_by_volume_key(cd, dm_device, root_hash_bytes,
194                                          crypt_get_volume_key_size(cd),
195                                          activate_flags);
196 out:
197         if (!r)
198                 crypt_dump(cd);
199         crypt_free(cd);
200         return r;
201 }
202
203 static int action_create(void)
204 {
205         struct crypt_device *cd = NULL;
206         struct crypt_params_verity params = {};
207         char salt_bytes[512];
208         int r;
209
210         if ((r = crypt_init(&cd, hash_device)))
211                 goto out;
212
213         params.hash_name = hash_algorithm ?: "sha256";
214         params.data_device = data_device;
215
216         if (salt_string) {
217                 if (hex_to_bytes(salt_string, salt_bytes) != salt_size) {
218                         r = -EINVAL;
219                         goto out;
220                 }
221                 params.salt = salt_bytes;
222         }
223
224         params.salt_size = salt_size;
225         params.data_block_size = data_block_size;
226         params.hash_block_size = hash_block_size;
227         params.data_size = data_blocks;
228         params.hash_area_offset = hash_start;
229         params.version = version;
230         params.flags = CRYPT_VERITY_CREATE_HASH;
231         if (!use_superblock)
232                 params.flags |= CRYPT_VERITY_NO_HEADER;
233
234         r = crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, &params);
235         if (!r)
236                 crypt_dump(cd);
237 out:
238         crypt_free(cd);
239         return r;
240 }
241
242 static __attribute__ ((noreturn)) void usage(poptContext popt_context,
243                                              int exitcode, const char *error,
244                                              const char *more)
245 {
246         poptPrintUsage(popt_context, stderr, 0);
247         if (error)
248                 log_err("%s: %s\n", more, error);
249         poptFreeContext(popt_context);
250         exit(exitcode);
251 }
252
253 static void help(poptContext popt_context,
254                  enum poptCallbackReason reason __attribute__((unused)),
255                  struct poptOption *key,
256                  const char *arg __attribute__((unused)),
257                  void *data __attribute__((unused)))
258 {
259         if (key->shortName == '?') {
260                 log_std("%s %s\n", PACKAGE_VERITY, PACKAGE_VERSION);
261                 poptPrintHelp(popt_context, stdout, 0);
262                 exit(EXIT_SUCCESS);
263         } else
264                 usage(popt_context, EXIT_SUCCESS, NULL, NULL);
265 }
266
267 static void _dbg_version_and_cmd(int argc, const char **argv)
268 {
269         int i;
270
271         log_std("# %s %s processing \"", PACKAGE_VERITY, PACKAGE_VERSION);
272         for (i = 0; i < argc; i++) {
273                 if (i)
274                         log_std(" ");
275                 log_std("%s", argv[i]);
276         }
277         log_std("\"\n");
278 }
279
280 int main(int argc, const char **argv)
281 {
282         static struct poptOption popt_help_options[] = {
283                 { NULL,    '\0', POPT_ARG_CALLBACK, help, 0, NULL,                         NULL },
284                 { "help",  '?',  POPT_ARG_NONE,     NULL, 0, N_("Show this help message"), NULL },
285                 { "usage", '\0', POPT_ARG_NONE,     NULL, 0, N_("Display brief usage"),    NULL },
286                 POPT_TABLEEND
287         };
288         static struct poptOption popt_options[] = {
289                 { NULL,                '\0', POPT_ARG_INCLUDE_TABLE, popt_help_options, 0, N_("Help options:"), NULL },
290                 { "version",           '\0', POPT_ARG_NONE, &opt_version_mode,          0, N_("Print package version"), NULL },
291                 { "verbose",            0 /*v*/,  POPT_ARG_NONE, &opt_verbose,               0, N_("Shows more detailed error messages"), NULL },
292                 { "debug",             '\0', POPT_ARG_NONE, &opt_debug,                 0, N_("Show debug messages"), NULL },
293                 { "create",             'c',    POPT_ARG_VAL, &mode, MODE_CREATE, "Create hash", NULL },
294                 { "verify",             'v',    POPT_ARG_VAL, &mode, MODE_VERIFY, "Verify integrity", NULL },
295                 { "activate",           'a',    POPT_ARG_VAL, &mode, MODE_ACTIVATE, "Activate the device", NULL },
296                 { "dump",               'd',    POPT_ARG_VAL, &mode, MODE_DUMP, "Dump the device", NULL },
297                 { "no-superblock",      0,      POPT_ARG_VAL, &use_superblock, 0, "Do not create/use superblock" },
298                 { "format",             0,      POPT_ARG_INT, &version, 0, "Format version (1 - normal format, 0 - original Chromium OS format)", "number" },
299                 { "data-block-size",    0,      POPT_ARG_INT, &data_block_size, 0, "Block size on the data device", "bytes" },
300                 { "hash-block-size",    0,      POPT_ARG_INT, &hash_block_size, 0, "Block size on the hash device", "bytes" },
301                 { "data-blocks",        0,      POPT_ARG_STRING, &data_blocks_string, 0, "The number of blocks in the data file", "blocks" },
302                 { "hash-start",         0,      POPT_ARG_STRING, &hash_start_string, 0, "Starting block on the hash device", "512-byte sectors" },
303                 { "algorithm",          0,      POPT_ARG_STRING, &hash_algorithm, 0, "Hash algorithm (default sha256)", "string" },
304                 { "salt",               0,      POPT_ARG_STRING, &salt_string, 0, "Salt", "hex string" },
305                 POPT_TABLEEND
306         };
307         poptContext popt_context;
308         int r;
309         char *end;
310
311         crypt_set_log_callback(NULL, _log, NULL);
312
313         setlocale(LC_ALL, "");
314         bindtextdomain(PACKAGE, LOCALEDIR);
315         textdomain(PACKAGE);
316
317         popt_context = poptGetContext("verity", argc, argv, popt_options, 0);
318
319         poptSetOtherOptionHelp(popt_context, "[-c|-v|-a|-d] [<device name> if activating] <data device> <hash device> [<root hash> if activating or verifying] [OPTION...]");
320
321         if (argc <= 1) {
322                 poptPrintHelp(popt_context, stdout, 0);
323                 exit(1);
324         }
325
326         r = poptGetNextOpt(popt_context);
327         if (r < -1)
328                 usage(popt_context, EXIT_FAILURE, poptStrerror(r),
329                       poptBadOption(popt_context, POPT_BADOPTION_NOALIAS));
330         if (opt_version_mode) {
331                 log_std("%s %s\n", PACKAGE_VERITY, PACKAGE_VERSION);
332                 poptFreeContext(popt_context);
333                 exit(EXIT_SUCCESS);
334         }
335
336         if (mode < 0)
337                 usage(popt_context, EXIT_FAILURE, _("Unknown action."),
338                       poptGetInvocationName(popt_context));
339
340         if (mode == MODE_ACTIVATE) {
341                 dm_device = poptGetArg(popt_context);
342                 if (!dm_device || !*dm_device)
343                         usage(popt_context, EXIT_FAILURE,
344                               _("Missing activation device name."),
345                               poptGetInvocationName(popt_context));
346         }
347
348         data_device = poptGetArg(popt_context);
349         if (!data_device)
350                 usage(popt_context, EXIT_FAILURE, _("Missing data device name."),
351                       poptGetInvocationName(popt_context));
352
353         hash_device = poptGetArg(popt_context);
354         if (!hash_device)
355                 usage(popt_context, EXIT_FAILURE, _("Missing hash device name."),
356                       poptGetInvocationName(popt_context));
357
358         if (mode == MODE_ACTIVATE || mode == MODE_VERIFY) {
359                 root_hash = poptGetArg(popt_context);
360                 if (!root_hash)
361                 usage(popt_context, EXIT_FAILURE, _("Root hash not specified."),
362                       poptGetInvocationName(popt_context));
363         }
364
365         if (data_blocks_string) {
366                 data_blocks = strtoll(data_blocks_string, &end, 10);
367                 if (!*data_blocks_string || *end)
368                         usage(popt_context, EXIT_FAILURE,
369                               _("Invalid number of data blocks."),
370                               poptGetInvocationName(popt_context));
371         }
372
373         /* hash start */
374         if (hash_start_string) {
375                 hash_start = strtoll(hash_start_string, &end, 10);
376                 if (!*hash_start_string || *end)
377                         usage(popt_context, EXIT_FAILURE,
378                               _("Invalid hash device offset."),
379                               poptGetInvocationName(popt_context));
380                 hash_start *= 512;
381         }
382
383         if (salt_string || !use_superblock) {
384                 if (!salt_string || !strcmp(salt_string, "-"))
385                         salt_string = "";
386                 salt_size = strlen(salt_string) / 2;
387         }
388
389         if (opt_debug) {
390                 opt_verbose = 1;
391                 crypt_set_debug_level(-1);
392                 _dbg_version_and_cmd(argc, argv);
393         }
394
395         switch (mode) {
396                 case MODE_ACTIVATE:
397                         r = action_activate(0);
398                         break;
399                 case MODE_VERIFY:
400                         r = action_activate(1);
401                         break;
402                 case MODE_CREATE:
403                         r = action_create();
404                         break;
405                 case MODE_DUMP:
406                         r = action_dump();
407                         break;
408         }
409
410         poptFreeContext(popt_context);
411         return r;
412 }