/* * Copyright 2014 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include #include #include #include #include #include "2sysincludes.h" #include "2common.h" #include "2sha.h" #include "futility.h" static const char usage[] = "\n" "Usage: " MYNAME " %s [OPTIONS] DIGEST [...]\n" "\n" "This simulates a TPM PCR extension, to determine the expected output\n" "\n" "Each DIGEST arg should be a hex string (spaces optional) of the\n" "appropriate length. The PCR is extended with each digest in turn\n" "and the new value displayed.\n" "\n" "Options:\n" " -i Initialize the PCR with the first DIGEST argument\n" " (the default is to start with all zeros)\n" " -2 Use sha256 DIGESTS (the default is sha1)\n" "\n" "Examples:\n" "\n" " " MYNAME " %s b52791126f96a21a8ba4d511c6f25a1c1eb6dc9e\n" " " MYNAME " %s " "'b5 27 91 12 6f 96 a2 1a 8b a4 d5 11 c6 f2 5a 1c 1e b6 dc 9e'\n" "\n"; static void print_help(int argc, char *argv[]) { printf(usage, argv[0], argv[0], argv[0]); } static int parse_hex(uint8_t *val, const char *str) { uint8_t v = 0; char c; int digit; for (digit = 0; digit < 2; digit++) { c = *str; if (!c) return 0; if (!isxdigit(c)) return 0; c = tolower(c); if (c >= '0' && c <= '9') v += c - '0'; else v += 10 + c - 'a'; if (!digit) v <<= 4; str++; } *val = v; return 1; } static void parse_digest_or_die(uint8_t *buf, int len, const char *str) { const char *s = str; int i; for (i = 0; i < len; i++) { /* skip whitespace */ while (*s && isspace(*s)) s++; if (!*s) break; if (!parse_hex(buf, s)) break; /* on to the next byte */ s += 2; buf++; } if (i != len) { fprintf(stderr, "Invalid DIGEST \"%s\"\n", str); exit(1); } } static void print_digest(const uint8_t *buf, int len) { int i; for (i = 0; i < len; i++) printf("%02x", buf[i]); } enum { OPT_HELP = 1000, }; static const struct option long_opts[] = { {"help", 0, 0, OPT_HELP}, {NULL, 0, 0, 0} }; static int do_pcr(int argc, char *argv[]) { uint8_t accum[VB2_MAX_DIGEST_SIZE * 2]; uint8_t pcr[VB2_MAX_DIGEST_SIZE]; int digest_alg = VB2_HASH_SHA1; int digest_size; int opt_init = 0; int errorcnt = 0; int i; opterr = 0; /* quiet, you */ while ((i = getopt_long(argc, argv, ":i2", long_opts, NULL)) != -1) { switch (i) { case 'i': opt_init = 1; break; case '2': digest_alg = VB2_HASH_SHA256; break; case OPT_HELP: print_help(argc, argv); return !!errorcnt; case '?': if (optopt) fprintf(stderr, "Unrecognized option: -%c\n", optopt); else fprintf(stderr, "Unrecognized option\n"); errorcnt++; break; case ':': fprintf(stderr, "Missing argument to -%c\n", optopt); errorcnt++; break; default: FATAL("Unrecognized getopt output: %d\n", i); } } if (errorcnt) { print_help(argc, argv); return 1; } if (argc - optind < 1 + opt_init) { fprintf(stderr, "You must extend at least one DIGEST\n"); print_help(argc, argv); return 1; } memset(pcr, 0, sizeof(pcr)); digest_size = vb2_digest_size(digest_alg); if (!digest_size) { fprintf(stderr, "Error determining digest size!\n"); return 1; } if (opt_init) { parse_digest_or_die(pcr, digest_size, argv[optind]); optind++; } printf("PCR: "); print_digest(pcr, digest_size); printf("\n"); for (i = optind; i < argc; i++) { memcpy(accum, pcr, sizeof(pcr)); parse_digest_or_die(accum + digest_size, digest_size, argv[i]); printf(" + "); print_digest(accum + digest_size, digest_size); printf("\n"); if (VB2_SUCCESS != vb2_digest_buffer(accum, digest_size * 2, digest_alg, pcr, digest_size)) { fprintf(stderr, "Error computing digest!\n"); return 1; } printf("PCR: "); print_digest(pcr, digest_size); printf("\n"); } return 0; } DECLARE_FUTIL_COMMAND(pcr, do_pcr, VBOOT_VERSION_ALL, "Simulate a TPM PCR extension operation");