xref: /aosp_15_r20/external/vboot_reference/utility/tpmc.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
1 /* Copyright 2012 The ChromiumOS Authors
2  * 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.
7  *
8  * The exit code is 0 for success, the TPM error code for TPM errors, and 255
9  * for other errors.
10  */
11 
12 #include <inttypes.h>
13 #include <stdint.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <syslog.h>
18 
19 #include "tlcl.h"
20 #include "tpm_error_messages.h"
21 #include "tss_constants.h"
22 
23 #define OTHER_ERROR 255  /* OTHER_ERROR must be the largest uint8_t value. */
24 
25 #ifdef TPM2_MODE
26 #define TPM_MODE_SELECT(_, tpm20_ver) tpm20_ver
27 #else
28 #define TPM_MODE_SELECT(tpm12_ver, _) tpm12_ver
29 #endif
30 
31 #define TPM_MODE_STRING TPM_MODE_SELECT("1.2", "2.0")
32 #define TPM12_NEEDS_PP TPM_MODE_SELECT(" (needs PP)", "")
33 #define TPM12_NEEDS_PP_REBOOT TPM_MODE_SELECT(" (needs PP, maybe reboot)", "")
34 
35 #define TPM20_NOT_IMPLEMENTED_DESCR(descr) \
36   descr TPM_MODE_SELECT("", " [not-implemented for TPM2.0]")
37 #define TPM20_NOT_IMPLEMENTED_HANDLER(handler) \
38   TPM_MODE_SELECT(handler, HandlerNotImplementedForTPM2)
39 #define TPM20_NOT_IMPLEMENTED(descr, handler) \
40   TPM20_NOT_IMPLEMENTED_DESCR(descr), \
41   TPM20_NOT_IMPLEMENTED_HANDLER(handler)
42 
43 #define TPM20_DOES_NOTHING_DESCR(descr) \
44   descr TPM_MODE_SELECT("", " [no-op for TPM2.0]")
45 #define TPM20_DOES_NOTHING_HANDLER(handler) \
46   TPM_MODE_SELECT(handler, HandlerDoNothingForTPM2)
47 #define TPM20_DOES_NOTHING(descr, handler) \
48   TPM20_DOES_NOTHING_DESCR(descr), \
49   TPM20_DOES_NOTHING_HANDLER(handler)
50 
51 typedef struct command_record {
52   const char* name;
53   const char* abbr;
54   const char* description;
55   uint32_t (*handler)(void);
56 } command_record;
57 
58 /* Set in main, consumed by handler functions below.  We use global variables
59  * so we can also choose to call Tlcl*() functions directly; they don't take
60  * argv/argc.
61  */
62 int nargs;
63 char** args;
64 
65 /* Converts a string in the form 0x[0-9a-f]+ to a 32-bit value.  Returns 0 for
66  * success, non-zero for failure.
67  */
HexStringToUint32(const char * string,uint32_t * value)68 static int HexStringToUint32(const char* string, uint32_t* value) {
69   char tail;
70   /* strtoul is not as good because it overflows silently */
71   const char* format = strncmp(string, "0x", 2) ? "%8x%c" : "0x%8x%c";
72   int n = sscanf(string, format, value, &tail);
73   return n != 1;
74 }
75 
76 /* Converts a string in the form [0-9a-f]+ to an 8-bit value.  Returns 0 for
77  * success, non-zero for failure.
78  */
HexStringToUint8(const char * string,uint8_t * value)79 static int HexStringToUint8(const char* string, uint8_t* value) {
80   char* end;
81   uint32_t large_value = strtoul(string, &end, 16);
82   if (*end != '\0' || large_value > 0xff) {
83     return 1;
84   }
85   *value = large_value;
86   return 0;
87 }
88 
HexStringToArray(const char * string,uint8_t * value,int num_bytes)89 static int HexStringToArray(const char* string, uint8_t* value, int num_bytes) {
90   int len = strlen(string);
91   if (!strncmp(string, "0x", 2)) {
92     string += 2;
93     len -= 2;
94   }
95   if (len != num_bytes * 2) {
96     return 1;
97   }
98   for (; len > 0; string += 2, len -= 2, value++) {
99     if (sscanf(string, "%2hhx", value) != 1) {
100       return 1;
101     }
102   }
103   return 0;
104 }
105 
106 /* TPM error check and reporting.  Returns 0 if |result| is 0 (TPM_SUCCESS).
107  * Otherwise looks up a TPM error in the error table and prints the error if
108  * found.  Then returns min(result, OTHER_ERROR) since some error codes, such
109  * as TPM_E_RETRY, do not fit in a byte.
110  */
ErrorCheck(uint32_t result,const char * cmd)111 static uint8_t ErrorCheck(uint32_t result, const char* cmd) {
112   uint8_t exit_code = result > OTHER_ERROR ? OTHER_ERROR : result;
113   if (result == 0) {
114     return 0;
115   } else {
116     int i;
117     int n = sizeof(tpm_error_table) / sizeof(tpm_error_table[0]);
118     fprintf(stderr, "command \"%s\" failed with code %#x\n", cmd, result);
119     for (i = 0; i < n; i++) {
120       if (tpm_error_table[i].code == result) {
121         fprintf(stderr, "%s\n%s\n", tpm_error_table[i].name,
122                 tpm_error_table[i].description);
123         return exit_code;
124       }
125     }
126     fprintf(stderr, "the TPM error code is unknown to this program\n");
127     return exit_code;
128   }
129 }
130 
131 /* Handler functions.  These wouldn't exist if C had closures.
132  */
HandlerTpmVersion(void)133 static uint32_t HandlerTpmVersion(void) {
134   puts(TPM_MODE_STRING);
135   return 0;
136 }
137 
138 /* TODO(apronin): stub for selected flags for TPM2 */
139 #ifdef TPM2_MODE
HandlerGetFlags(void)140 static uint32_t HandlerGetFlags(void) {
141   fprintf(stderr, "getflags not implemented for TPM2\n");
142   exit(OTHER_ERROR);
143 }
144 #else
HandlerGetFlags(void)145 static uint32_t HandlerGetFlags(void) {
146   uint8_t disabled;
147   uint8_t deactivated;
148   uint8_t nvlocked;
149   uint32_t result = TlclGetFlags(&disabled, &deactivated, &nvlocked);
150   if (result == 0) {
151     printf("disabled: %d\ndeactivated: %d\nnvlocked: %d\n",
152            disabled, deactivated, nvlocked);
153   }
154   return result;
155 }
156 #endif
157 
158 #ifndef TPM2_MODE
HandlerActivate(void)159 static uint32_t HandlerActivate(void) {
160   return TlclSetDeactivated(0);
161 }
162 
HandlerDeactivate(void)163 static uint32_t HandlerDeactivate(void) {
164   return TlclSetDeactivated(1);
165 }
166 #endif
167 
HandlerDefineSpace(void)168 static uint32_t HandlerDefineSpace(void) {
169   uint32_t index, size, perm;
170   int overwrite = 1;
171 
172   if (nargs != 5 && nargs != 6) {
173     fprintf(stderr, "usage: tpmc def <index> <size> <perm> "
174                     "[--no-overwrite])\n");
175     exit(OTHER_ERROR);
176   }
177 
178   if (HexStringToUint32(args[2], &index) != 0 ||
179       HexStringToUint32(args[3], &size) != 0 ||
180       HexStringToUint32(args[4], &perm) != 0) {
181     fprintf(stderr, "<index>, <size>, and <perm> must be "
182             "32-bit hex (0x[0-9a-f]+)\n");
183     exit(OTHER_ERROR);
184   }
185 
186   if (args[5] && strcmp(args[5], "--no-overwrite") == 0) {
187     overwrite = 0;
188   }
189 
190 #ifdef TPM2_MODE
191   // For TPM 2.0, DefineSpace will fail if the space already exists, so to
192   // support the default 'overwrite' mode, need to undefine the space first.
193   if (overwrite) {
194     TlclUndefineSpace(index);
195   }
196 #else  /* ifndef TPM2_MODE */
197   // For TPM 1.2, we have to check the existing before calling DefineSpace(),
198   // since it will automaticly overwrite the existing space by default.
199   // Do nothing for TPM 2.0. We rely on DefineSpace() to return the appropriate
200   // error code.
201   if (!overwrite) {
202     uint32_t result , permissions;
203     result = TlclGetPermissions(index, &permissions);
204     if (!result) {
205       fprintf(stderr, "The space is existing but --no-overwrite is set.\n");
206       exit(OTHER_ERROR);
207     }
208   }
209 #endif
210 
211   return TlclDefineSpace(index, perm, size);
212 }
213 
HandlerUndefineSpace(void)214 static uint32_t HandlerUndefineSpace(void) {
215   uint32_t index;
216   if (nargs != 3) {
217     fprintf(stderr, "usage: tpmc undef <index>\n");
218     exit(OTHER_ERROR);
219   }
220   if (HexStringToUint32(args[2], &index) != 0) {
221     fprintf(stderr, "<index> must be "
222             "32-bit hex (0x[0-9a-f]+)\n");
223     exit(OTHER_ERROR);
224   }
225   return TlclUndefineSpace(index);
226 }
227 
HandlerWrite(void)228 static uint32_t HandlerWrite(void) {
229   uint32_t index, size;
230   uint8_t value[TPM_MAX_COMMAND_SIZE];
231   char** byteargs;
232   int i;
233   if (nargs < 3) {
234     fprintf(stderr, "usage: tpmc write <index> [<byte0> <byte1> ...]\n");
235     exit(OTHER_ERROR);
236   }
237   if (HexStringToUint32(args[2], &index) != 0) {
238     fprintf(stderr, "<index> must be 32-bit hex (0x[0-9a-f]+)\n");
239     exit(OTHER_ERROR);
240   }
241   size = nargs - 3;
242   if (size > sizeof(value)) {
243     fprintf(stderr, "byte array too large\n");
244     exit(OTHER_ERROR);
245   }
246 
247   byteargs = args + 3;
248   for (i = 0; i < size; i++) {
249     if (HexStringToUint8(byteargs[i], &value[i]) != 0) {
250       fprintf(stderr, "invalid byte %s, should be [0-9a-f][0-9a-f]?\n",
251               byteargs[i]);
252       exit(OTHER_ERROR);
253     }
254   }
255 
256   if (size == 0) {
257 #ifndef TPM2_MODE
258     if (index == TPM_NV_INDEX_LOCK) {
259       fprintf(stderr, "This would set the nvLocked bit. "
260               "Use \"tpmc setnv\" instead.\n");
261       exit(OTHER_ERROR);
262     }
263 #endif
264     printf("warning: zero-length write\n");
265   } else {
266     printf("writing %d byte%s\n", size, size > 1 ? "s" : "");
267   }
268 
269   return TlclWrite(index, value, size);
270 }
271 
HandlerPCRRead(void)272 static uint32_t HandlerPCRRead(void) {
273   uint32_t index;
274   uint8_t value[TPM_PCR_DIGEST];
275   uint32_t result;
276   int i;
277   if (nargs != 3) {
278     fprintf(stderr, "usage: tpmc pcrread <index>\n");
279     exit(OTHER_ERROR);
280   }
281   if (HexStringToUint32(args[2], &index) != 0) {
282     fprintf(stderr, "<index> must be 32-bit hex (0x[0-9a-f]+)\n");
283     exit(OTHER_ERROR);
284   }
285   result = TlclPCRRead(index, value, sizeof(value));
286   if (result == 0) {
287     for (i = 0; i < TPM_PCR_DIGEST; i++) {
288       printf("%02x", value[i]);
289     }
290     printf("\n");
291   }
292   return result;
293 }
294 
HandlerPCRExtend(void)295 static uint32_t HandlerPCRExtend(void) {
296   uint32_t index;
297   uint8_t value[TPM_PCR_DIGEST];
298   if (nargs != 4) {
299     fprintf(stderr, "usage: tpmc pcrextend <index> <extend_hash>\n");
300     exit(OTHER_ERROR);
301   }
302   if (HexStringToUint32(args[2], &index) != 0) {
303     fprintf(stderr, "<index> must be 32-bit hex (0x[0-9a-f]+)\n");
304     exit(OTHER_ERROR);
305   }
306   if (HexStringToArray(args[3], value, TPM_PCR_DIGEST)) {
307     fprintf(stderr, "<extend_hash> must be a %d-byte hex string\n",
308 	    TPM_PCR_DIGEST);
309     exit(OTHER_ERROR);
310   }
311   return TlclExtend(index, value, value);
312 }
313 
HandlerRead(void)314 static uint32_t HandlerRead(void) {
315   uint32_t index, size;
316   uint8_t value[4096];
317   uint32_t result;
318   int i;
319   if (nargs != 4) {
320     fprintf(stderr, "usage: tpmc read <index> <size>\n");
321     exit(OTHER_ERROR);
322   }
323   if (HexStringToUint32(args[2], &index) != 0 ||
324       HexStringToUint32(args[3], &size) != 0) {
325     fprintf(stderr, "<index> and <size> must be 32-bit hex (0x[0-9a-f]+)\n");
326     exit(OTHER_ERROR);
327   }
328   if (size > sizeof(value)) {
329     fprintf(stderr, "size of read (%#x) is too big\n", size);
330     exit(OTHER_ERROR);
331   }
332   result = TlclRead(index, value, size);
333   if (result == 0 && size > 0) {
334     for (i = 0; i < size - 1; i++) {
335       printf("%x ", value[i]);
336     }
337     printf("%x\n", value[i]);
338   }
339   return result;
340 }
341 
HandlerGetPermissions(void)342 static uint32_t HandlerGetPermissions(void) {
343   uint32_t index, permissions, result;
344   if (nargs != 3) {
345     fprintf(stderr, "usage: tpmc getp <index>\n");
346     exit(OTHER_ERROR);
347   }
348   if (HexStringToUint32(args[2], &index) != 0) {
349     fprintf(stderr, "<index> must be 32-bit hex (0x[0-9a-f]+)\n");
350     exit(OTHER_ERROR);
351   }
352   result = TlclGetPermissions(index, &permissions);
353   if (result == 0) {
354     printf("space %#x has permissions %#x\n", index, permissions);
355   }
356   return result;
357 }
358 
HandlerGetOwnership(void)359 static uint32_t HandlerGetOwnership(void) {
360   uint8_t owned = 0;
361   uint32_t result;
362   if (nargs != 2) {
363     fprintf(stderr, "usage: tpmc getownership\n");
364     exit(OTHER_ERROR);
365   }
366   result = TlclGetOwnership(&owned);
367   if (result == 0) {
368     printf("Owned: %s\n", owned ? "yes" : "no");
369   }
370   return result;
371 }
372 
HandlerGetRandom(void)373 static uint32_t HandlerGetRandom(void) {
374   uint32_t length, size = 0;
375   uint8_t* bytes;
376   uint32_t result;
377   int i;
378   if (nargs != 3) {
379     fprintf(stderr, "usage: tpmc getrandom <size>\n");
380     exit(OTHER_ERROR);
381   }
382   if (HexStringToUint32(args[2], &length) != 0) {
383     fprintf(stderr, "<size> must be 32-bit hex (0x[0-9a-f]+)\n");
384     exit(OTHER_ERROR);
385   }
386   bytes = calloc(1, length);
387   if (bytes == NULL) {
388     perror("calloc");
389     exit(OTHER_ERROR);
390   }
391   result = TlclGetRandom(bytes, length, &size);
392   if (result == 0 && size > 0) {
393     for (i = 0; i < size; i++) {
394       printf("%02x", bytes[i]);
395     }
396     printf("\n");
397   }
398   free(bytes);
399   return result;
400 }
401 
HandlerGetPermanentFlags(void)402 static uint32_t HandlerGetPermanentFlags(void) {
403   TPM_PERMANENT_FLAGS pflags;
404   uint32_t result = TlclGetPermanentFlags(&pflags);
405   if (result == 0) {
406 #define P(name) printf("%s %d\n", #name, pflags.name)
407 #ifdef TPM2_MODE
408     P(ownerAuthSet);
409     P(endorsementAuthSet);
410     P(lockoutAuthSet);
411     P(disableClear);
412     P(inLockout);
413     P(tpmGeneratedEPS);
414 #else
415     P(disable);
416     P(ownership);
417     P(deactivated);
418     P(readPubek);
419     P(disableOwnerClear);
420     P(allowMaintenance);
421     P(physicalPresenceLifetimeLock);
422     P(physicalPresenceHWEnable);
423     P(physicalPresenceCMDEnable);
424     P(CEKPUsed);
425     P(TPMpost);
426     P(TPMpostLock);
427     P(FIPS);
428     P(Operator);
429     P(enableRevokeEK);
430     P(nvLocked);
431     P(readSRKPub);
432     P(tpmEstablished);
433     P(maintenanceDone);
434     P(disableFullDALogicInfo);
435 #endif
436 #undef P
437   }
438   return result;
439 }
440 
HandlerGetSTClearFlags(void)441 static uint32_t HandlerGetSTClearFlags(void) {
442   TPM_STCLEAR_FLAGS vflags;
443   uint32_t result = TlclGetSTClearFlags(&vflags);
444   if (result == 0) {
445 #define P(name) printf("%s %d\n", #name, vflags.name)
446 #ifdef TPM2_MODE
447   P(phEnable);
448   P(shEnable);
449   P(ehEnable);
450   P(phEnableNV);
451   P(orderly);
452 #else
453   P(deactivated);
454   P(disableForceClear);
455   P(physicalPresence);
456   P(physicalPresenceLock);
457   P(bGlobalLock);
458 #endif
459 #undef P
460   }
461   return result;
462 }
463 
HandlerSendRaw(void)464 static uint32_t HandlerSendRaw(void) {
465   uint8_t request[4096];
466   uint8_t response[4096];
467   uint32_t result;
468   int size;
469   int i;
470   if (nargs == 2) {
471     fprintf(stderr, "usage: tpmc sendraw <hex byte 0> ... <hex byte N>\n");
472     exit(OTHER_ERROR);
473   }
474   for (i = 0; i < nargs - 2 && i < sizeof(request); i++) {
475     if (HexStringToUint8(args[2 + i], &request[i]) != 0) {
476       fprintf(stderr, "bad byte value \"%s\"\n", args[2 + i]);
477       exit(OTHER_ERROR);
478     }
479   }
480   size = TlclPacketSize(request);
481   if (size != i) {
482     fprintf(stderr, "bad request: size field is %d, but packet has %d bytes\n",
483             size, i);
484     exit(OTHER_ERROR);
485   }
486   bzero(response, sizeof(response));
487   result = TlclSendReceive(request, response, sizeof(response));
488   if (result != 0) {
489     fprintf(stderr, "request failed with code %d\n", result);
490   }
491   size = TlclPacketSize(response);
492   if (size < 10 || size > sizeof(response)) {
493     fprintf(stderr, "unexpected response size %d\n", size);
494     exit(OTHER_ERROR);
495   }
496   for (i = 0; i < size; i++) {
497     printf("0x%02x ", response[i]);
498     if (i == size - 1 || (i + 1) % 8 == 0) {
499       printf("\n");
500     }
501   }
502   return result;
503 }
504 
HandlerGetVersion(void)505 static uint32_t HandlerGetVersion(void) {
506   uint32_t vendor;
507   uint64_t firmware_version;
508   uint8_t vendor_specific[32];
509   size_t vendor_specific_size = sizeof(vendor_specific);
510   uint32_t result = TlclGetVersion(&vendor, &firmware_version, vendor_specific,
511                                    &vendor_specific_size);
512   if (result == 0) {
513     printf("vendor %08x\nfirmware_version %016" PRIx64 "\nvendor_specific ",
514            vendor, firmware_version);
515     size_t n;
516     for (n = 0; n < vendor_specific_size; ++n) {
517       printf("%02x", vendor_specific[n]);
518     }
519     printf("\n");
520   }
521   return result;
522 }
523 
524 #ifndef TPM2_MODE
PrintIFXFirmwarePackage(TPM_IFX_FIRMWAREPACKAGE * firmware_package,const char * prefix)525 static void PrintIFXFirmwarePackage(TPM_IFX_FIRMWAREPACKAGE* firmware_package,
526                                     const char* prefix) {
527   printf("%s_package_id %08x\n", prefix,
528          firmware_package->FwPackageIdentifier);
529   printf("%s_version %08x\n", prefix, firmware_package->Version);
530   printf("%s_stale_version %08x\n", prefix, firmware_package->StaleVersion);
531 }
532 
HandlerIFXFieldUpgradeInfo(void)533 static uint32_t HandlerIFXFieldUpgradeInfo(void) {
534   TPM_IFX_FIELDUPGRADEINFO info;
535   uint32_t result = TlclIFXFieldUpgradeInfo(&info);
536   if (result == 0) {
537     printf("max_data_size %u\n", info.wMaxDataSize);
538     PrintIFXFirmwarePackage(&info.sBootloaderFirmwarePackage, "bootloader");
539     PrintIFXFirmwarePackage(&info.sFirmwarePackages[0], "fw0");
540     PrintIFXFirmwarePackage(&info.sFirmwarePackages[1], "fw1");
541     printf("status %04x\n", info.wSecurityModuleStatus);
542     PrintIFXFirmwarePackage(&info.sProcessFirmwarePackage, "process_fw");
543     printf("field_upgrade_counter %u\n", info.wFieldUpgradeCounter);
544   }
545   return result;
546 }
547 
HandlerCheckOwnerAuth(void)548 static uint32_t HandlerCheckOwnerAuth(void) {
549   /* Attempt to define an NVRAM space using owner auth. We're using
550    * TPM_NV_INDEX_TRIAL, which doesn't actually allocate a space but still
551    * performs the owner authorization checks. Thus the return status indicates
552    * whether owner authorization was successful or not.
553    *
554    * The owner_auth value below is the commonly used well-known secret, i.e. the
555    * SHA1 hash of 20 zero bytes. This is the owner secret that is effective
556    * immediately after taking TPM ownership when we haven't configured a random
557    * owner password yet.
558    */
559   uint8_t owner_auth[TPM_AUTH_DATA_LEN] = {
560       0x67, 0x68, 0x03, 0x3e, 0x21, 0x64, 0x68, 0x24, 0x7b, 0xd0,
561       0x31, 0xa0, 0xa2, 0xd9, 0x87, 0x6d, 0x79, 0x81, 0x8f, 0x8f};
562   return TlclDefineSpaceEx(owner_auth, sizeof(owner_auth), TPM_NV_INDEX_TRIAL,
563                            TPM_NV_PER_OWNERWRITE, 1, NULL, 0);
564 }
565 #endif  /* !TPM2_MODE */
566 
567 #ifdef TPM2_MODE
HandlerDoNothingForTPM2(void)568 static uint32_t HandlerDoNothingForTPM2(void) {
569   return 0;
570 }
571 
HandlerNotImplementedForTPM2(void)572 static uint32_t HandlerNotImplementedForTPM2(void) {
573   fprintf(stderr, "%s: not implemented for TPM2.0\n", args[1]);
574   exit(OTHER_ERROR);
575 }
576 #endif
577 
578 /* Table of TPM commands.
579  */
580 command_record command_table[] = {
581   { "tpmversion", "tpmver", "print TPM version: 1.2 or 2.0",
582     HandlerTpmVersion },
583   { "getflags", "getf", "read and print the value of selected flags",
584     HandlerGetFlags },
585   { "startup", "sta", "issue a Startup command", TlclStartup },
586   { "selftestfull", "test", "issue a SelfTestFull command", TlclSelfTestFull },
587   { "continueselftest", "ctest", "issue a ContinueSelfTest command",
588     TlclContinueSelfTest },
589   { "assertphysicalpresence", "ppon",
590     TPM20_DOES_NOTHING("assert Physical Presence",
591       TlclAssertPhysicalPresence) },
592   { "physicalpresencecmdenable", "ppcmd",
593     TPM20_NOT_IMPLEMENTED("turn on software PP",
594       TlclPhysicalPresenceCMDEnable) },
595   { "enable", "ena",
596     TPM20_DOES_NOTHING("enable the TPM" TPM12_NEEDS_PP,
597       TlclSetEnable) },
598   { "disable", "dis",
599     TPM20_NOT_IMPLEMENTED("disable the TPM" TPM12_NEEDS_PP,
600       TlclClearEnable) },
601   { "activate", "act",
602     TPM20_DOES_NOTHING("activate the TPM" TPM12_NEEDS_PP_REBOOT,
603       HandlerActivate) },
604   { "deactivate", "deact",
605     TPM20_NOT_IMPLEMENTED("deactivate the TPM" TPM12_NEEDS_PP_REBOOT,
606       HandlerDeactivate) },
607   { "clear", "clr",
608     "clear the TPM owner" TPM12_NEEDS_PP,
609     TlclForceClear },
610   { "setnvlocked", "setnv",
611     TPM20_NOT_IMPLEMENTED("set the nvLocked flag permanently (IRREVERSIBLE!)",
612       TlclSetNvLocked) },
613   { "lockphysicalpresence", "pplock",
614     TPM_MODE_SELECT("lock (turn off) PP until reboot",
615       "set rollback protection lock for kernel image until reboot"),
616     TlclLockPhysicalPresence },
617   { "setbgloballock", "block",
618     TPM_MODE_SELECT("set the bGlobalLock until reboot",
619       "set rollback protection lock for R/W firmware until reboot"),
620     TlclSetGlobalLock },
621   { "definespace", "def",
622     TPM_MODE_SELECT("define a space (def <index> <size> <perm>). ",
623         "define a space (def <index> <size> <perm> [--no-overwrite]). ")
624       "Default will overwrite if the space is defined.",
625     HandlerDefineSpace },
626   { "undefinespace", "undef",
627     "undefine a space (undef <index>)"
628     TPM_MODE_SELECT(" only succeeds when NvLocked is not set", ""),
629     HandlerUndefineSpace },
630   { "write", "write", "write to a space (write <index> [<byte0> <byte1> ...])",
631     HandlerWrite },
632   { "read", "read", "read from a space (read <index> <size>)",
633     HandlerRead },
634   { "pcrread", "pcr", "read from a PCR (pcrread <index>)",
635     HandlerPCRRead },
636   { "pcrextend", "extend", "extend a PCR (extend <index> <extend_hash>)",
637     HandlerPCRExtend },
638   { "getownership", "geto", "print state of TPM ownership",
639     HandlerGetOwnership },
640   { "getpermissions", "getp", "print space permissions (getp <index>)",
641     HandlerGetPermissions },
642   { "getpermanentflags", "getpf", "print all permanent flags",
643     HandlerGetPermanentFlags },
644   { "getrandom", "rand", "read bytes from RNG (rand <size>)",
645     HandlerGetRandom },
646   { "getstclearflags", "getvf", "print all volatile (ST_CLEAR) flags",
647     HandlerGetSTClearFlags },
648   { "resume", "res", "execute TPM_Startup(ST_STATE)", TlclResume },
649   { "savestate", "save", "execute TPM_SaveState", TlclSaveState },
650   { "sendraw", "raw", "send a raw request and print raw response",
651     HandlerSendRaw },
652   { "getversion", "getver", "get TPM vendor and firmware version",
653     HandlerGetVersion },
654   { "ifxfieldupgradeinfo", "ifxfui",
655     TPM20_NOT_IMPLEMENTED("read and print IFX field upgrade info",
656       HandlerIFXFieldUpgradeInfo) },
657   { "checkownerauth", "chko",
658     TPM20_NOT_IMPLEMENTED("Check owner authorization with well-known secret",
659       HandlerCheckOwnerAuth) },
660 };
661 
662 static int n_commands = sizeof(command_table) / sizeof(command_table[0]);
663 
main(int argc,char * argv[])664 int main(int argc, char* argv[]) {
665   char *progname;
666   uint32_t result;
667 
668   progname = strrchr(argv[0], '/');
669   if (progname)
670     progname++;
671   else
672     progname = argv[0];
673 
674   if (argc < 2) {
675     fprintf(stderr, "usage: %s <TPM command> [args]\n   or: %s help\n",
676             progname, progname);
677     return OTHER_ERROR;
678   } else {
679     command_record* c;
680     const char* cmd = argv[1];
681     nargs = argc;
682     args = argv;
683 
684     if (strcmp(cmd, "help") == 0) {
685       printf("tpmc mode: TPM%s\n", TPM_MODE_STRING);
686       printf("%26s %7s  %s\n\n", "command", "abbr.", "description");
687       for (c = command_table; c < command_table + n_commands; c++) {
688         printf("%26s %7s  %s\n", c->name, c->abbr, c->description);
689       }
690       return 0;
691     }
692     if (!strcmp(cmd, "tpmversion") || !strcmp(cmd, "tpmver")) {
693       return HandlerTpmVersion();
694     }
695 
696     result = TlclLibInit();
697     if (result) {
698       fprintf(stderr, "initialization failed with code %d\n", result);
699       return result > OTHER_ERROR ? OTHER_ERROR : result;
700     }
701 
702     for (c = command_table; c < command_table + n_commands; c++) {
703       if (strcmp(cmd, c->name) == 0 || strcmp(cmd, c->abbr) == 0) {
704         return ErrorCheck(c->handler(), cmd);
705       }
706     }
707 
708     /* No command matched. */
709     fprintf(stderr, "%s: unknown command: %s\n", progname, cmd);
710     return OTHER_ERROR;
711   }
712 }
713