diff options
Diffstat (limited to 'futility/cmd_pcr.c')
-rw-r--r-- | futility/cmd_pcr.c | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/futility/cmd_pcr.c b/futility/cmd_pcr.c new file mode 100644 index 00000000..9149ccfe --- /dev/null +++ b/futility/cmd_pcr.c @@ -0,0 +1,186 @@ +/* + * 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 <ctype.h> +#include <getopt.h> +#include <stdint.h> +#include <stdio.h> +#include <string.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 help_and_quit(const char *prog) +{ + printf(usage, prog, prog, prog); +} + +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]); +} + + +static int do_pcr(int argc, char *argv[]) +{ + uint8_t accum[SHA256_DIGEST_SIZE * 2]; + uint8_t pcr[SHA256_DIGEST_SIZE]; + int digest_alg = SHA1_DIGEST_ALGORITHM; + int digest_size = SHA1_DIGEST_SIZE; + int opt_init = 0; + int errorcnt = 0; + uint8_t *digest; + int i; + + opterr = 0; /* quiet, you */ + while ((i = getopt(argc, argv, ":i2")) != -1) { + switch (i) { + case 'i': + opt_init = 1; + break; + case '2': + digest_alg = SHA256_DIGEST_ALGORITHM; + digest_size = SHA256_DIGEST_SIZE; + break; + 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: + DIE; + } + } + + if (errorcnt) { + help_and_quit(argv[0]); + return 1; + } + + if (argc - optind < 1 + opt_init) { + fprintf(stderr, "You must extend at least one DIGEST\n"); + help_and_quit(argv[0]); + return 1; + } + + memset(pcr, 0, sizeof(pcr)); + + 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"); + + digest = DigestBuf(accum, digest_size * 2, digest_alg); + if (!digest) { + fprintf(stderr, "Error computing digest!\n"); + return 1; + } + memcpy(pcr, digest, digest_size); + free(digest); + + printf("PCR: "); + print_digest(pcr, digest_size); + printf("\n"); + } + + return 0; +} + +DECLARE_FUTIL_COMMAND(pcr, do_pcr, + "Simulate a TPM PCR extension operation", + help_and_quit); |