Home | History | Annotate | Download | only in utility
      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.
      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 <stdint.h>
     13 #include <stdlib.h>
     14 #include <stdio.h>
     15 #include <string.h>
     16 #include <syslog.h>
     17 
     18 #include "tlcl.h"
     19 #include "tpm_error_messages.h"
     20 #include "tss_constants.h"
     21 
     22 #define OTHER_ERROR 255  /* OTHER_ERROR must be the largest uint8_t value. */
     23 
     24 typedef struct command_record {
     25   const char* name;
     26   const char* abbr;
     27   const char* description;
     28   uint32_t (*handler)(void);
     29 } command_record;
     30 
     31 /* 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  */
     35 int nargs;
     36 char** 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  */
     41 int 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  */
     52 int 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.  Then returns min(result, OTHER_ERROR) since some error codes, such
     65  * as TPM_E_RETRY, do not fit in a byte.
     66  */
     67 uint8_t ErrorCheck(uint32_t result, const char* cmd) {
     68   uint8_t exit_code = result > OTHER_ERROR ? OTHER_ERROR : result;
     69   if (result == 0) {
     70     return 0;
     71   } else {
     72     int i;
     73     int n = sizeof(tpm_error_table) / sizeof(tpm_error_table[0]);
     74     fprintf(stderr, "command \"%s\" failed with code 0x%x\n", cmd, result);
     75     for (i = 0; i < n; i++) {
     76       if (tpm_error_table[i].code == result) {
     77         fprintf(stderr, "%s\n%s\n", tpm_error_table[i].name,
     78                 tpm_error_table[i].description);
     79         return exit_code;
     80       }
     81     }
     82     fprintf(stderr, "the TPM error code is unknown to this program\n");
     83     return exit_code;
     84   }
     85 }
     86 
     87 /* Handler functions.  These wouldn't exist if C had closures.
     88  */
     89 static uint32_t HandlerGetFlags(void) {
     90   uint8_t disabled;
     91   uint8_t deactivated;
     92   uint8_t nvlocked;
     93   uint32_t result = TlclGetFlags(&disabled, &deactivated, &nvlocked);
     94   if (result == 0) {
     95     printf("disabled: %d\ndeactivated: %d\nnvlocked: %d\n",
     96            disabled, deactivated, nvlocked);
     97   }
     98   return result;
     99 }
    100 
    101 static uint32_t HandlerActivate(void) {
    102   return TlclSetDeactivated(0);
    103 }
    104 
    105 static uint32_t HandlerDeactivate(void) {
    106   return TlclSetDeactivated(1);
    107 }
    108 
    109 static uint32_t HandlerDefineSpace(void) {
    110   uint32_t index, size, perm;
    111   if (nargs != 5) {
    112     fprintf(stderr, "usage: tpmc def <index> <size> <perm>\n");
    113     exit(OTHER_ERROR);
    114   }
    115   if (HexStringToUint32(args[2], &index) != 0 ||
    116       HexStringToUint32(args[3], &size) != 0 ||
    117       HexStringToUint32(args[4], &perm) != 0) {
    118     fprintf(stderr, "<index>, <size>, and <perm> must be "
    119             "32-bit hex (0x[0-9a-f]+)\n");
    120     exit(OTHER_ERROR);
    121   }
    122   return TlclDefineSpace(index, perm, size);
    123 }
    124 
    125 static uint32_t HandlerWrite(void) {
    126   uint32_t index, size;
    127   uint8_t value[TPM_MAX_COMMAND_SIZE];
    128   char** byteargs;
    129   int i;
    130   if (nargs < 3) {
    131     fprintf(stderr, "usage: tpmc write <index> [<byte0> <byte1> ...]\n");
    132     exit(OTHER_ERROR);
    133   }
    134   if (HexStringToUint32(args[2], &index) != 0) {
    135     fprintf(stderr, "<index> must be 32-bit hex (0x[0-9a-f]+)\n");
    136     exit(OTHER_ERROR);
    137   }
    138   size = nargs - 3;
    139   if (size > sizeof(value)) {
    140     fprintf(stderr, "byte array too large\n");
    141     exit(OTHER_ERROR);
    142   }
    143 
    144   byteargs = args + 3;
    145   for (i = 0; i < size; i++) {
    146     if (HexStringToUint8(byteargs[i], &value[i]) != 0) {
    147       fprintf(stderr, "invalid byte %s, should be [0-9a-f][0-9a-f]?\n",
    148               byteargs[i]);
    149       exit(OTHER_ERROR);
    150     }
    151   }
    152 
    153   if (size == 0) {
    154     if (index == TPM_NV_INDEX_LOCK) {
    155       fprintf(stderr, "This would set the nvLocked bit. "
    156               "Use \"tpmc setnv\" instead.\n");
    157       exit(OTHER_ERROR);
    158     }
    159     printf("warning: zero-length write\n");
    160   } else {
    161     printf("writing %d byte%s\n", size, size > 1 ? "s" : "");
    162   }
    163 
    164   return TlclWrite(index, value, size);
    165 }
    166 
    167 static uint32_t HandlerPCRRead(void) {
    168   uint32_t index;
    169   uint8_t value[TPM_PCR_DIGEST];
    170   uint32_t result;
    171   int i;
    172   if (nargs != 3) {
    173     fprintf(stderr, "usage: tpmc pcrread <index>\n");
    174     exit(OTHER_ERROR);
    175   }
    176   if (HexStringToUint32(args[2], &index) != 0) {
    177     fprintf(stderr, "<index> must be 32-bit hex (0x[0-9a-f]+)\n");
    178     exit(OTHER_ERROR);
    179   }
    180   result = TlclPCRRead(index, value, sizeof(value));
    181   if (result == 0) {
    182     for (i = 0; i < TPM_PCR_DIGEST; i++) {
    183       printf("%02x", value[i]);
    184     }
    185     printf("\n");
    186   }
    187   return result;
    188 }
    189 
    190 static uint32_t HandlerRead(void) {
    191   uint32_t index, size;
    192   uint8_t value[4096];
    193   uint32_t result;
    194   int i;
    195   if (nargs != 4) {
    196     fprintf(stderr, "usage: tpmc read <index> <size>\n");
    197     exit(OTHER_ERROR);
    198   }
    199   if (HexStringToUint32(args[2], &index) != 0 ||
    200       HexStringToUint32(args[3], &size) != 0) {
    201     fprintf(stderr, "<index> and <size> must be 32-bit hex (0x[0-9a-f]+)\n");
    202     exit(OTHER_ERROR);
    203   }
    204   if (size > sizeof(value)) {
    205     fprintf(stderr, "size of read (0x%x) is too big\n", size);
    206     exit(OTHER_ERROR);
    207   }
    208   result = TlclRead(index, value, size);
    209   if (result == 0 && size > 0) {
    210     for (i = 0; i < size - 1; i++) {
    211       printf("%x ", value[i]);
    212     }
    213     printf("%x\n", value[i]);
    214   }
    215   return result;
    216 }
    217 
    218 static uint32_t HandlerGetPermissions(void) {
    219   uint32_t index, permissions, result;
    220   if (nargs != 3) {
    221     fprintf(stderr, "usage: tpmc getp <index>\n");
    222     exit(OTHER_ERROR);
    223   }
    224   if (HexStringToUint32(args[2], &index) != 0) {
    225     fprintf(stderr, "<index> must be 32-bit hex (0x[0-9a-f]+)\n");
    226     exit(OTHER_ERROR);
    227   }
    228   result = TlclGetPermissions(index, &permissions);
    229   if (result == 0) {
    230     printf("space 0x%x has permissions 0x%x\n", index, permissions);
    231   }
    232   return result;
    233 }
    234 
    235 static uint32_t HandlerGetOwnership(void) {
    236   uint8_t owned = 0;
    237   uint32_t result;
    238   if (nargs != 2) {
    239     fprintf(stderr, "usage: tpmc getownership\n");
    240     exit(OTHER_ERROR);
    241   }
    242   result = TlclGetOwnership(&owned);
    243   if (result == 0) {
    244     printf("Owned: %s\n", owned ? "yes" : "no");
    245   }
    246   return result;
    247 }
    248 
    249 static uint32_t HandlerGetRandom(void) {
    250   uint32_t length, size;
    251   uint8_t* bytes;
    252   uint32_t result;
    253   int i;
    254   if (nargs != 3) {
    255     fprintf(stderr, "usage: tpmc getrandom <size>\n");
    256     exit(OTHER_ERROR);
    257   }
    258   if (HexStringToUint32(args[2], &length) != 0) {
    259     fprintf(stderr, "<size> must be 32-bit hex (0x[0-9a-f]+)\n");
    260     exit(OTHER_ERROR);
    261   }
    262   bytes = calloc(1, length);
    263   if (bytes == NULL) {
    264     perror("calloc");
    265     exit(OTHER_ERROR);
    266   }
    267   result = TlclGetRandom(bytes, length, &size);
    268   if (result == 0 && size > 0) {
    269     for (i = 0; i < size; i++) {
    270       printf("%02x", bytes[i]);
    271     }
    272     printf("\n");
    273   }
    274   free(bytes);
    275   return result;
    276 }
    277 
    278 static uint32_t HandlerGetPermanentFlags(void) {
    279   TPM_PERMANENT_FLAGS pflags;
    280   uint32_t result = TlclGetPermanentFlags(&pflags);
    281   if (result == 0) {
    282 #define P(name) printf("%s %d\n", #name, pflags.name)
    283     P(disable);
    284     P(ownership);
    285     P(deactivated);
    286     P(readPubek);
    287     P(disableOwnerClear);
    288     P(allowMaintenance);
    289     P(physicalPresenceLifetimeLock);
    290     P(physicalPresenceHWEnable);
    291     P(physicalPresenceCMDEnable);
    292     P(CEKPUsed);
    293     P(TPMpost);
    294     P(TPMpostLock);
    295     P(FIPS);
    296     P(Operator);
    297     P(enableRevokeEK);
    298     P(nvLocked);
    299     P(readSRKPub);
    300     P(tpmEstablished);
    301     P(maintenanceDone);
    302     P(disableFullDALogicInfo);
    303 #undef P
    304   }
    305   return result;
    306 }
    307 
    308 static uint32_t HandlerGetSTClearFlags(void) {
    309   TPM_STCLEAR_FLAGS vflags;
    310   uint32_t result = TlclGetSTClearFlags(&vflags);
    311   if (result == 0) {
    312 #define P(name) printf("%s %d\n", #name, vflags.name)
    313   P(deactivated);
    314   P(disableForceClear);
    315   P(physicalPresence);
    316   P(physicalPresenceLock);
    317   P(bGlobalLock);
    318 #undef P
    319   }
    320   return result;
    321 }
    322 
    323 
    324 static uint32_t HandlerSendRaw(void) {
    325   uint8_t request[4096];
    326   uint8_t response[4096];
    327   uint32_t result;
    328   int size;
    329   int i;
    330   if (nargs == 2) {
    331     fprintf(stderr, "usage: tpmc sendraw <hex byte 0> ... <hex byte N>\n");
    332     exit(OTHER_ERROR);
    333   }
    334   for (i = 0; i < nargs - 2 && i < sizeof(request); i++) {
    335     if (HexStringToUint8(args[2 + i], &request[i]) != 0) {
    336       fprintf(stderr, "bad byte value \"%s\"\n", args[2 + i]);
    337       exit(OTHER_ERROR);
    338     }
    339   }
    340   size = TlclPacketSize(request);
    341   if (size != i) {
    342     fprintf(stderr, "bad request: size field is %d, but packet has %d bytes\n",
    343             size, i);
    344     exit(OTHER_ERROR);
    345   }
    346   bzero(response, sizeof(response));
    347   result = TlclSendReceive(request, response, sizeof(response));
    348   if (result != 0) {
    349     fprintf(stderr, "request failed with code %d\n", result);
    350   }
    351   size = TlclPacketSize(response);
    352   if (size < 10 || size > sizeof(response)) {
    353     fprintf(stderr, "unexpected response size %d\n", size);
    354     exit(OTHER_ERROR);
    355   }
    356   for (i = 0; i < size; i++) {
    357     printf("0x%02x ", response[i]);
    358     if (i == size - 1 || (i + 1) % 8 == 0) {
    359       printf("\n");
    360     }
    361   }
    362   return result;
    363 }
    364 
    365 
    366 /* Table of TPM commands.
    367  */
    368 command_record command_table[] = {
    369   { "getflags", "getf", "read and print the value of selected flags",
    370     HandlerGetFlags },
    371   { "startup", "sta", "issue a Startup command", TlclStartup },
    372   { "selftestfull", "test", "issue a SelfTestFull command", TlclSelfTestFull },
    373   { "continueselftest", "ctest", "issue a ContinueSelfTest command",
    374     TlclContinueSelfTest },
    375   { "assertphysicalpresence", "ppon", "assert Physical Presence",
    376     TlclAssertPhysicalPresence },
    377   { "physicalpresencecmdenable", "ppcmd", "turn on software PP",
    378     TlclPhysicalPresenceCMDEnable },
    379   { "enable", "ena", "enable the TPM (needs PP)", TlclSetEnable },
    380   { "disable", "dis", "disable the TPM (needs PP)", TlclClearEnable },
    381   { "activate", "act", "activate the TPM (needs PP, maybe reboot)",
    382     HandlerActivate },
    383   { "deactivate", "deact", "deactivate the TPM (needs PP, maybe reboot)",
    384     HandlerDeactivate },
    385   { "clear", "clr", "clear the TPM owner (needs PP)", TlclForceClear },
    386   { "setnvlocked", "setnv", "set the nvLocked flag permanently (IRREVERSIBLE!)",
    387     TlclSetNvLocked },
    388   { "lockphysicalpresence", "pplock", "lock (turn off) PP until reboot",
    389     TlclLockPhysicalPresence },
    390   { "setbgloballock", "block", "set the bGlobalLock until reboot",
    391     TlclSetGlobalLock },
    392   { "definespace", "def", "define a space (def <index> <size> <perm>)",
    393     HandlerDefineSpace },
    394   { "write", "write", "write to a space (write <index> [<byte0> <byte1> ...])",
    395     HandlerWrite },
    396   { "read", "read", "read from a space (read <index> <size>)",
    397     HandlerRead },
    398   { "pcrread", "pcr", "read from a PCR (pcrread <index>)",
    399     HandlerPCRRead },
    400   { "getownership", "geto", "print state of TPM ownership",
    401     HandlerGetOwnership },
    402   { "getpermissions", "getp", "print space permissions (getp <index>)",
    403     HandlerGetPermissions },
    404   { "getpermanentflags", "getpf", "print all permanent flags",
    405     HandlerGetPermanentFlags },
    406   { "getrandom", "rand", "read bytes from RNG (rand <size>)",
    407     HandlerGetRandom },
    408   { "getstclearflags", "getvf", "print all volatile (ST_CLEAR) flags",
    409     HandlerGetSTClearFlags },
    410   { "resume", "res", "execute TPM_Startup(ST_STATE)", TlclResume },
    411   { "savestate", "save", "execute TPM_SaveState", TlclSaveState },
    412   { "sendraw", "raw", "send a raw request and print raw response",
    413     HandlerSendRaw },
    414 };
    415 
    416 static int n_commands = sizeof(command_table) / sizeof(command_table[0]);
    417 
    418 int main(int argc, char* argv[]) {
    419   char *progname;
    420   progname = strrchr(argv[0], '/');
    421   if (progname)
    422     progname++;
    423   else
    424     progname = argv[0];
    425 
    426   if (argc < 2) {
    427     fprintf(stderr, "usage: %s <TPM command> [args]\n   or: %s help\n",
    428             progname, progname);
    429     return OTHER_ERROR;
    430   } else {
    431     command_record* c;
    432     const char* cmd = argv[1];
    433     nargs = argc;
    434     args = argv;
    435 
    436     if (strcmp(cmd, "help") == 0) {
    437       printf("%26s %7s  %s\n\n", "command", "abbr.", "description");
    438       for (c = command_table; c < command_table + n_commands; c++) {
    439         printf("%26s %7s  %s\n", c->name, c->abbr, c->description);
    440       }
    441       return 0;
    442     }
    443 
    444     TlclLibInit();
    445 
    446     for (c = command_table; c < command_table + n_commands; c++) {
    447       if (strcmp(cmd, c->name) == 0 || strcmp(cmd, c->abbr) == 0) {
    448         return ErrorCheck(c->handler(), cmd);
    449       }
    450     }
    451 
    452     /* No command matched. */
    453     fprintf(stderr, "%s: unknown command: %s\n", progname, cmd);
    454     return OTHER_ERROR;
    455   }
    456 }
    457