tpm2_getcap.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856
  1. /* SPDX-License-Identifier: BSD-3-Clause */
  2. #include <ctype.h>
  3. #include <stdbool.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include "log.h"
  8. #include "pcr.h"
  9. #include "tpm2_alg_util.h"
  10. #include "tpm2_capability.h"
  11. #include "tpm2_cc_util.h"
  12. #include "tpm2_tool.h"
  13. /*
  14. * Older versions of tpm2-tss misspelled these constants' names.
  15. * See https://github.com/tpm2-software/tpm2-tss/issues/1500.
  16. */
  17. #ifndef TPM2_PT_HR_TRANSIENT_MIN
  18. #define TPM2_PT_HR_TRANSIENT_MIN ((TPM2_PT) (TPM2_PT_FIXED + 14))
  19. #define TPM2_PT_HR_PERSISTENT_MIN ((TPM2_PT) (TPM2_PT_FIXED + 15))
  20. #define TPM2_PT_HR_NV_INDEX ((TPM2_PT) (TPM2_PT_VAR + 2))
  21. #define TPM2_PT_HR_TRANSIENT_AVAIL ((TPM2_PT) (TPM2_PT_VAR + 7))
  22. #define TPM2_PT_HR_PERSISTENT ((TPM2_PT) (TPM2_PT_VAR + 8))
  23. #define TPM2_PT_HR_PERSISTENT_AVAIL ((TPM2_PT) (TPM2_PT_VAR + 9))
  24. #endif
  25. /* convenience macro to convert flags into "1" / "0" strings */
  26. #define prop_str(val) val ? "1" : "0"
  27. /* number of elements in the capability_map array */
  28. #define CAPABILITY_MAP_COUNT \
  29. (sizeof (capability_map) / sizeof (capability_map_entry_t))
  30. /* Structure to map a string to the appropriate TPM2_CAP / TPM2_PT pair */
  31. typedef struct capability_map_entry {
  32. char *capability_string;
  33. TPM2_CAP capability;
  34. UINT32 property;
  35. UINT32 count;
  36. } capability_map_entry_t;
  37. /*
  38. * Array of structures for use as a lookup table to map string representation
  39. * of a capability to the proper TPM2_CAP / TPM2_PT pair.
  40. */
  41. capability_map_entry_t capability_map[] = {
  42. {
  43. .capability_string = "algorithms",
  44. .capability = TPM2_CAP_ALGS,
  45. .property = TPM2_ALG_FIRST,
  46. .count = TPM2_MAX_CAP_ALGS,
  47. },
  48. {
  49. .capability_string = "commands",
  50. .capability = TPM2_CAP_COMMANDS,
  51. .property = TPM2_CC_FIRST,
  52. .count = TPM2_MAX_CAP_CC,
  53. },
  54. {
  55. .capability_string = "pcrs",
  56. .capability = TPM2_CAP_PCRS,
  57. .property = 0,
  58. .count = TPM2_MAX_TPM_PROPERTIES,
  59. },
  60. {
  61. .capability_string = "properties-fixed",
  62. .capability = TPM2_CAP_TPM_PROPERTIES,
  63. .property = TPM2_PT_FIXED,
  64. .count = TPM2_MAX_TPM_PROPERTIES,
  65. },
  66. {
  67. .capability_string = "properties-variable",
  68. .capability = TPM2_CAP_TPM_PROPERTIES,
  69. .property = TPM2_PT_VAR,
  70. .count = TPM2_MAX_TPM_PROPERTIES,
  71. },
  72. {
  73. .capability_string = "ecc-curves",
  74. .capability = TPM2_CAP_ECC_CURVES,
  75. .property = TPM2_ECC_NIST_P192,
  76. .count = TPM2_MAX_ECC_CURVES,
  77. },
  78. {
  79. .capability_string = "handles-transient",
  80. .capability = TPM2_CAP_HANDLES,
  81. .property = TPM2_TRANSIENT_FIRST,
  82. .count = TPM2_MAX_CAP_HANDLES,
  83. },
  84. {
  85. .capability_string = "handles-persistent",
  86. .capability = TPM2_CAP_HANDLES,
  87. .property = TPM2_PERSISTENT_FIRST,
  88. .count = TPM2_MAX_CAP_HANDLES,
  89. },
  90. {
  91. .capability_string = "handles-permanent",
  92. .capability = TPM2_CAP_HANDLES,
  93. .property = TPM2_PERMANENT_FIRST,
  94. .count = TPM2_MAX_CAP_HANDLES,
  95. },
  96. {
  97. .capability_string = "handles-pcr",
  98. .capability = TPM2_CAP_HANDLES,
  99. .property = TPM2_PCR_FIRST,
  100. .count = TPM2_MAX_CAP_HANDLES,
  101. },
  102. {
  103. .capability_string = "handles-nv-index",
  104. .capability = TPM2_CAP_HANDLES,
  105. .property = TPM2_NV_INDEX_FIRST,
  106. .count = TPM2_MAX_CAP_HANDLES,
  107. },
  108. {
  109. .capability_string = "handles-loaded-session",
  110. .capability = TPM2_CAP_HANDLES,
  111. .property = TPM2_LOADED_SESSION_FIRST,
  112. .count = TPM2_MAX_CAP_HANDLES,
  113. },
  114. {
  115. .capability_string = "handles-saved-session",
  116. .capability = TPM2_CAP_HANDLES,
  117. .property = TPM2_ACTIVE_SESSION_FIRST,
  118. .count = TPM2_MAX_CAP_HANDLES,
  119. },
  120. };
  121. /*
  122. * Structure to hold options for this tool.
  123. */
  124. typedef struct capability_opts {
  125. char *capability_string;
  126. TPM2_CAP capability;
  127. UINT32 property;
  128. UINT32 count;
  129. bool list;
  130. } capability_opts_t;
  131. static capability_opts_t options;
  132. /*
  133. * This function uses the 'capability_string' field in the capabilities_opts
  134. * structure to locate the same string in the capability_map array and then
  135. * populates the 'capability' and 'property' fields of the capability_opts_t
  136. * structure with the appropriate values from the capability_map.
  137. * Return values:
  138. * true - the function executed normally.
  139. * false - no matching entry found in capability_map.
  140. */
  141. bool sanity_check_capability_opts(void) {
  142. if (options.capability_string == NULL) {
  143. LOG_ERR("missing capability string, see --help");
  144. return false;
  145. }
  146. size_t i;
  147. for (i = 0; i < CAPABILITY_MAP_COUNT; ++i) {
  148. int cmp = strcmp(capability_map[i].capability_string,
  149. options.capability_string);
  150. if (cmp == 0) {
  151. options.capability = capability_map[i].capability;
  152. options.property = capability_map[i].property;
  153. options.count = capability_map[i].count;
  154. return true;
  155. }
  156. }
  157. LOG_ERR("invalid capability string: %s, see --help",
  158. options.capability_string);
  159. return false;
  160. }
  161. static void print_cap_map() {
  162. size_t i;
  163. for (i = 0; i < CAPABILITY_MAP_COUNT; ++i) {
  164. const char *capstr = capability_map[i].capability_string;
  165. tpm2_tool_output("- %s\n", capstr);
  166. }
  167. }
  168. /*
  169. * There are a number of fixed TPM properties (tagged properties) that are
  170. * characters (8bit chars) packed into 32bit integers, trim leading and trailing spaces
  171. */
  172. static char *
  173. get_uint32_as_chars(UINT32 value) {
  174. static char buf[5];
  175. value = tpm2_util_ntoh_32(value);
  176. UINT8 *bytes = (UINT8 *) &value;
  177. /*
  178. * move the start of the string to the beginning
  179. * first non space character
  180. * Record the number of skips in i.
  181. */
  182. unsigned i;
  183. for (i = 0; i < sizeof(value); i++) {
  184. UINT8 b = *bytes;
  185. if (!isspace(b)) {
  186. break;
  187. }
  188. bytes++;
  189. }
  190. /* record the number of trailing spaces in j */
  191. unsigned j;
  192. for (j = sizeof(value) - i; j > i; j--) {
  193. UINT8 b = bytes[j - 1];
  194. /* NULL bytes count as space */
  195. if (b && !isspace(b)) {
  196. break;
  197. }
  198. }
  199. memcpy(buf, bytes, j);
  200. buf[j] = '\0';
  201. return buf;
  202. }
  203. /*
  204. * Print string representations of the TPMA_MODES.
  205. */
  206. static void tpm2_tool_output_tpma_modes(TPMA_MODES modes) {
  207. tpm2_tool_output("TPM2_PT_MODES:\n"
  208. " raw: 0x%X\n", modes);
  209. if (modes & TPMA_MODES_FIPS_140_2)
  210. tpm2_tool_output(" value: TPMA_MODES_FIPS_140_2\n");
  211. if (modes & TPMA_MODES_RESERVED1_MASK)
  212. tpm2_tool_output(
  213. " value: TPMA_MODES_RESERVED1 (these bits shouldn't be set)\n");
  214. }
  215. /*
  216. * Print string representation of the TPMA_PERMANENT attributes.
  217. */
  218. static void dump_permanent_attrs(TPMA_PERMANENT attrs) {
  219. tpm2_tool_output("TPM2_PT_PERSISTENT:\n");
  220. tpm2_tool_output(" ownerAuthSet: %s\n",
  221. prop_str (attrs & TPMA_PERMANENT_OWNERAUTHSET));
  222. tpm2_tool_output(" endorsementAuthSet: %s\n",
  223. prop_str (attrs & TPMA_PERMANENT_ENDORSEMENTAUTHSET));
  224. tpm2_tool_output(" lockoutAuthSet: %s\n",
  225. prop_str (attrs & TPMA_PERMANENT_LOCKOUTAUTHSET));
  226. tpm2_tool_output(" reserved1: %s\n",
  227. prop_str (attrs & TPMA_PERMANENT_RESERVED1_MASK));
  228. tpm2_tool_output(" disableClear: %s\n",
  229. prop_str (attrs & TPMA_PERMANENT_DISABLECLEAR));
  230. tpm2_tool_output(" inLockout: %s\n",
  231. prop_str (attrs & TPMA_PERMANENT_INLOCKOUT));
  232. tpm2_tool_output(" tpmGeneratedEPS: %s\n",
  233. prop_str (attrs & TPMA_PERMANENT_TPMGENERATEDEPS));
  234. tpm2_tool_output(" reserved2: %s\n",
  235. prop_str (attrs & TPMA_PERMANENT_RESERVED2_MASK));
  236. }
  237. /*
  238. * Print string representations of the TPMA_STARTUP_CLEAR attributes.
  239. */
  240. static void dump_startup_clear_attrs(TPMA_STARTUP_CLEAR attrs) {
  241. tpm2_tool_output("TPM2_PT_STARTUP_CLEAR:\n");
  242. tpm2_tool_output(" phEnable: %s\n",
  243. prop_str (attrs & TPMA_STARTUP_CLEAR_PHENABLE));
  244. tpm2_tool_output(" shEnable: %s\n",
  245. prop_str (attrs & TPMA_STARTUP_CLEAR_SHENABLE));
  246. tpm2_tool_output(" ehEnable: %s\n",
  247. prop_str (attrs & TPMA_STARTUP_CLEAR_EHENABLE));;
  248. tpm2_tool_output(" phEnableNV: %s\n",
  249. prop_str (attrs & TPMA_STARTUP_CLEAR_PHENABLENV));
  250. tpm2_tool_output(" reserved1: %s\n",
  251. prop_str (attrs & TPMA_STARTUP_CLEAR_RESERVED1_MASK));
  252. tpm2_tool_output(" orderly: %s\n",
  253. prop_str (attrs & TPMA_STARTUP_CLEAR_ORDERLY));
  254. }
  255. /*
  256. * Iterate over all fixed properties, call the unique print function for each.
  257. */
  258. static void dump_tpm_properties_fixed(TPMS_TAGGED_PROPERTY properties[],
  259. size_t count) {
  260. size_t i;
  261. char *buf;
  262. for (i = 0; i < count; ++i) {
  263. TPM2_PT property = properties[i].property;
  264. UINT32 value = properties[i].value;
  265. switch (property) {
  266. case TPM2_PT_FAMILY_INDICATOR:
  267. buf = get_uint32_as_chars(value);
  268. tpm2_tool_output("TPM2_PT_FAMILY_INDICATOR:\n"
  269. " raw: 0x%X\n"
  270. " value: \"%s\"\n", value, buf);
  271. break;
  272. case TPM2_PT_LEVEL:
  273. tpm2_tool_output("TPM2_PT_LEVEL:\n"
  274. " raw: %d\n", value);
  275. break;
  276. case TPM2_PT_REVISION:
  277. tpm2_tool_output("TPM2_PT_REVISION:\n"
  278. " raw: 0x%X\n"
  279. " value: %.2f\n", value, (float )value / 100);
  280. break;
  281. case TPM2_PT_DAY_OF_YEAR:
  282. tpm2_tool_output("TPM2_PT_DAY_OF_YEAR:\n"
  283. " raw: 0x%X\n", value);
  284. break;
  285. case TPM2_PT_YEAR:
  286. tpm2_tool_output("TPM2_PT_YEAR:\n"
  287. " raw: 0x%X\n", value);
  288. break;
  289. case TPM2_PT_MANUFACTURER: {
  290. UINT32 he_value = tpm2_util_ntoh_32(value);
  291. tpm2_tool_output("TPM2_PT_MANUFACTURER:\n"
  292. " raw: 0x%X\n"
  293. " value: \"%.*s\"\n", value, (int )sizeof(value),
  294. (char * )&he_value);
  295. }
  296. break;
  297. case TPM2_PT_VENDOR_STRING_1:
  298. buf = get_uint32_as_chars(value);
  299. tpm2_tool_output("TPM2_PT_VENDOR_STRING_1:\n"
  300. " raw: 0x%X\n"
  301. " value: \"%s\"\n", value, buf);
  302. break;
  303. case TPM2_PT_VENDOR_STRING_2:
  304. buf = get_uint32_as_chars(value);
  305. tpm2_tool_output("TPM2_PT_VENDOR_STRING_2:\n"
  306. " raw: 0x%X\n"
  307. " value: \"%s\"\n", value, buf);
  308. break;
  309. case TPM2_PT_VENDOR_STRING_3:
  310. buf = get_uint32_as_chars(value);
  311. tpm2_tool_output("TPM2_PT_VENDOR_STRING_3:\n"
  312. " raw: 0x%X\n"
  313. " value: \"%s\"\n", value, buf);
  314. break;
  315. case TPM2_PT_VENDOR_STRING_4:
  316. buf = get_uint32_as_chars(value);
  317. tpm2_tool_output("TPM2_PT_VENDOR_STRING_4:\n"
  318. " raw: 0x%X\n"
  319. " value: \"%s\"\n", value, buf);
  320. break;
  321. case TPM2_PT_VENDOR_TPM_TYPE:
  322. tpm2_tool_output("TPM2_PT_VENDOR_TPM_TYPE:\n"
  323. " raw: 0x%X\n", value);
  324. break;
  325. case TPM2_PT_FIRMWARE_VERSION_1:
  326. tpm2_tool_output("TPM2_PT_FIRMWARE_VERSION_1:\n"
  327. " raw: 0x%X\n", value);
  328. break;
  329. case TPM2_PT_FIRMWARE_VERSION_2:
  330. tpm2_tool_output("TPM2_PT_FIRMWARE_VERSION_2:\n"
  331. " raw: 0x%X\n", value);
  332. break;
  333. case TPM2_PT_INPUT_BUFFER:
  334. tpm2_tool_output("TPM2_PT_INPUT_BUFFER:\n"
  335. " raw: 0x%X\n", value);
  336. break;
  337. case TPM2_PT_HR_TRANSIENT_MIN:
  338. tpm2_tool_output("TPM2_PT_HR_TRANSIENT_MIN:\n"
  339. " raw: 0x%X\n", value);
  340. break;
  341. case TPM2_PT_HR_PERSISTENT_MIN:
  342. tpm2_tool_output("TPM2_PT_HR_PERSISTENT_MIN:\n"
  343. " raw: 0x%X\n", value);
  344. break;
  345. case TPM2_PT_HR_LOADED_MIN:
  346. tpm2_tool_output("TPM2_PT_HR_LOADED_MIN:\n"
  347. " raw: 0x%X\n", value);
  348. break;
  349. case TPM2_PT_ACTIVE_SESSIONS_MAX:
  350. tpm2_tool_output("TPM2_PT_ACTIVE_SESSIONS_MAX:\n"
  351. " raw: 0x%X\n", value);
  352. break;
  353. case TPM2_PT_PCR_COUNT:
  354. tpm2_tool_output("TPM2_PT_PCR_COUNT:\n"
  355. " raw: 0x%X\n", value);
  356. break;
  357. case TPM2_PT_PCR_SELECT_MIN:
  358. tpm2_tool_output("TPM2_PT_PCR_SELECT_MIN:\n"
  359. " raw: 0x%X\n", value);
  360. break;
  361. case TPM2_PT_CONTEXT_GAP_MAX:
  362. tpm2_tool_output("TPM2_PT_CONTEXT_GAP_MAX:\n"
  363. " raw: 0x%X\n", value);
  364. break;
  365. case TPM2_PT_NV_COUNTERS_MAX:
  366. tpm2_tool_output("TPM2_PT_NV_COUNTERS_MAX:\n"
  367. " raw: 0x%X\n", value);
  368. break;
  369. case TPM2_PT_NV_INDEX_MAX:
  370. tpm2_tool_output("TPM2_PT_NV_INDEX_MAX:\n"
  371. " raw: 0x%X\n", value);
  372. break;
  373. case TPM2_PT_MEMORY:
  374. tpm2_tool_output("TPM2_PT_MEMORY:\n"
  375. " raw: 0x%X\n", value);
  376. break;
  377. case TPM2_PT_CLOCK_UPDATE:
  378. tpm2_tool_output("TPM2_PT_CLOCK_UPDATE:\n"
  379. " raw: 0x%X\n", value);
  380. break;
  381. case TPM2_PT_CONTEXT_HASH: /* this may be a TPM2_ALG_ID type */
  382. tpm2_tool_output("TPM2_PT_CONTEXT_HASH:\n"
  383. " raw: 0x%X\n", value);
  384. break;
  385. case TPM2_PT_CONTEXT_SYM: /* this is a TPM2_ALG_ID type */
  386. tpm2_tool_output("TPM2_PT_CONTEXT_SYM:\n"
  387. " raw: 0x%X\n", value);
  388. break;
  389. case TPM2_PT_CONTEXT_SYM_SIZE:
  390. tpm2_tool_output("TPM2_PT_CONTEXT_SYM_SIZE:\n"
  391. " raw: 0x%X\n", value);
  392. break;
  393. case TPM2_PT_ORDERLY_COUNT:
  394. tpm2_tool_output("TPM2_PT_ORDERLY_COUNT:\n"
  395. " raw: 0x%X\n", value);
  396. break;
  397. case TPM2_PT_MAX_COMMAND_SIZE:
  398. tpm2_tool_output("TPM2_PT_MAX_COMMAND_SIZE:\n"
  399. " raw: 0x%X\n", value);
  400. break;
  401. case TPM2_PT_MAX_RESPONSE_SIZE:
  402. tpm2_tool_output("TPM2_PT_MAX_RESPONSE_SIZE:\n"
  403. " raw: 0x%X\n", value);
  404. break;
  405. case TPM2_PT_MAX_DIGEST:
  406. tpm2_tool_output("TPM2_PT_MAX_DIGEST:\n"
  407. " raw: 0x%X\n", value);
  408. break;
  409. case TPM2_PT_MAX_OBJECT_CONTEXT:
  410. tpm2_tool_output("TPM2_PT_MAX_OBJECT_CONTEXT:\n"
  411. " raw: 0x%X\n", value);
  412. break;
  413. case TPM2_PT_MAX_SESSION_CONTEXT:
  414. tpm2_tool_output("TPM2_PT_MAX_SESSION_CONTEXT:\n"
  415. " raw: 0x%X\n", value);
  416. break;
  417. case TPM2_PT_PS_FAMILY_INDICATOR:
  418. tpm2_tool_output("TPM2_PT_PS_FAMILY_INDICATOR:\n"
  419. " raw: 0x%X\n", value);
  420. break;
  421. case TPM2_PT_PS_LEVEL:
  422. tpm2_tool_output("TPM2_PT_PS_LEVEL:\n"
  423. " raw: 0x%X\n", value);
  424. break;
  425. case TPM2_PT_PS_REVISION:
  426. tpm2_tool_output("TPM2_PT_PS_REVISION:\n"
  427. " raw: 0x%X\n", value);
  428. break;
  429. case TPM2_PT_PS_DAY_OF_YEAR:
  430. tpm2_tool_output("TPM2_PT_PS_DAY_OF_YEAR:\n"
  431. " raw: 0x%X\n", value);
  432. break;
  433. case TPM2_PT_PS_YEAR:
  434. tpm2_tool_output("TPM2_PT_PS_YEAR:\n"
  435. " raw: 0x%X\n", value);
  436. break;
  437. case TPM2_PT_SPLIT_MAX:
  438. tpm2_tool_output("TPM2_PT_SPLIT_MAX:\n"
  439. " raw: 0x%X\n", value);
  440. break;
  441. case TPM2_PT_TOTAL_COMMANDS:
  442. tpm2_tool_output("TPM2_PT_TOTAL_COMMANDS:\n"
  443. " raw: 0x%X\n", value);
  444. break;
  445. case TPM2_PT_LIBRARY_COMMANDS:
  446. tpm2_tool_output("TPM2_PT_LIBRARY_COMMANDS:\n"
  447. " raw: 0x%X\n", value);
  448. break;
  449. case TPM2_PT_VENDOR_COMMANDS:
  450. tpm2_tool_output("TPM2_PT_VENDOR_COMMANDS:\n"
  451. " raw: 0x%X\n", value);
  452. break;
  453. case TPM2_PT_NV_BUFFER_MAX:
  454. tpm2_tool_output("TPM2_PT_NV_BUFFER_MAX:\n"
  455. " raw: 0x%X\n", value);
  456. break;
  457. case TPM2_PT_MODES:
  458. tpm2_tool_output_tpma_modes((TPMA_MODES) value);
  459. break;
  460. }
  461. }
  462. }
  463. /*
  464. * Iterate over all variable properties, call the unique print function for each.
  465. */
  466. static void dump_tpm_properties_var(TPMS_TAGGED_PROPERTY properties[],
  467. size_t count) {
  468. size_t i;
  469. for (i = 0; i < count; ++i) {
  470. TPM2_PT property = properties[i].property;
  471. UINT32 value = properties[i].value;
  472. switch (property) {
  473. case TPM2_PT_PERMANENT:
  474. dump_permanent_attrs((TPMA_PERMANENT) value);
  475. break;
  476. case TPM2_PT_STARTUP_CLEAR:
  477. dump_startup_clear_attrs((TPMA_STARTUP_CLEAR) value);
  478. break;
  479. case TPM2_PT_HR_NV_INDEX:
  480. tpm2_tool_output("TPM2_PT_HR_NV_INDEX: 0x%X\n", value);
  481. break;
  482. case TPM2_PT_HR_LOADED:
  483. tpm2_tool_output("TPM2_PT_HR_LOADED: 0x%X\n", value);
  484. break;
  485. case TPM2_PT_HR_LOADED_AVAIL:
  486. tpm2_tool_output("TPM2_PT_HR_LOADED_AVAIL: 0x%X\n", value);
  487. break;
  488. case TPM2_PT_HR_ACTIVE:
  489. tpm2_tool_output("TPM2_PT_HR_ACTIVE: 0x%X\n", value);
  490. break;
  491. case TPM2_PT_HR_ACTIVE_AVAIL:
  492. tpm2_tool_output("TPM2_PT_HR_ACTIVE_AVAIL: 0x%X\n", value);
  493. break;
  494. case TPM2_PT_HR_TRANSIENT_AVAIL:
  495. tpm2_tool_output("TPM2_PT_HR_TRANSIENT_AVAIL: 0x%X\n", value);
  496. break;
  497. case TPM2_PT_HR_PERSISTENT:
  498. tpm2_tool_output("TPM2_PT_HR_PERSISTENT: 0x%X\n", value);
  499. break;
  500. case TPM2_PT_HR_PERSISTENT_AVAIL:
  501. tpm2_tool_output("TPM2_PT_HR_PERSISTENT_AVAIL: 0x%X\n", value);
  502. break;
  503. case TPM2_PT_NV_COUNTERS:
  504. tpm2_tool_output("TPM2_PT_NV_COUNTERS: 0x%X\n", value);
  505. break;
  506. case TPM2_PT_NV_COUNTERS_AVAIL:
  507. tpm2_tool_output("TPM2_PT_NV_COUNTERS_AVAIL: 0x%X\n", value);
  508. break;
  509. case TPM2_PT_ALGORITHM_SET:
  510. tpm2_tool_output("TPM2_PT_ALGORITHM_SET: 0x%X\n", value);
  511. break;
  512. case TPM2_PT_LOADED_CURVES:
  513. tpm2_tool_output("TPM2_PT_LOADED_CURVES: 0x%X\n", value);
  514. break;
  515. case TPM2_PT_LOCKOUT_COUNTER:
  516. tpm2_tool_output("TPM2_PT_LOCKOUT_COUNTER: 0x%X\n", value);
  517. break;
  518. case TPM2_PT_MAX_AUTH_FAIL:
  519. tpm2_tool_output("TPM2_PT_MAX_AUTH_FAIL: 0x%X\n", value);
  520. break;
  521. case TPM2_PT_LOCKOUT_INTERVAL:
  522. tpm2_tool_output("TPM2_PT_LOCKOUT_INTERVAL: 0x%X\n", value);
  523. break;
  524. case TPM2_PT_LOCKOUT_RECOVERY:
  525. tpm2_tool_output("TPM2_PT_LOCKOUT_RECOVERY: 0x%X\n", value);
  526. break;
  527. case TPM2_PT_NV_WRITE_RECOVERY:
  528. tpm2_tool_output("TPM2_PT_NV_WRITE_RECOVERY: 0x%X\n", value);
  529. break;
  530. case TPM2_PT_AUDIT_COUNTER_0:
  531. tpm2_tool_output("TPM2_PT_AUDIT_COUNTER_0: 0x%X\n", value);
  532. break;
  533. case TPM2_PT_AUDIT_COUNTER_1:
  534. tpm2_tool_output("TPM2_PT_AUDIT_COUNTER_1: 0x%X\n", value);
  535. break;
  536. default:
  537. tpm2_tool_output("unknown%X: 0x%X\n", value, value);
  538. break;
  539. }
  540. }
  541. }
  542. /*
  543. * Print data about TPM2_ALG_ID in human readable form.
  544. */
  545. static void dump_algorithm_properties(TPM2_ALG_ID id, TPMA_ALGORITHM alg_attrs) {
  546. const char *id_name = tpm2_alg_util_algtostr(id, tpm2_alg_util_flags_any);
  547. bool is_unknown = id_name == NULL;
  548. id_name = id_name ? id_name : "unknown";
  549. if (!is_unknown) {
  550. tpm2_tool_output("%s:\n", id_name);
  551. } else {
  552. /* If it's unknown, we don't want N unknowns in the map, so
  553. * make them unknown42, unknown<alg id> since that's unique.
  554. * We do it this way, as most folks will want to just look up
  555. * if a given alg via "friendly" name like rsa is supported.
  556. */
  557. tpm2_tool_output("%s%x:\n", id_name, id);
  558. }
  559. tpm2_tool_output(" value: 0x%X\n", id);
  560. tpm2_tool_output(" asymmetric: %s\n",
  561. prop_str (alg_attrs & TPMA_ALGORITHM_ASYMMETRIC));
  562. tpm2_tool_output(" symmetric: %s\n",
  563. prop_str (alg_attrs & TPMA_ALGORITHM_SYMMETRIC));
  564. tpm2_tool_output(" hash: %s\n",
  565. prop_str (alg_attrs & TPMA_ALGORITHM_HASH));
  566. tpm2_tool_output(" object: %s\n",
  567. prop_str (alg_attrs & TPMA_ALGORITHM_OBJECT));
  568. tpm2_tool_output(" reserved: 0x%X\n",
  569. (alg_attrs & TPMA_ALGORITHM_RESERVED1_MASK) >> 4);
  570. tpm2_tool_output(" signing: %s\n",
  571. prop_str (alg_attrs & TPMA_ALGORITHM_SIGNING));
  572. tpm2_tool_output(" encrypting: %s\n",
  573. prop_str (alg_attrs & TPMA_ALGORITHM_ENCRYPTING));
  574. tpm2_tool_output(" method: %s\n",
  575. prop_str (alg_attrs & TPMA_ALGORITHM_METHOD));
  576. }
  577. /*
  578. * Iterate over the count TPMS_ALG_PROPERTY entries and dump the
  579. * TPMA_ALGORITHM attributes for each.
  580. */
  581. static void dump_algorithms(TPMS_ALG_PROPERTY alg_properties[], size_t count) {
  582. size_t i;
  583. for (i = 0; i < count; ++i)
  584. dump_algorithm_properties(alg_properties[i].alg,
  585. alg_properties[i].algProperties);
  586. }
  587. /*
  588. * Pretty print the bit fields from the TPMA_CC (UINT32)
  589. */
  590. static bool dump_command_attrs(TPMA_CC tpma_cc) {
  591. const char *value = tpm2_cc_util_to_str(
  592. tpma_cc & TPMA_CC_COMMANDINDEX_MASK);
  593. /* not found, make a hex version of it */
  594. if (!value) {
  595. /*
  596. * big enough for hex representation of
  597. * saturated U32 + 0x prefix and then some.
  598. */
  599. static char _buf[16];
  600. memset(_buf, 0, sizeof(_buf));
  601. int rc = snprintf(_buf, sizeof(_buf), "0x%x", tpma_cc);
  602. /* ignore bytes, we don't care if it's truncated and it shouldnt happen */
  603. UNUSED(rc);
  604. value = _buf;
  605. }
  606. tpm2_tool_output("%s:\n", value);
  607. tpm2_tool_output(" value: 0x%X\n", tpma_cc);
  608. tpm2_tool_output(" commandIndex: 0x%x\n",
  609. tpma_cc & TPMA_CC_COMMANDINDEX_MASK);
  610. tpm2_tool_output(" reserved1: 0x%x\n",
  611. (tpma_cc & TPMA_CC_RESERVED1_MASK) >> 16);
  612. tpm2_tool_output(" nv: %s\n", prop_str (tpma_cc & TPMA_CC_NV));
  613. tpm2_tool_output(" extensive: %s\n",
  614. prop_str (tpma_cc & TPMA_CC_EXTENSIVE));
  615. tpm2_tool_output(" flushed: %s\n",
  616. prop_str (tpma_cc & TPMA_CC_FLUSHED));
  617. tpm2_tool_output(" cHandles: 0x%x\n",
  618. (tpma_cc & TPMA_CC_CHANDLES_MASK) >> TPMA_CC_CHANDLES_SHIFT);
  619. tpm2_tool_output(" rHandle: %s\n",
  620. prop_str (tpma_cc & TPMA_CC_RHANDLE));
  621. tpm2_tool_output(" V: %s\n", prop_str (tpma_cc & TPMA_CC_V));
  622. tpm2_tool_output(" Res: 0x%x\n",
  623. (tpma_cc & TPMA_CC_RES_MASK) >> TPMA_CC_RES_SHIFT);
  624. return true;
  625. }
  626. /*
  627. * Iterate over an array of TPM2_ECC_CURVEs and dump out a human readable
  628. * representation of each array member.
  629. */
  630. static void dump_ecc_curves(TPM2_ECC_CURVE curve[], UINT32 count) {
  631. size_t i;
  632. for (i = 0; i < count; ++i) {
  633. switch (curve[i]) {
  634. case TPM2_ECC_NIST_P192:
  635. tpm2_tool_output("TPM2_ECC_NIST_P192: 0x%X\n", curve[i]);
  636. break;
  637. case TPM2_ECC_NIST_P224:
  638. tpm2_tool_output("TPM2_ECC_NIST_P224: 0x%X\n", curve[i]);
  639. break;
  640. case TPM2_ECC_NIST_P256:
  641. tpm2_tool_output("TPM2_ECC_NIST_P256: 0x%X\n", curve[i]);
  642. break;
  643. case TPM2_ECC_NIST_P384:
  644. tpm2_tool_output("TPM2_ECC_NIST_P384: 0x%X\n", curve[i]);
  645. break;
  646. case TPM2_ECC_NIST_P521:
  647. tpm2_tool_output("TPM2_ECC_NIST_P521: 0x%X\n", curve[i]);
  648. break;
  649. case TPM2_ECC_BN_P256:
  650. tpm2_tool_output("TPM2_ECC_BN_P256: 0x%X\n", curve[i]);
  651. break;
  652. case TPM2_ECC_BN_P638:
  653. tpm2_tool_output("TPM2_ECC_BN_P638: 0x%X\n", curve[i]);
  654. break;
  655. case TPM2_ECC_SM2_P256:
  656. tpm2_tool_output("TPM2_ECC_SM2_P256: 0x%X\n", curve[i]);
  657. break;
  658. default:
  659. tpm2_tool_output("unknown%X: 0x%X\n", curve[i], curve[i]);
  660. break;
  661. }
  662. }
  663. }
  664. /*
  665. * Iterate over an array of TPMA_CCs and dump out a human readable
  666. * representation of each array member.
  667. */
  668. static bool dump_command_attr_array(TPMA_CC command_attributes[], UINT32 count) {
  669. size_t i;
  670. bool result = true;
  671. for (i = 0; i < count; ++i)
  672. result &= dump_command_attrs(command_attributes[i]);
  673. return result;
  674. }
  675. /*
  676. * Iterate over an array of TPML_HANDLEs and dump out the handle
  677. * values.
  678. */
  679. static void dump_handles(TPM2_HANDLE handles[], UINT32 count) {
  680. UINT32 i;
  681. for (i = 0; i < count; ++i)
  682. tpm2_tool_output("- 0x%X\n", handles[i]);
  683. }
  684. /*
  685. * Query the TPM for TPM capabilities.
  686. */
  687. static tool_rc get_tpm_capability_all(ESYS_CONTEXT *context,
  688. TPMS_CAPABILITY_DATA **capability_data) {
  689. return tpm2_capability_get(context, options.capability, options.property,
  690. options.count, capability_data);
  691. }
  692. /*
  693. * This function is a glorified switch statement. It uses the 'capability'
  694. * and 'property' fields from the capability_opts structure to find the right
  695. * print function for the capabilities in the 'capabilities' parameter.
  696. * On success it will return true, if it fails (is unable to find an
  697. * appropriate print function for the provided 'capability' / 'property'
  698. * pair or the print routine fails) then it will return false.
  699. */
  700. static bool dump_tpm_capability(TPMU_CAPABILITIES *capabilities) {
  701. bool result = true;
  702. switch (options.capability) {
  703. case TPM2_CAP_ALGS:
  704. dump_algorithms(capabilities->algorithms.algProperties,
  705. capabilities->algorithms.count);
  706. break;
  707. case TPM2_CAP_COMMANDS:
  708. result = dump_command_attr_array(
  709. capabilities->command.commandAttributes,
  710. capabilities->command.count);
  711. break;
  712. case TPM2_CAP_TPM_PROPERTIES:
  713. switch (options.property) {
  714. case TPM2_PT_FIXED:
  715. dump_tpm_properties_fixed(capabilities->tpmProperties.tpmProperty,
  716. capabilities->tpmProperties.count);
  717. break;
  718. case TPM2_PT_VAR:
  719. dump_tpm_properties_var(capabilities->tpmProperties.tpmProperty,
  720. capabilities->tpmProperties.count);
  721. break;
  722. default:
  723. return false;
  724. }
  725. break;
  726. case TPM2_CAP_ECC_CURVES:
  727. dump_ecc_curves(capabilities->eccCurves.eccCurves,
  728. capabilities->eccCurves.count);
  729. break;
  730. case TPM2_CAP_HANDLES:
  731. switch (options.property & TPM2_HR_RANGE_MASK) {
  732. case TPM2_HR_TRANSIENT:
  733. case TPM2_HR_PERSISTENT:
  734. case TPM2_HR_PERMANENT:
  735. case TPM2_HR_PCR:
  736. case TPM2_HR_NV_INDEX:
  737. case TPM2_HT_LOADED_SESSION << TPM2_HR_SHIFT:
  738. case TPM2_HT_SAVED_SESSION << TPM2_HR_SHIFT:
  739. dump_handles(capabilities->handles.handle,
  740. capabilities->handles.count);
  741. break;
  742. default:
  743. return false;
  744. }
  745. break;
  746. case TPM2_CAP_PCRS:
  747. pcr_print_pcr_selections(&capabilities->assignedPCR);
  748. break;
  749. default:
  750. return false;
  751. }
  752. return result;
  753. }
  754. static bool on_option(char key, char *value) {
  755. UNUSED(value);
  756. switch (key) {
  757. case 'l':
  758. options.list = true;
  759. }
  760. return true;
  761. }
  762. static bool on_arg(int argc, char *argv[]) {
  763. if (argc != 1) {
  764. LOG_ERR("Only supports 1 capability group, got: %d", argc);
  765. return false;
  766. }
  767. options.capability_string = argv[0];
  768. return true;
  769. }
  770. static bool tpm2_tool_onstart(tpm2_options **opts) {
  771. const struct option topts[] = { { "list", no_argument, NULL, 'l' },
  772. };
  773. *opts = tpm2_options_new("l", ARRAY_LEN(topts), topts, on_option, on_arg,
  774. 0);
  775. return *opts != NULL;
  776. }
  777. static tool_rc tpm2_tool_onrun(ESYS_CONTEXT *context, tpm2_option_flags flags) {
  778. UNUSED(flags);
  779. if (options.list && options.capability_string) {
  780. LOG_ERR("Cannot specify -l with a capability group.");
  781. return tool_rc_option_error;
  782. }
  783. /* list known capabilities, ie -l option */
  784. if (options.list) {
  785. print_cap_map();
  786. return tool_rc_success;
  787. }
  788. /* List a capability, ie <capability group> option */
  789. TPMS_CAPABILITY_DATA *capability_data = NULL;
  790. bool ret = sanity_check_capability_opts();
  791. if (!ret) {
  792. return tool_rc_option_error;
  793. }
  794. /* get requested capability from TPM, dump it to stdout */
  795. tool_rc rc = get_tpm_capability_all(context, &capability_data);
  796. if (rc != tool_rc_success) {
  797. return rc;
  798. }
  799. bool result = dump_tpm_capability(&capability_data->data);
  800. free(capability_data);
  801. return result ? tool_rc_success : tool_rc_general_error;
  802. }
  803. // Register this tool with tpm2_tool.c
  804. TPM2_TOOL_REGISTER("getcap", tpm2_tool_onstart, tpm2_tool_onrun, NULL, NULL)