blob: 98004e80fd26a70e20dd3c156425104b996cfc41 [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
Bill Richardson0c3ba242013-03-29 11:09:30 -070012#include <stdint.h>
13#include <stdlib.h>
Luigi Semenzatoe72291c2010-08-10 09:46:09 -070014#include <stdio.h>
15#include <string.h>
16#include <syslog.h>
17
18#include "tlcl.h"
19#include "tpm_error_messages.h"
Luigi Semenzatoc91e2392010-08-17 14:31:52 -070020#include "tss_constants.h"
Luigi Semenzatoe72291c2010-08-10 09:46:09 -070021
Luigi Semenzatoa8cba992010-09-21 14:12:15 -070022#define OTHER_ERROR 255
23
Luigi Semenzatoe72291c2010-08-10 09:46:09 -070024typedef struct command_record {
25 const char* name;
26 const char* abbr;
27 const char* description;
28 uint32_t (*handler)(void);
29} command_record;
30
Luigi Semenzatoc91e2392010-08-17 14:31:52 -070031/* Set in main, consumed by handler functions below. We use global variables
32 * so we can also choose to call Tlcl*() functions directly; they don't take
33 * argv/argc.
34 */
35int nargs;
36char** args;
37
38/* Converts a string in the form 0x[0-9a-f]+ to a 32-bit value. Returns 0 for
39 * success, non-zero for failure.
40 */
41int HexStringToUint32(const char* string, uint32_t* value) {
42 char tail[1];
43 /* strtoul is not as good because it overflows silently */
44 char* format = strncmp(string, "0x", 2) ? "%8x%s" : "0x%8x%s";
45 int n = sscanf(string, format, value, tail);
46 return n != 1;
47}
48
49/* Converts a string in the form [0-9a-f]+ to an 8-bit value. Returns 0 for
50 * success, non-zero for failure.
51 */
52int HexStringToUint8(const char* string, uint8_t* value) {
53 char* end;
54 uint32_t large_value = strtoul(string, &end, 16);
55 if (*end != '\0' || large_value > 0xff) {
56 return 1;
57 }
58 *value = large_value;
59 return 0;
60}
61
62/* TPM error check and reporting. Returns 0 if |result| is 0 (TPM_SUCCESS).
63 * Otherwise looks up a TPM error in the error table and prints the error if
64 * found.
65 */
66uint32_t ErrorCheck(uint32_t result, const char* cmd) {
67 if (result == 0) {
68 return 0;
69 } else {
70 int i;
71 int n = sizeof(tpm_error_table) / sizeof(tpm_error_table[0]);
72 fprintf(stderr, "command \"%s\" failed with code 0x%x\n", cmd, result);
73 for (i = 0; i < n; i++) {
74 if (tpm_error_table[i].code == result) {
75 fprintf(stderr, "%s\n%s\n", tpm_error_table[i].name,
76 tpm_error_table[i].description);
Luigi Semenzatoa8cba992010-09-21 14:12:15 -070077 return result;
Luigi Semenzatoc91e2392010-08-17 14:31:52 -070078 }
79 }
80 fprintf(stderr, "the TPM error code is unknown to this program\n");
Luigi Semenzatoa8cba992010-09-21 14:12:15 -070081 return result;
Luigi Semenzatoc91e2392010-08-17 14:31:52 -070082 }
83}
84
Luigi Semenzatoe72291c2010-08-10 09:46:09 -070085/* Handler functions. These wouldn't exist if C had closures.
86 */
Luigi Semenzatoe72291c2010-08-10 09:46:09 -070087static uint32_t HandlerGetFlags(void) {
88 uint8_t disabled;
89 uint8_t deactivated;
90 uint8_t nvlocked;
91 uint32_t result = TlclGetFlags(&disabled, &deactivated, &nvlocked);
92 if (result == 0) {
93 printf("disabled: %d\ndeactivated: %d\nnvlocked: %d\n",
94 disabled, deactivated, nvlocked);
95 }
96 return result;
97}
98
99static uint32_t HandlerActivate(void) {
100 return TlclSetDeactivated(0);
101}
102
103static uint32_t HandlerDeactivate(void) {
104 return TlclSetDeactivated(1);
105}
106
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700107static uint32_t HandlerDefineSpace(void) {
108 uint32_t index, size, perm;
109 if (nargs != 5) {
110 fprintf(stderr, "usage: tpmc def <index> <size> <perm>\n");
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700111 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700112 }
113 if (HexStringToUint32(args[2], &index) != 0 ||
114 HexStringToUint32(args[3], &size) != 0 ||
115 HexStringToUint32(args[4], &perm) != 0) {
116 fprintf(stderr, "<index>, <size>, and <perm> must be "
117 "32-bit hex (0x[0-9a-f]+)\n");
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700118 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700119 }
120 return TlclDefineSpace(index, perm, size);
121}
122
123static uint32_t HandlerWrite(void) {
124 uint32_t index, size;
125 uint8_t value[TPM_MAX_COMMAND_SIZE];
126 char** byteargs;
127 int i;
128 if (nargs < 3) {
129 fprintf(stderr, "usage: tpmc write <index> [<byte0> <byte1> ...]\n");
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700130 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700131 }
132 if (HexStringToUint32(args[2], &index) != 0) {
133 fprintf(stderr, "<index> must be 32-bit hex (0x[0-9a-f]+)\n");
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700134 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700135 }
136 size = nargs - 3;
137 if (size > sizeof(value)) {
138 fprintf(stderr, "byte array too large\n");
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700139 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700140 }
141
142 byteargs = args + 3;
143 for (i = 0; i < size; i++) {
144 if (HexStringToUint8(byteargs[i], &value[i]) != 0) {
145 fprintf(stderr, "invalid byte %s, should be [0-9a-f][0-9a-f]?\n",
146 byteargs[i]);
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700147 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700148 }
149 }
150
151 if (size == 0) {
152 if (index == TPM_NV_INDEX_LOCK) {
153 fprintf(stderr, "This would set the nvLocked bit. "
154 "Use \"tpmc setnv\" instead.\n");
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700155 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700156 }
157 printf("warning: zero-length write\n");
158 } else {
159 printf("writing %d byte%s\n", size, size > 1 ? "s" : "");
160 }
161
162 return TlclWrite(index, value, size);
163}
164
Kees Cook946370d2012-01-09 14:17:40 -0800165static uint32_t HandlerPCRRead(void) {
166 uint32_t index;
167 uint8_t value[TPM_PCR_DIGEST];
168 uint32_t result;
169 int i;
170 if (nargs != 3) {
171 fprintf(stderr, "usage: tpmc pcrread <index>\n");
172 exit(OTHER_ERROR);
173 }
174 if (HexStringToUint32(args[2], &index) != 0) {
175 fprintf(stderr, "<index> must be 32-bit hex (0x[0-9a-f]+)\n");
176 exit(OTHER_ERROR);
177 }
178 result = TlclPCRRead(index, value, sizeof(value));
179 if (result == 0) {
180 for (i = 0; i < TPM_PCR_DIGEST; i++) {
181 printf("%02x", value[i]);
182 }
183 printf("\n");
184 }
185 return result;
186}
187
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700188static uint32_t HandlerRead(void) {
189 uint32_t index, size;
190 uint8_t value[4096];
191 uint32_t result;
192 int i;
193 if (nargs != 4) {
194 fprintf(stderr, "usage: tpmc read <index> <size>\n");
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700195 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700196 }
197 if (HexStringToUint32(args[2], &index) != 0 ||
198 HexStringToUint32(args[3], &size) != 0) {
199 fprintf(stderr, "<index> and <size> must be 32-bit hex (0x[0-9a-f]+)\n");
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700200 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700201 }
202 if (size > sizeof(value)) {
203 fprintf(stderr, "size of read (0x%x) is too big\n", size);
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700204 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700205 }
206 result = TlclRead(index, value, size);
207 if (result == 0 && size > 0) {
208 for (i = 0; i < size - 1; i++) {
209 printf("%x ", value[i]);
210 }
211 printf("%x\n", value[i]);
212 }
213 return result;
214}
215
216static uint32_t HandlerGetPermissions(void) {
217 uint32_t index, permissions, result;
218 if (nargs != 3) {
219 fprintf(stderr, "usage: tpmc getp <index>\n");
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700220 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700221 }
222 if (HexStringToUint32(args[2], &index) != 0) {
223 fprintf(stderr, "<index> must be 32-bit hex (0x[0-9a-f]+)\n");
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700224 exit(OTHER_ERROR);
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700225 }
226 result = TlclGetPermissions(index, &permissions);
227 if (result == 0) {
228 printf("space 0x%x has permissions 0x%x\n", index, permissions);
229 }
230 return result;
231}
232
Kees Cook8b6da262012-06-07 13:48:26 -0700233static uint32_t HandlerGetOwnership(void) {
234 uint8_t owned = 0;
235 uint32_t result;
236 if (nargs != 2) {
237 fprintf(stderr, "usage: tpmc getownership\n");
238 exit(OTHER_ERROR);
239 }
240 result = TlclGetOwnership(&owned);
241 if (result == 0) {
242 printf("Owned: %s\n", owned ? "yes" : "no");
243 }
244 return result;
245}
246
Kees Cookf0605cb2012-02-29 16:09:14 -0800247static uint32_t HandlerGetRandom(void) {
248 uint32_t length, size;
249 uint8_t* bytes;
250 uint32_t result;
251 int i;
252 if (nargs != 3) {
253 fprintf(stderr, "usage: tpmc getrandom <size>\n");
254 exit(OTHER_ERROR);
255 }
256 if (HexStringToUint32(args[2], &length) != 0) {
257 fprintf(stderr, "<size> must be 32-bit hex (0x[0-9a-f]+)\n");
258 exit(OTHER_ERROR);
259 }
260 bytes = calloc(1, length);
261 if (bytes == NULL) {
262 perror("calloc");
263 exit(OTHER_ERROR);
264 }
265 result = TlclGetRandom(bytes, length, &size);
266 if (result == 0 && size > 0) {
267 for (i = 0; i < size; i++) {
268 printf("%02x", bytes[i]);
269 }
270 printf("\n");
271 }
272 free(bytes);
273 return result;
274}
275
Luigi Semenzato5896b962010-08-25 07:16:03 -0700276static uint32_t HandlerGetPermanentFlags(void) {
277 TPM_PERMANENT_FLAGS pflags;
278 uint32_t result = TlclGetPermanentFlags(&pflags);
279 if (result == 0) {
280#define P(name) printf("%s %d\n", #name, pflags.name)
281 P(disable);
282 P(ownership);
283 P(deactivated);
284 P(readPubek);
285 P(disableOwnerClear);
286 P(allowMaintenance);
287 P(physicalPresenceLifetimeLock);
288 P(physicalPresenceHWEnable);
289 P(physicalPresenceCMDEnable);
290 P(CEKPUsed);
291 P(TPMpost);
292 P(TPMpostLock);
293 P(FIPS);
294 P(Operator);
295 P(enableRevokeEK);
296 P(nvLocked);
297 P(readSRKPub);
298 P(tpmEstablished);
299 P(maintenanceDone);
300 P(disableFullDALogicInfo);
301#undef P
302 }
303 return result;
304}
305
306static uint32_t HandlerGetSTClearFlags(void) {
307 TPM_STCLEAR_FLAGS vflags;
308 uint32_t result = TlclGetSTClearFlags(&vflags);
309 if (result == 0) {
310#define P(name) printf("%s %d\n", #name, vflags.name)
311 P(deactivated);
312 P(disableForceClear);
313 P(physicalPresence);
314 P(physicalPresenceLock);
315 P(bGlobalLock);
316#undef P
317 }
318 return result;
319}
320
321
Luigi Semenzato3428b4b2013-01-11 15:50:39 -0800322static uint32_t HandlerSendRaw(void) {
323 uint8_t request[4096];
324 uint8_t response[4096];
325 uint32_t result;
326 int size;
327 int i;
328 if (nargs == 2) {
329 fprintf(stderr, "usage: tpmc sendraw <hex byte 0> ... <hex byte N>\n");
330 exit(OTHER_ERROR);
331 }
332 for (i = 0; i < nargs - 2 && i < sizeof(request); i++) {
333 if (HexStringToUint8(args[2 + i], &request[i]) != 0) {
334 fprintf(stderr, "bad byte value \"%s\"\n", args[2 + i]);
335 exit(OTHER_ERROR);
336 }
337 }
338 size = TlclPacketSize(request);
339 if (size != i) {
340 fprintf(stderr, "bad request: size field is %d, but packet has %d bytes\n",
341 size, i);
342 exit(OTHER_ERROR);
343 }
344 bzero(response, sizeof(response));
345 result = TlclSendReceive(request, response, sizeof(response));
346 if (result != 0) {
347 fprintf(stderr, "request failed with code %d\n", result);
348 }
349 size = TlclPacketSize(response);
350 if (size < 10 || size > sizeof(response)) {
351 fprintf(stderr, "unexpected response size %d\n", size);
352 exit(OTHER_ERROR);
353 }
354 for (i = 0; i < size; i++) {
355 printf("0x%02x ", response[i]);
356 if (i == size - 1 || (i + 1) % 8 == 0) {
357 printf("\n");
358 }
359 }
360 return result;
361}
362
363
Luigi Semenzatoe72291c2010-08-10 09:46:09 -0700364/* Table of TPM commands.
365 */
366command_record command_table[] = {
367 { "getflags", "getf", "read and print the value of selected flags",
368 HandlerGetFlags },
369 { "startup", "sta", "issue a Startup command", TlclStartup },
370 { "selftestfull", "test", "issue a SelfTestFull command", TlclSelfTestFull },
371 { "continueselftest", "ctest", "issue a ContinueSelfTest command",
372 TlclContinueSelfTest },
373 { "assertphysicalpresence", "ppon", "assert Physical Presence",
374 TlclAssertPhysicalPresence },
Luigi Semenzato1d83dd12010-08-30 10:23:43 -0700375 { "physicalpresencecmdenable", "ppcmd", "turn on software PP",
376 TlclPhysicalPresenceCMDEnable },
Luigi Semenzatoe72291c2010-08-10 09:46:09 -0700377 { "enable", "ena", "enable the TPM (needs PP)", TlclSetEnable },
378 { "disable", "dis", "disable the TPM (needs PP)", TlclClearEnable },
379 { "activate", "act", "activate the TPM (needs PP, maybe reboot)",
380 HandlerActivate },
381 { "deactivate", "deact", "deactivate the TPM (needs PP, maybe reboot)",
382 HandlerDeactivate },
Luigi Semenzato56cec582010-08-10 15:09:37 -0700383 { "clear", "clr", "clear the TPM owner (needs PP)", TlclForceClear },
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700384 { "setnvlocked", "setnv", "set the nvLocked flag permanently (IRREVERSIBLE!)",
385 TlclSetNvLocked },
Gaurav Shahac6d5602011-07-20 18:10:10 -0700386 { "lockphysicalpresence", "pplock", "lock (turn off) PP until reboot",
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700387 TlclLockPhysicalPresence },
388 { "setbgloballock", "block", "set the bGlobalLock until reboot",
389 TlclSetGlobalLock },
390 { "definespace", "def", "define a space (def <index> <size> <perm>)",
391 HandlerDefineSpace },
392 { "write", "write", "write to a space (write <index> [<byte0> <byte1> ...])",
393 HandlerWrite },
394 { "read", "read", "read from a space (read <index> <size>)",
395 HandlerRead },
Kees Cook946370d2012-01-09 14:17:40 -0800396 { "pcrread", "pcr", "read from a PCR (pcrread <index>)",
397 HandlerPCRRead },
Kees Cook8b6da262012-06-07 13:48:26 -0700398 { "getownership", "geto", "print state of TPM ownership",
399 HandlerGetOwnership },
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700400 { "getpermissions", "getp", "print space permissions (getp <index>)",
401 HandlerGetPermissions },
Luigi Semenzato5896b962010-08-25 07:16:03 -0700402 { "getpermanentflags", "getpf", "print all permanent flags",
403 HandlerGetPermanentFlags },
Kees Cookf0605cb2012-02-29 16:09:14 -0800404 { "getrandom", "rand", "read bytes from RNG (rand <size>)",
405 HandlerGetRandom },
Luigi Semenzato5896b962010-08-25 07:16:03 -0700406 { "getstclearflags", "getvf", "print all volatile (ST_CLEAR) flags",
407 HandlerGetSTClearFlags },
Luigi Semenzatod903cc82010-10-27 09:42:51 -0700408 { "resume", "res", "execute TPM_Startup(ST_STATE)", TlclResume },
Luigi Semenzato54992f92011-03-16 10:56:48 -0700409 { "savestate", "save", "execute TPM_SaveState", TlclSaveState },
Luigi Semenzato3428b4b2013-01-11 15:50:39 -0800410 { "sendraw", "raw", "send a raw request and print raw response",
411 HandlerSendRaw },
Luigi Semenzatoe72291c2010-08-10 09:46:09 -0700412};
413
414static int n_commands = sizeof(command_table) / sizeof(command_table[0]);
415
416int main(int argc, char* argv[]) {
Bill Richardsonfeb25182013-03-07 12:54:29 -0800417 char *progname;
418 progname = strrchr(argv[0], '/');
419 if (progname)
420 progname++;
421 else
422 progname = argv[0];
423
Luigi Semenzatoe72291c2010-08-10 09:46:09 -0700424 if (argc < 2) {
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700425 fprintf(stderr, "usage: %s <TPM command> [args]\n or: %s help\n",
Bill Richardsonfeb25182013-03-07 12:54:29 -0800426 progname, progname);
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700427 return OTHER_ERROR;
Luigi Semenzatoe72291c2010-08-10 09:46:09 -0700428 } else {
429 command_record* c;
430 const char* cmd = argv[1];
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700431 nargs = argc;
432 args = argv;
Luigi Semenzatoe72291c2010-08-10 09:46:09 -0700433
434 if (strcmp(cmd, "help") == 0) {
Luigi Semenzato1d83dd12010-08-30 10:23:43 -0700435 printf("%26s %7s %s\n\n", "command", "abbr.", "description");
Luigi Semenzatoe72291c2010-08-10 09:46:09 -0700436 for (c = command_table; c < command_table + n_commands; c++) {
Luigi Semenzato1d83dd12010-08-30 10:23:43 -0700437 printf("%26s %7s %s\n", c->name, c->abbr, c->description);
Luigi Semenzatoe72291c2010-08-10 09:46:09 -0700438 }
439 return 0;
440 }
441
442 TlclLibInit();
443
444 for (c = command_table; c < command_table + n_commands; c++) {
445 if (strcmp(cmd, c->name) == 0 || strcmp(cmd, c->abbr) == 0) {
Luigi Semenzatoc91e2392010-08-17 14:31:52 -0700446 return ErrorCheck(c->handler(), cmd);
Luigi Semenzatoe72291c2010-08-10 09:46:09 -0700447 }
448 }
449
450 /* No command matched. */
Bill Richardsonfeb25182013-03-07 12:54:29 -0800451 fprintf(stderr, "%s: unknown command: %s\n", progname, cmd);
Luigi Semenzatoa8cba992010-09-21 14:12:15 -0700452 return OTHER_ERROR;
Luigi Semenzatoe72291c2010-08-10 09:46:09 -0700453 }
454}