blob: 898e25525abbbc270f719344c82503605f77f95e [file] [log] [blame]
Kees Cookf0605cb2012-02-29 16:09:14 -08001/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Luigi Semenzatoe72291c2010-08-10 09:46:09 -07002 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 *
5 * TPM command utility. Runs simple TPM commands. Mostly useful when physical
6 * presence has not been locked.
Luigi Semenzatoa8cba992010-09-21 14:12:15 -07007 *
8 * The exit code is 0 for success, the TPM error code for TPM errors, and 255
9 * for other errors.
Luigi Semenzatoe72291c2010-08-10 09:46:09 -070010 */
11
12#include <stdio.h>
13#include <string.h>
14#include <syslog.h>
15
16#include "tlcl.h"
17#include "tpm_error_messages.h"
Luigi Semenzatoc91e2392010-08-17 14:31:52 -070018#include "tss_constants.h"
Luigi Semenzatoe72291c2010-08-10 09:46:09 -070019
Luigi Semenzatoa8cba992010-09-21 14:12:15 -070020#define OTHER_ERROR 255
21
Luigi Semenzatoe72291c2010-08-10 09:46:09 -070022typedef struct command_record {
23 const char* name;
24 const char* abbr;
25 const char* description;
26 uint32_t (*handler)(void);
27} command_record;
28
Luigi Semenzatoc91e2392010-08-17 14:31:52 -070029/* Set in main, consumed by handler functions below. We use global variables
30 * so we can also choose to call Tlcl*() functions directly; they don't take
31 * argv/argc.
32 */
33int nargs;
34char** args;
35
36/* Converts a string in the form 0x[0-9a-f]+ to a 32-bit value. Returns 0 for
37 * success, non-zero for failure.
38 */
39int HexStringToUint32(const char* string, uint32_t* value) {
40 char tail[1];
41 /* strtoul is not as good because it overflows silently */
42 char* format = strncmp(string, "0x", 2) ? "%8x%s" : "0x%8x%s";
43 int n = sscanf(string, format, value, tail);
44 return n != 1;
45}
46
47/* Converts a string in the form [0-9a-f]+ to an 8-bit value. Returns 0 for
48 * success, non-zero for failure.
49 */
50int HexStringToUint8(const char* string, uint8_t* value) {
51 char* end;
52 uint32_t large_value = strtoul(string, &end, 16);
53 if (*end != '\0' || large_value > 0xff) {
54 return 1;
55 }
56 *value = large_value;
57 return 0;
58}
59
60/* TPM error check and reporting. Returns 0 if |result| is 0 (TPM_SUCCESS).
61 * Otherwise looks up a TPM error in the error table and prints the error if
62 * found.
63 */
64uint32_t ErrorCheck(uint32_t result, const char* cmd) {
65 if (result == 0) {
66 return 0;
67 } else {
68 int i;
69 int n = sizeof(tpm_error_table) / sizeof(tpm_error_table[0]);
70 fprintf(stderr, "command \"%s\" failed with code 0x%x\n", cmd, result);
71 for (i = 0; i < n; i++) {
72 if (tpm_error_table[i].code == result) {
73 fprintf(stderr, "%s\n%s\n", tpm_error_table[i].name,
74 tpm_error_table[i].description);
Luigi Semenzatoa8cba992010-09-21 14:12:15 -070075 return result;
Luigi Semenzatoc91e2392010-08-17 14:31:52 -070076 }
77 }
78 fprintf(stderr, "the TPM error code is unknown to this program\n");
Luigi Semenzatoa8cba992010-09-21 14:12:15 -070079 return result;
Luigi Semenzatoc91e2392010-08-17 14:31:52 -070080 }
81}
82
Luigi Semenzatoe72291c2010-08-10 09:46:09 -070083/* Handler functions. These wouldn't exist if C had closures.
84 */
Luigi Semenzatoe72291c2010-08-10 09:46:09 -070085static uint32_t HandlerGetFlags(void) {
86 uint8_t disabled;
87 uint8_t deactivated;
88 uint8_t nvlocked;
89 uint32_t result = TlclGetFlags(&disabled, &deactivated, &nvlocked);
90 if (result == 0) {
91 printf("disabled: %d\ndeactivated: %d\nnvlocked: %d\n",
92 disabled, deactivated, nvlocked);
93 }
94 return result;
95}
96
97static uint32_t HandlerActivate(void) {
98 return TlclSetDeactivated(0);
99}
100
101static uint32_t HandlerDeactivate(void) {
102 return TlclSetDeactivated(1);
103}
104
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700105static uint32_t HandlerDefineSpace(void) {
106 uint32_t index, size, perm;
107 if (nargs != 5) {
108 fprintf(stderr, "usage: tpmc def <index> <size> <perm>\n");
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700109 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700110 }
111 if (HexStringToUint32(args[2], &index) != 0 ||
112 HexStringToUint32(args[3], &size) != 0 ||
113 HexStringToUint32(args[4], &perm) != 0) {
114 fprintf(stderr, "<index>, <size>, and <perm> must be "
115 "32-bit hex (0x[0-9a-f]+)\n");
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700116 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700117 }
118 return TlclDefineSpace(index, perm, size);
119}
120
121static uint32_t HandlerWrite(void) {
122 uint32_t index, size;
123 uint8_t value[TPM_MAX_COMMAND_SIZE];
124 char** byteargs;
125 int i;
126 if (nargs < 3) {
127 fprintf(stderr, "usage: tpmc write <index> [<byte0> <byte1> ...]\n");
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700128 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700129 }
130 if (HexStringToUint32(args[2], &index) != 0) {
131 fprintf(stderr, "<index> must be 32-bit hex (0x[0-9a-f]+)\n");
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700132 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700133 }
134 size = nargs - 3;
135 if (size > sizeof(value)) {
136 fprintf(stderr, "byte array too large\n");
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700137 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700138 }
139
140 byteargs = args + 3;
141 for (i = 0; i < size; i++) {
142 if (HexStringToUint8(byteargs[i], &value[i]) != 0) {
143 fprintf(stderr, "invalid byte %s, should be [0-9a-f][0-9a-f]?\n",
144 byteargs[i]);
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700145 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700146 }
147 }
148
149 if (size == 0) {
150 if (index == TPM_NV_INDEX_LOCK) {
151 fprintf(stderr, "This would set the nvLocked bit. "
152 "Use \"tpmc setnv\" instead.\n");
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700153 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700154 }
155 printf("warning: zero-length write\n");
156 } else {
157 printf("writing %d byte%s\n", size, size > 1 ? "s" : "");
158 }
159
160 return TlclWrite(index, value, size);
161}
162
Kees Cook946370d2012-01-09 14:17:40 -0800163static uint32_t HandlerPCRRead(void) {
164 uint32_t index;
165 uint8_t value[TPM_PCR_DIGEST];
166 uint32_t result;
167 int i;
168 if (nargs != 3) {
169 fprintf(stderr, "usage: tpmc pcrread <index>\n");
170 exit(OTHER_ERROR);
171 }
172 if (HexStringToUint32(args[2], &index) != 0) {
173 fprintf(stderr, "<index> must be 32-bit hex (0x[0-9a-f]+)\n");
174 exit(OTHER_ERROR);
175 }
176 result = TlclPCRRead(index, value, sizeof(value));
177 if (result == 0) {
178 for (i = 0; i < TPM_PCR_DIGEST; i++) {
179 printf("%02x", value[i]);
180 }
181 printf("\n");
182 }
183 return result;
184}
185
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700186static uint32_t HandlerRead(void) {
187 uint32_t index, size;
188 uint8_t value[4096];
189 uint32_t result;
190 int i;
191 if (nargs != 4) {
192 fprintf(stderr, "usage: tpmc read <index> <size>\n");
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700193 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700194 }
195 if (HexStringToUint32(args[2], &index) != 0 ||
196 HexStringToUint32(args[3], &size) != 0) {
197 fprintf(stderr, "<index> and <size> must be 32-bit hex (0x[0-9a-f]+)\n");
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700198 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700199 }
200 if (size > sizeof(value)) {
201 fprintf(stderr, "size of read (0x%x) is too big\n", size);
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700202 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700203 }
204 result = TlclRead(index, value, size);
205 if (result == 0 && size > 0) {
206 for (i = 0; i < size - 1; i++) {
207 printf("%x ", value[i]);
208 }
209 printf("%x\n", value[i]);
210 }
211 return result;
212}
213
214static uint32_t HandlerGetPermissions(void) {
215 uint32_t index, permissions, result;
216 if (nargs != 3) {
217 fprintf(stderr, "usage: tpmc getp <index>\n");
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700218 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700219 }
220 if (HexStringToUint32(args[2], &index) != 0) {
221 fprintf(stderr, "<index> must be 32-bit hex (0x[0-9a-f]+)\n");
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700222 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700223 }
224 result = TlclGetPermissions(index, &permissions);
225 if (result == 0) {
226 printf("space 0x%x has permissions 0x%x\n", index, permissions);
227 }
228 return result;
229}
230
Kees Cook8b6da262012-06-07 13:48:26 -0700231static uint32_t HandlerGetOwnership(void) {
232 uint8_t owned = 0;
233 uint32_t result;
234 if (nargs != 2) {
235 fprintf(stderr, "usage: tpmc getownership\n");
236 exit(OTHER_ERROR);
237 }
238 result = TlclGetOwnership(&owned);
239 if (result == 0) {
240 printf("Owned: %s\n", owned ? "yes" : "no");
241 }
242 return result;
243}
244
Kees Cookf0605cb2012-02-29 16:09:14 -0800245static uint32_t HandlerGetRandom(void) {
246 uint32_t length, size;
247 uint8_t* bytes;
248 uint32_t result;
249 int i;
250 if (nargs != 3) {
251 fprintf(stderr, "usage: tpmc getrandom <size>\n");
252 exit(OTHER_ERROR);
253 }
254 if (HexStringToUint32(args[2], &length) != 0) {
255 fprintf(stderr, "<size> must be 32-bit hex (0x[0-9a-f]+)\n");
256 exit(OTHER_ERROR);
257 }
258 bytes = calloc(1, length);
259 if (bytes == NULL) {
260 perror("calloc");
261 exit(OTHER_ERROR);
262 }
263 result = TlclGetRandom(bytes, length, &size);
264 if (result == 0 && size > 0) {
265 for (i = 0; i < size; i++) {
266 printf("%02x", bytes[i]);
267 }
268 printf("\n");
269 }
270 free(bytes);
271 return result;
272}
273
Luigi Semenzato5896b962010-08-25 07:16:03 -0700274static uint32_t HandlerGetPermanentFlags(void) {
275 TPM_PERMANENT_FLAGS pflags;
276 uint32_t result = TlclGetPermanentFlags(&pflags);
277 if (result == 0) {
278#define P(name) printf("%s %d\n", #name, pflags.name)
279 P(disable);
280 P(ownership);
281 P(deactivated);
282 P(readPubek);
283 P(disableOwnerClear);
284 P(allowMaintenance);
285 P(physicalPresenceLifetimeLock);
286 P(physicalPresenceHWEnable);
287 P(physicalPresenceCMDEnable);
288 P(CEKPUsed);
289 P(TPMpost);
290 P(TPMpostLock);
291 P(FIPS);
292 P(Operator);
293 P(enableRevokeEK);
294 P(nvLocked);
295 P(readSRKPub);
296 P(tpmEstablished);
297 P(maintenanceDone);
298 P(disableFullDALogicInfo);
299#undef P
300 }
301 return result;
302}
303
304static uint32_t HandlerGetSTClearFlags(void) {
305 TPM_STCLEAR_FLAGS vflags;
306 uint32_t result = TlclGetSTClearFlags(&vflags);
307 if (result == 0) {
308#define P(name) printf("%s %d\n", #name, vflags.name)
309 P(deactivated);
310 P(disableForceClear);
311 P(physicalPresence);
312 P(physicalPresenceLock);
313 P(bGlobalLock);
314#undef P
315 }
316 return result;
317}
318
319
Luigi Semenzato3428b4b2013-01-11 15:50:39 -0800320static uint32_t HandlerSendRaw(void) {
321 uint8_t request[4096];
322 uint8_t response[4096];
323 uint32_t result;
324 int size;
325 int i;
326 if (nargs == 2) {
327 fprintf(stderr, "usage: tpmc sendraw <hex byte 0> ... <hex byte N>\n");
328 exit(OTHER_ERROR);
329 }
330 for (i = 0; i < nargs - 2 && i < sizeof(request); i++) {
331 if (HexStringToUint8(args[2 + i], &request[i]) != 0) {
332 fprintf(stderr, "bad byte value \"%s\"\n", args[2 + i]);
333 exit(OTHER_ERROR);
334 }
335 }
336 size = TlclPacketSize(request);
337 if (size != i) {
338 fprintf(stderr, "bad request: size field is %d, but packet has %d bytes\n",
339 size, i);
340 exit(OTHER_ERROR);
341 }
342 bzero(response, sizeof(response));
343 result = TlclSendReceive(request, response, sizeof(response));
344 if (result != 0) {
345 fprintf(stderr, "request failed with code %d\n", result);
346 }
347 size = TlclPacketSize(response);
348 if (size < 10 || size > sizeof(response)) {
349 fprintf(stderr, "unexpected response size %d\n", size);
350 exit(OTHER_ERROR);
351 }
352 for (i = 0; i < size; i++) {
353 printf("0x%02x ", response[i]);
354 if (i == size - 1 || (i + 1) % 8 == 0) {
355 printf("\n");
356 }
357 }
358 return result;
359}
360
361
Luigi Semenzatoe72291c2010-08-10 09:46:09 -0700362/* Table of TPM commands.
363 */
364command_record command_table[] = {
365 { "getflags", "getf", "read and print the value of selected flags",
366 HandlerGetFlags },
367 { "startup", "sta", "issue a Startup command", TlclStartup },
368 { "selftestfull", "test", "issue a SelfTestFull command", TlclSelfTestFull },
369 { "continueselftest", "ctest", "issue a ContinueSelfTest command",
370 TlclContinueSelfTest },
371 { "assertphysicalpresence", "ppon", "assert Physical Presence",
372 TlclAssertPhysicalPresence },
Luigi Semenzato1d83dd12010-08-30 10:23:43 -0700373 { "physicalpresencecmdenable", "ppcmd", "turn on software PP",
374 TlclPhysicalPresenceCMDEnable },
Luigi Semenzatoe72291c2010-08-10 09:46:09 -0700375 { "enable", "ena", "enable the TPM (needs PP)", TlclSetEnable },
376 { "disable", "dis", "disable the TPM (needs PP)", TlclClearEnable },
377 { "activate", "act", "activate the TPM (needs PP, maybe reboot)",
378 HandlerActivate },
379 { "deactivate", "deact", "deactivate the TPM (needs PP, maybe reboot)",
380 HandlerDeactivate },
Luigi Semenzato56cec582010-08-10 15:09:37 -0700381 { "clear", "clr", "clear the TPM owner (needs PP)", TlclForceClear },
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700382 { "setnvlocked", "setnv", "set the nvLocked flag permanently (IRREVERSIBLE!)",
383 TlclSetNvLocked },
Gaurav Shahac6d5602011-07-20 18:10:10 -0700384 { "lockphysicalpresence", "pplock", "lock (turn off) PP until reboot",
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700385 TlclLockPhysicalPresence },
386 { "setbgloballock", "block", "set the bGlobalLock until reboot",
387 TlclSetGlobalLock },
388 { "definespace", "def", "define a space (def <index> <size> <perm>)",
389 HandlerDefineSpace },
390 { "write", "write", "write to a space (write <index> [<byte0> <byte1> ...])",
391 HandlerWrite },
392 { "read", "read", "read from a space (read <index> <size>)",
393 HandlerRead },
Kees Cook946370d2012-01-09 14:17:40 -0800394 { "pcrread", "pcr", "read from a PCR (pcrread <index>)",
395 HandlerPCRRead },
Kees Cook8b6da262012-06-07 13:48:26 -0700396 { "getownership", "geto", "print state of TPM ownership",
397 HandlerGetOwnership },
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700398 { "getpermissions", "getp", "print space permissions (getp <index>)",
399 HandlerGetPermissions },
Luigi Semenzato5896b962010-08-25 07:16:03 -0700400 { "getpermanentflags", "getpf", "print all permanent flags",
401 HandlerGetPermanentFlags },
Kees Cookf0605cb2012-02-29 16:09:14 -0800402 { "getrandom", "rand", "read bytes from RNG (rand <size>)",
403 HandlerGetRandom },
Luigi Semenzato5896b962010-08-25 07:16:03 -0700404 { "getstclearflags", "getvf", "print all volatile (ST_CLEAR) flags",
405 HandlerGetSTClearFlags },
Luigi Semenzatod903cc82010-10-27 09:42:51 -0700406 { "resume", "res", "execute TPM_Startup(ST_STATE)", TlclResume },
Luigi Semenzato54992f92011-03-16 10:56:48 -0700407 { "savestate", "save", "execute TPM_SaveState", TlclSaveState },
Luigi Semenzato3428b4b2013-01-11 15:50:39 -0800408 { "sendraw", "raw", "send a raw request and print raw response",
409 HandlerSendRaw },
Luigi Semenzatoe72291c2010-08-10 09:46:09 -0700410};
411
412static int n_commands = sizeof(command_table) / sizeof(command_table[0]);
413
414int main(int argc, char* argv[]) {
415 if (argc < 2) {
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700416 fprintf(stderr, "usage: %s <TPM command> [args]\n or: %s help\n",
Luigi Semenzatoe72291c2010-08-10 09:46:09 -0700417 argv[0], argv[0]);
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700418 return OTHER_ERROR;
Luigi Semenzatoe72291c2010-08-10 09:46:09 -0700419 } else {
420 command_record* c;
421 const char* cmd = argv[1];
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700422 nargs = argc;
423 args = argv;
Luigi Semenzatoe72291c2010-08-10 09:46:09 -0700424
425 if (strcmp(cmd, "help") == 0) {
Luigi Semenzato1d83dd12010-08-30 10:23:43 -0700426 printf("%26s %7s %s\n\n", "command", "abbr.", "description");
Luigi Semenzatoe72291c2010-08-10 09:46:09 -0700427 for (c = command_table; c < command_table + n_commands; c++) {
Luigi Semenzato1d83dd12010-08-30 10:23:43 -0700428 printf("%26s %7s %s\n", c->name, c->abbr, c->description);
Luigi Semenzatoe72291c2010-08-10 09:46:09 -0700429 }
430 return 0;
431 }
432
433 TlclLibInit();
434
435 for (c = command_table; c < command_table + n_commands; c++) {
436 if (strcmp(cmd, c->name) == 0 || strcmp(cmd, c->abbr) == 0) {
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700437 return ErrorCheck(c->handler(), cmd);
Luigi Semenzatoe72291c2010-08-10 09:46:09 -0700438 }
439 }
440
441 /* No command matched. */
442 fprintf(stderr, "%s: unknown command: %s\n", argv[0], cmd);
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700443 return OTHER_ERROR;
Luigi Semenzatoe72291c2010-08-10 09:46:09 -0700444 }
445}