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