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