| // Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by the GPL v2 license that can |
| // be found in the LICENSE file. |
| // |
| // Driver program for creating verity hash images. |
| #include <stdio.h> |
| #include <stdlib.h> |
| |
| #include "verity/file_hasher.h" |
| #include "verity/logging.h" |
| #include "verity/simple_file/env.h" |
| #include "verity/simple_file/file.h" |
| #include "verity/utils.h" |
| |
| namespace { |
| void print_usage(const char *name) { |
| // We used to advertise more algorithms, but they've never been implemented: |
| // sha512 sha384 sha mdc2 ripemd160 md4 md2 |
| fprintf(stderr, |
| "Usage:\n" |
| " %s <arg>=<value>...\n" |
| "Options:\n" |
| " mode One of 'create' or 'verify'\n" |
| " alg Hash algorithm to use. One of:\n" |
| " sha256 sha224 sha1 md5\n" |
| " payload Path to the image to hash\n" |
| " payload_blocks Size of the image, in blocks (4096 bytes)\n" |
| " hashtree Path to a hash tree to create or read from\n" |
| " root_hexdigest Digest of the root node (in hex) for verification\n" |
| " salt Salt (in hex)\n" |
| "\n", name); |
| } |
| |
| typedef enum { VERITY_NONE = 0, VERITY_CREATE, VERITY_VERIFY } verity_mode_t; |
| |
| static unsigned int parse_blocks(const char *block_s) { |
| return (unsigned int)strtoul(block_s, NULL, 0); |
| } |
| } // namespace |
| |
| static int verity_create(const char *alg, |
| const char *image_path, |
| unsigned int image_blocks, |
| const char *hash_path, |
| const char *salt); |
| |
| void splitarg(char *arg, char **key, char **val) { |
| char *sp = NULL; |
| *key = strtok_r(arg, "=", &sp); |
| *val = strtok_r(NULL, "=", &sp); |
| } |
| |
| int main(int argc, char **argv) { |
| verity_mode_t mode = VERITY_CREATE; |
| const char *alg = NULL; |
| const char *payload = NULL; |
| const char *hashtree = NULL; |
| const char *salt = NULL; |
| unsigned int payload_blocks = 0; |
| int i; |
| char *key, *val; |
| |
| for (i = 1; i < argc; i++) { |
| splitarg(argv[i], &key, &val); |
| if (!key) |
| continue; |
| if (!val) { |
| fprintf(stderr, "missing value: %s\n", key); |
| print_usage(argv[0]); |
| return -1; |
| } |
| if (!strcmp(key, "alg")) |
| alg = val; |
| else if (!strcmp(key, "payload")) |
| payload = val; |
| else if (!strcmp(key, "payload_blocks")) |
| payload_blocks = parse_blocks(val); |
| else if (!strcmp(key, "hashtree")) |
| hashtree = val; |
| else if (!strcmp(key, "root_hexdigest")) |
| // Silently drop root_hexdigest for now... |
| ; |
| else if (!strcmp(key, "mode")) |
| // Silently drop the mode for now... |
| ; |
| else if (!strcmp(key, "salt")) |
| salt = val; |
| else { |
| fprintf(stderr, "bogus key: '%s'\n", key); |
| print_usage(argv[0]); |
| return -1; |
| } |
| } |
| |
| if (!alg || !payload || !hashtree) { |
| fprintf(stderr, "missing data: %s%s%s\n", |
| alg ? "" : "alg ", |
| payload ? "" : "payload ", |
| hashtree ? "" : "hashtree"); |
| print_usage(argv[0]); |
| return -1; |
| } |
| |
| if (mode == VERITY_CREATE) { |
| return verity_create(alg, payload, payload_blocks, hashtree, salt); |
| } else { |
| LOG(FATAL) << "Verification not done yet"; |
| } |
| return -1; |
| } |
| |
| static int verity_create(const char *alg, |
| const char *image_path, |
| unsigned int image_blocks, |
| const char *hash_path, |
| const char *salt) { |
| // Configure files |
| simple_file::Env env; |
| |
| simple_file::File source; |
| LOG_IF(FATAL, !source.Initialize(image_path, O_RDONLY, &env)) |
| << "Failed to open the source file: " << image_path; |
| simple_file::File destination; |
| LOG_IF(FATAL, !destination.Initialize(hash_path, |
| O_CREAT|O_RDWR|O_TRUNC, |
| &env)) |
| << "Failed to open destination file: " << hash_path; |
| |
| // Create the actual worker and create the hash image. |
| verity::FileHasher hasher; |
| LOG_IF(FATAL, !hasher.Initialize(&source, |
| &destination, |
| image_blocks, |
| alg)) |
| << "Failed to initialize hasher"; |
| if (salt) |
| hasher.set_salt(salt); |
| LOG_IF(FATAL, !hasher.Hash()) |
| << "Failed to hash hasher"; |
| LOG_IF(FATAL, !hasher.Store()) |
| << "Failed to store hasher"; |
| hasher.PrintTable(true); |
| return 0; |
| } |