1 /* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
5 * TPM command utility. Runs simple TPM commands. Mostly useful when physical
6 * presence has not been locked.
8 * The exit code is 0 for success, the TPM error code for TPM errors, and 255
19 #include "tpm_error_messages.h"
20 #include "tss_constants.h"
22 #define OTHER_ERROR 255 /* OTHER_ERROR must be the largest uint8_t value. */
25 #define TPM_MODE_SELECT(_, tpm20_ver) tpm20_ver
27 #define TPM_MODE_SELECT(tpm12_ver, _) tpm12_ver
30 #define TPM_MODE_STRING TPM_MODE_SELECT("1.2", "2.0")
31 #define TPM12_NEEDS_PP TPM_MODE_SELECT(" (needs PP)", "")
32 #define TPM12_NEEDS_PP_REBOOT TPM_MODE_SELECT(" (needs PP, maybe reboot)", "")
34 #define TPM20_NOT_IMPLEMENTED_DESCR(descr) \
35 descr TPM_MODE_SELECT("", " [not-implemented for TPM2.0]")
36 #define TPM20_NOT_IMPLEMENTED_HANDLER(handler) \
37 TPM_MODE_SELECT(handler, HandlerNotImplementedForTPM2)
38 #define TPM20_NOT_IMPLEMENTED(descr, handler) \
39 TPM20_NOT_IMPLEMENTED_DESCR(descr), \
40 TPM20_NOT_IMPLEMENTED_HANDLER(handler)
42 #define TPM20_DOES_NOTHING_DESCR(descr) \
43 descr TPM_MODE_SELECT("", " [no-op for TPM2.0]")
44 #define TPM20_DOES_NOTHING_HANDLER(handler) \
45 TPM_MODE_SELECT(handler, HandlerDoNothingForTPM2)
46 #define TPM20_DOES_NOTHING(descr, handler) \
47 TPM20_DOES_NOTHING_DESCR(descr), \
48 TPM20_DOES_NOTHING_HANDLER(handler)
50 typedef struct command_record {
53 const char* description;
54 uint32_t (*handler)(void);
57 /* Set in main, consumed by handler functions below. We use global variables
58 * so we can also choose to call Tlcl*() functions directly; they don't take
64 /* Converts a string in the form 0x[0-9a-f]+ to a 32-bit value. Returns 0 for
65 * success, non-zero for failure.
67 int HexStringToUint32(const char* string, uint32_t* value) {
69 /* strtoul is not as good because it overflows silently */
70 char* format = strncmp(string, "0x", 2) ? "%8x%s" : "0x%8x%s";
71 int n = sscanf(string, format, value, tail);
75 /* Converts a string in the form [0-9a-f]+ to an 8-bit value. Returns 0 for
76 * success, non-zero for failure.
78 int HexStringToUint8(const char* string, uint8_t* value) {
80 uint32_t large_value = strtoul(string, &end, 16);
81 if (*end != '\0' || large_value > 0xff) {
88 int HexStringToArray(const char* string, uint8_t* value, int num_bytes) {
89 int len = strlen(string);
90 if (!strncmp(string, "0x", 2)) {
94 if (len != num_bytes * 2) {
97 for (; len > 0; string += 2, len -= 2, value++) {
98 if (sscanf(string, "%2hhx", value) != 1) {
105 /* TPM error check and reporting. Returns 0 if |result| is 0 (TPM_SUCCESS).
106 * Otherwise looks up a TPM error in the error table and prints the error if
107 * found. Then returns min(result, OTHER_ERROR) since some error codes, such
108 * as TPM_E_RETRY, do not fit in a byte.
110 uint8_t ErrorCheck(uint32_t result, const char* cmd) {
111 uint8_t exit_code = result > OTHER_ERROR ? OTHER_ERROR : result;
116 int n = sizeof(tpm_error_table) / sizeof(tpm_error_table[0]);
117 fprintf(stderr, "command \"%s\" failed with code 0x%x\n", cmd, result);
118 for (i = 0; i < n; i++) {
119 if (tpm_error_table[i].code == result) {
120 fprintf(stderr, "%s\n%s\n", tpm_error_table[i].name,
121 tpm_error_table[i].description);
125 fprintf(stderr, "the TPM error code is unknown to this program\n");
130 /* Handler functions. These wouldn't exist if C had closures.
132 /* TODO(apronin): stub for selected flags for TPM2 */
134 static uint32_t HandlerGetFlags(void) {
135 fprintf(stderr, "getflags not implemented for TPM2\n");
139 static uint32_t HandlerGetFlags(void) {
143 uint32_t result = TlclGetFlags(&disabled, &deactivated, &nvlocked);
145 printf("disabled: %d\ndeactivated: %d\nnvlocked: %d\n",
146 disabled, deactivated, nvlocked);
153 static uint32_t HandlerActivate(void) {
154 return TlclSetDeactivated(0);
157 static uint32_t HandlerDeactivate(void) {
158 return TlclSetDeactivated(1);
162 static uint32_t HandlerDefineSpace(void) {
163 uint32_t index, size, perm;
165 fprintf(stderr, "usage: tpmc def <index> <size> <perm>\n");
168 if (HexStringToUint32(args[2], &index) != 0 ||
169 HexStringToUint32(args[3], &size) != 0 ||
170 HexStringToUint32(args[4], &perm) != 0) {
171 fprintf(stderr, "<index>, <size>, and <perm> must be "
172 "32-bit hex (0x[0-9a-f]+)\n");
175 return TlclDefineSpace(index, perm, size);
178 static uint32_t HandlerWrite(void) {
179 uint32_t index, size;
180 uint8_t value[TPM_MAX_COMMAND_SIZE];
184 fprintf(stderr, "usage: tpmc write <index> [<byte0> <byte1> ...]\n");
187 if (HexStringToUint32(args[2], &index) != 0) {
188 fprintf(stderr, "<index> must be 32-bit hex (0x[0-9a-f]+)\n");
192 if (size > sizeof(value)) {
193 fprintf(stderr, "byte array too large\n");
198 for (i = 0; i < size; i++) {
199 if (HexStringToUint8(byteargs[i], &value[i]) != 0) {
200 fprintf(stderr, "invalid byte %s, should be [0-9a-f][0-9a-f]?\n",
208 if (index == TPM_NV_INDEX_LOCK) {
209 fprintf(stderr, "This would set the nvLocked bit. "
210 "Use \"tpmc setnv\" instead.\n");
214 printf("warning: zero-length write\n");
216 printf("writing %d byte%s\n", size, size > 1 ? "s" : "");
219 return TlclWrite(index, value, size);
222 static uint32_t HandlerPCRRead(void) {
224 uint8_t value[TPM_PCR_DIGEST];
228 fprintf(stderr, "usage: tpmc pcrread <index>\n");
231 if (HexStringToUint32(args[2], &index) != 0) {
232 fprintf(stderr, "<index> must be 32-bit hex (0x[0-9a-f]+)\n");
235 result = TlclPCRRead(index, value, sizeof(value));
237 for (i = 0; i < TPM_PCR_DIGEST; i++) {
238 printf("%02x", value[i]);
245 static uint32_t HandlerPCRExtend(void) {
247 uint8_t value[TPM_PCR_DIGEST];
249 fprintf(stderr, "usage: tpmc pcrextend <index> <extend_hash>\n");
252 if (HexStringToUint32(args[2], &index) != 0) {
253 fprintf(stderr, "<index> must be 32-bit hex (0x[0-9a-f]+)\n");
256 if (HexStringToArray(args[3], value, TPM_PCR_DIGEST)) {
257 fprintf(stderr, "<extend_hash> must be a 20-byte hex string\n");
260 return TlclExtend(index, value, value);
263 static uint32_t HandlerRead(void) {
264 uint32_t index, size;
269 fprintf(stderr, "usage: tpmc read <index> <size>\n");
272 if (HexStringToUint32(args[2], &index) != 0 ||
273 HexStringToUint32(args[3], &size) != 0) {
274 fprintf(stderr, "<index> and <size> must be 32-bit hex (0x[0-9a-f]+)\n");
277 if (size > sizeof(value)) {
278 fprintf(stderr, "size of read (0x%x) is too big\n", size);
281 result = TlclRead(index, value, size);
282 if (result == 0 && size > 0) {
283 for (i = 0; i < size - 1; i++) {
284 printf("%x ", value[i]);
286 printf("%x\n", value[i]);
291 static uint32_t HandlerGetPermissions(void) {
292 uint32_t index, permissions, result;
294 fprintf(stderr, "usage: tpmc getp <index>\n");
297 if (HexStringToUint32(args[2], &index) != 0) {
298 fprintf(stderr, "<index> must be 32-bit hex (0x[0-9a-f]+)\n");
301 result = TlclGetPermissions(index, &permissions);
303 printf("space 0x%x has permissions 0x%x\n", index, permissions);
308 static uint32_t HandlerGetOwnership(void) {
312 fprintf(stderr, "usage: tpmc getownership\n");
315 result = TlclGetOwnership(&owned);
317 printf("Owned: %s\n", owned ? "yes" : "no");
322 static uint32_t HandlerGetRandom(void) {
323 uint32_t length, size;
328 fprintf(stderr, "usage: tpmc getrandom <size>\n");
331 if (HexStringToUint32(args[2], &length) != 0) {
332 fprintf(stderr, "<size> must be 32-bit hex (0x[0-9a-f]+)\n");
335 bytes = calloc(1, length);
340 result = TlclGetRandom(bytes, length, &size);
341 if (result == 0 && size > 0) {
342 for (i = 0; i < size; i++) {
343 printf("%02x", bytes[i]);
351 static uint32_t HandlerGetPermanentFlags(void) {
352 TPM_PERMANENT_FLAGS pflags;
353 uint32_t result = TlclGetPermanentFlags(&pflags);
355 #define P(name) printf("%s %d\n", #name, pflags.name)
358 P(endorsementAuthSet);
368 P(disableOwnerClear);
370 P(physicalPresenceLifetimeLock);
371 P(physicalPresenceHWEnable);
372 P(physicalPresenceCMDEnable);
383 P(disableFullDALogicInfo);
390 static uint32_t HandlerGetSTClearFlags(void) {
391 TPM_STCLEAR_FLAGS vflags;
392 uint32_t result = TlclGetSTClearFlags(&vflags);
394 #define P(name) printf("%s %d\n", #name, vflags.name)
403 P(disableForceClear);
405 P(physicalPresenceLock);
413 static uint32_t HandlerSendRaw(void) {
414 uint8_t request[4096];
415 uint8_t response[4096];
420 fprintf(stderr, "usage: tpmc sendraw <hex byte 0> ... <hex byte N>\n");
423 for (i = 0; i < nargs - 2 && i < sizeof(request); i++) {
424 if (HexStringToUint8(args[2 + i], &request[i]) != 0) {
425 fprintf(stderr, "bad byte value \"%s\"\n", args[2 + i]);
429 size = TlclPacketSize(request);
431 fprintf(stderr, "bad request: size field is %d, but packet has %d bytes\n",
435 bzero(response, sizeof(response));
436 result = TlclSendReceive(request, response, sizeof(response));
438 fprintf(stderr, "request failed with code %d\n", result);
440 size = TlclPacketSize(response);
441 if (size < 10 || size > sizeof(response)) {
442 fprintf(stderr, "unexpected response size %d\n", size);
445 for (i = 0; i < size; i++) {
446 printf("0x%02x ", response[i]);
447 if (i == size - 1 || (i + 1) % 8 == 0) {
455 static uint32_t HandlerDoNothingForTPM2(void) {
459 static uint32_t HandlerNotImplementedForTPM2(void) {
460 fprintf(stderr, "%s: not implemented for TPM2.0\n", args[1]);
465 /* Table of TPM commands.
467 command_record command_table[] = {
468 { "getflags", "getf", "read and print the value of selected flags",
470 { "startup", "sta", "issue a Startup command", TlclStartup },
471 { "selftestfull", "test", "issue a SelfTestFull command", TlclSelfTestFull },
472 { "continueselftest", "ctest", "issue a ContinueSelfTest command",
473 TlclContinueSelfTest },
474 { "assertphysicalpresence", "ppon",
475 TPM20_DOES_NOTHING("assert Physical Presence",
476 TlclAssertPhysicalPresence) },
477 { "physicalpresencecmdenable", "ppcmd",
478 TPM20_NOT_IMPLEMENTED("turn on software PP",
479 TlclPhysicalPresenceCMDEnable) },
481 TPM20_DOES_NOTHING("enable the TPM" TPM12_NEEDS_PP,
484 TPM20_NOT_IMPLEMENTED("disable the TPM" TPM12_NEEDS_PP,
487 TPM20_DOES_NOTHING("activate the TPM" TPM12_NEEDS_PP_REBOOT,
489 { "deactivate", "deact",
490 TPM20_NOT_IMPLEMENTED("deactivate the TPM" TPM12_NEEDS_PP_REBOOT,
491 HandlerDeactivate) },
493 "clear the TPM owner" TPM12_NEEDS_PP,
495 { "setnvlocked", "setnv",
496 TPM20_NOT_IMPLEMENTED("set the nvLocked flag permanently (IRREVERSIBLE!)",
498 { "lockphysicalpresence", "pplock",
499 TPM_MODE_SELECT("lock (turn off) PP until reboot",
500 "set rollback protection lock for kernel image until reboot"),
501 TlclLockPhysicalPresence },
502 { "setbgloballock", "block",
503 TPM_MODE_SELECT("set the bGlobalLock until reboot",
504 "set rollback protection lock for R/W firmware until reboot"),
506 { "definespace", "def", "define a space (def <index> <size> <perm>)",
507 HandlerDefineSpace },
508 { "write", "write", "write to a space (write <index> [<byte0> <byte1> ...])",
510 { "read", "read", "read from a space (read <index> <size>)",
512 { "pcrread", "pcr", "read from a PCR (pcrread <index>)",
514 { "pcrextend", "extend", "extend a PCR (extend <index> <extend_hash>)",
516 { "getownership", "geto", "print state of TPM ownership",
517 HandlerGetOwnership },
518 { "getpermissions", "getp", "print space permissions (getp <index>)",
519 HandlerGetPermissions },
520 { "getpermanentflags", "getpf", "print all permanent flags",
521 HandlerGetPermanentFlags },
522 { "getrandom", "rand", "read bytes from RNG (rand <size>)",
524 { "getstclearflags", "getvf", "print all volatile (ST_CLEAR) flags",
525 HandlerGetSTClearFlags },
526 { "resume", "res", "execute TPM_Startup(ST_STATE)", TlclResume },
527 { "savestate", "save", "execute TPM_SaveState", TlclSaveState },
528 { "sendraw", "raw", "send a raw request and print raw response",
532 static int n_commands = sizeof(command_table) / sizeof(command_table[0]);
534 int main(int argc, char* argv[]) {
538 progname = strrchr(argv[0], '/');
545 fprintf(stderr, "usage: %s <TPM command> [args]\n or: %s help\n",
550 const char* cmd = argv[1];
554 if (strcmp(cmd, "help") == 0) {
555 printf("tpmc mode: TPM%s\n", TPM_MODE_STRING);
556 printf("%26s %7s %s\n\n", "command", "abbr.", "description");
557 for (c = command_table; c < command_table + n_commands; c++) {
558 printf("%26s %7s %s\n", c->name, c->abbr, c->description);
563 result = TlclLibInit();
565 fprintf(stderr, "initialization failed with code %d\n", result);
566 return result > OTHER_ERROR ? OTHER_ERROR : result;
569 for (c = command_table; c < command_table + n_commands; c++) {
570 if (strcmp(cmd, c->name) == 0 || strcmp(cmd, c->abbr) == 0) {
571 return ErrorCheck(c->handler(), cmd);
575 /* No command matched. */
576 fprintf(stderr, "%s: unknown command: %s\n", progname, cmd);