Home | History | Annotate | Download | only in futility
      1 /*
      2  * Copyright 2014 The Chromium OS Authors. All rights reserved.
      3  * Use of this source code is governed by a BSD-style license that can be
      4  * found in the LICENSE file.
      5  */
      6 
      7 #include <ctype.h>
      8 #include <getopt.h>
      9 #include <stdint.h>
     10 #include <stdio.h>
     11 #include <string.h>
     12 
     13 #include "futility.h"
     14 
     15 static const char usage[] = "\n"
     16 	"Usage:  " MYNAME " %s [OPTIONS] DIGEST [...]\n"
     17 	"\n"
     18 	"This simulates a TPM PCR extension, to determine the expected output\n"
     19 	"\n"
     20 	"Each DIGEST arg should be a hex string (spaces optional) of the\n"
     21 	"appropriate length. The PCR is extended with each digest in turn\n"
     22 	"and the new value displayed.\n"
     23 	"\n"
     24 	"Options:\n"
     25 	"  -i      Initialize the PCR with the first DIGEST argument\n"
     26 	"            (the default is to start with all zeros)\n"
     27 	"  -2      Use sha256 DIGESTS (the default is sha1)\n"
     28 	"\n"
     29 	"Examples:\n"
     30 	"\n"
     31 	"  " MYNAME " %s b52791126f96a21a8ba4d511c6f25a1c1eb6dc9e\n"
     32 	"  " MYNAME " %s "
     33 	"'b5 27 91 12 6f 96 a2 1a 8b a4 d5 11 c6 f2 5a 1c 1e b6 dc 9e'\n"
     34 	"\n";
     35 
     36 static void help_and_quit(const char *prog)
     37 {
     38 	printf(usage, prog, prog, prog);
     39 }
     40 
     41 static int parse_hex(uint8_t *val, const char *str)
     42 {
     43 	uint8_t v = 0;
     44 	char c;
     45 	int digit;
     46 
     47 	for (digit = 0; digit < 2; digit++) {
     48 		c = *str;
     49 		if (!c)
     50 			return 0;
     51 		if (!isxdigit(c))
     52 			return 0;
     53 		c = tolower(c);
     54 		if (c >= '0' && c <= '9')
     55 			v += c - '0';
     56 		else
     57 			v += 10 + c - 'a';
     58 		if (!digit)
     59 			v <<= 4;
     60 		str++;
     61 	}
     62 
     63 	*val = v;
     64 	return 1;
     65 }
     66 
     67 static void parse_digest_or_die(uint8_t *buf, int len, const char *str)
     68 {
     69 	const char *s = str;
     70 	int i;
     71 
     72 	for (i = 0; i < len; i++) {
     73 		/* skip whitespace */
     74 		while (*s && isspace(*s))
     75 			s++;
     76 		if (!*s)
     77 			break;
     78 		if (!parse_hex(buf, s))
     79 			break;
     80 
     81 		/* on to the next byte */
     82 		s += 2;
     83 		buf++;
     84 	}
     85 
     86 	if (i != len) {
     87 		fprintf(stderr, "Invalid DIGEST \"%s\"\n", str);
     88 		exit(1);
     89 	}
     90 }
     91 
     92 static void print_digest(const uint8_t *buf, int len)
     93 {
     94 	int i;
     95 	for (i = 0; i < len; i++)
     96 		printf("%02x", buf[i]);
     97 }
     98 
     99 
    100 static int do_pcr(int argc, char *argv[])
    101 {
    102 	uint8_t accum[SHA256_DIGEST_SIZE * 2];
    103 	uint8_t pcr[SHA256_DIGEST_SIZE];
    104 	int digest_alg = SHA1_DIGEST_ALGORITHM;
    105 	int digest_size = SHA1_DIGEST_SIZE;
    106 	int opt_init = 0;
    107 	int errorcnt = 0;
    108 	uint8_t *digest;
    109 	int i;
    110 
    111 	opterr = 0;		/* quiet, you */
    112 	while ((i = getopt(argc, argv, ":i2")) != -1) {
    113 		switch (i) {
    114 		case 'i':
    115 			opt_init = 1;
    116 			break;
    117 		case '2':
    118 			digest_alg = SHA256_DIGEST_ALGORITHM;
    119 			digest_size = SHA256_DIGEST_SIZE;
    120 			break;
    121 		case '?':
    122 			if (optopt)
    123 				fprintf(stderr, "Unrecognized option: -%c\n",
    124 					optopt);
    125 			else
    126 				fprintf(stderr, "Unrecognized option\n");
    127 			errorcnt++;
    128 			break;
    129 		case ':':
    130 			fprintf(stderr, "Missing argument to -%c\n", optopt);
    131 			errorcnt++;
    132 			break;
    133 		default:
    134 			DIE;
    135 		}
    136 	}
    137 
    138 	if (errorcnt) {
    139 		help_and_quit(argv[0]);
    140 		return 1;
    141 	}
    142 
    143 	if (argc - optind < 1 + opt_init) {
    144 		fprintf(stderr, "You must extend at least one DIGEST\n");
    145 		help_and_quit(argv[0]);
    146 		return 1;
    147 	}
    148 
    149 	memset(pcr, 0, sizeof(pcr));
    150 
    151 	if (opt_init) {
    152 		parse_digest_or_die(pcr, digest_size, argv[optind]);
    153 		optind++;
    154 	}
    155 
    156 	printf("PCR: ");
    157 	print_digest(pcr, digest_size);
    158 	printf("\n");
    159 
    160 	for (i = optind; i < argc; i++) {
    161 		memcpy(accum, pcr, sizeof(pcr));
    162 		parse_digest_or_die(accum + digest_size, digest_size, argv[i]);
    163 
    164 		printf("   + ");
    165 		print_digest(accum + digest_size, digest_size);
    166 		printf("\n");
    167 
    168 		digest = DigestBuf(accum, digest_size * 2, digest_alg);
    169 		if (!digest) {
    170 			fprintf(stderr, "Error computing digest!\n");
    171 			return 1;
    172 		}
    173 		memcpy(pcr, digest, digest_size);
    174 		free(digest);
    175 
    176 		printf("PCR: ");
    177 		print_digest(pcr, digest_size);
    178 		printf("\n");
    179 	}
    180 
    181 	return 0;
    182 }
    183 
    184 DECLARE_FUTIL_COMMAND(pcr, do_pcr,
    185 		      VBOOT_VERSION_ALL,
    186 		      "Simulate a TPM PCR extension operation",
    187 		      help_and_quit);
    188