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 
help_and_quit(const char * prog)36 static void help_and_quit(const char *prog)
37 {
38 	printf(usage, prog, prog, prog);
39 }
40 
parse_hex(uint8_t * val,const char * str)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 
parse_digest_or_die(uint8_t * buf,int len,const char * str)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 
print_digest(const uint8_t * buf,int len)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 
do_pcr(int argc,char * argv[])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