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