tpm2_eventlog_yaml.c 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  1. #include <ctype.h>
  2. #include <errno.h>
  3. #include <inttypes.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <uchar.h>
  8. #include <tss2/tss2_tpm2_types.h>
  9. #include "log.h"
  10. #include "efi_event.h"
  11. #include "tpm2_alg_util.h"
  12. #include "tpm2_eventlog.h"
  13. #include "tpm2_eventlog_yaml.h"
  14. #include "tpm2_tool.h"
  15. #include "tpm2_tool_output.h"
  16. #ifdef HAVE_CONFIG_H
  17. #include <config.h>
  18. #endif
  19. #ifdef HAVE_EFIVAR_EFIVAR_H
  20. #include <efivar/efivar.h>
  21. #endif
  22. char const *eventtype_to_string (UINT32 event_type) {
  23. switch (event_type) {
  24. case EV_PREBOOT_CERT:
  25. return "EV_PREBOOT_CERT";
  26. case EV_POST_CODE:
  27. return "EV_POST_CODE";
  28. case EV_UNUSED:
  29. return "EV_UNUSED";
  30. case EV_NO_ACTION:
  31. return "EV_NO_ACTION";
  32. case EV_SEPARATOR:
  33. return "EV_SEPARATOR";
  34. case EV_ACTION:
  35. return "EV_ACTION";
  36. case EV_EVENT_TAG:
  37. return "EV_EVENT_TAG";
  38. case EV_S_CRTM_CONTENTS:
  39. return "EV_S_CRTM_CONTENTS";
  40. case EV_S_CRTM_VERSION:
  41. return "EV_S_CRTM_VERSION";
  42. case EV_CPU_MICROCODE:
  43. return "EV_CPU_MICROCODE";
  44. case EV_PLATFORM_CONFIG_FLAGS:
  45. return "EV_PLATFORM_CONFIG_FLAGS";
  46. case EV_TABLE_OF_DEVICES:
  47. return "EV_TABLE_OF_DEVICES";
  48. case EV_COMPACT_HASH:
  49. return "EV_COMPACT_HASH";
  50. case EV_IPL:
  51. return "EV_IPL";
  52. case EV_IPL_PARTITION_DATA:
  53. return "EV_IPL_PARTITION_DATA";
  54. case EV_NONHOST_CODE:
  55. return "EV_NONHOST_CODE";
  56. case EV_NONHOST_CONFIG:
  57. return "EV_NONHOST_CONFIG";
  58. case EV_NONHOST_INFO:
  59. return "EV_NONHOST_INFO";
  60. case EV_OMIT_BOOT_DEVICE_EVENTS:
  61. return "EV_OMIT_BOOT_DEVICE_EVENTS";
  62. case EV_EFI_VARIABLE_DRIVER_CONFIG:
  63. return "EV_EFI_VARIABLE_DRIVER_CONFIG";
  64. case EV_EFI_VARIABLE_BOOT:
  65. return "EV_EFI_VARIABLE_BOOT";
  66. case EV_EFI_BOOT_SERVICES_APPLICATION:
  67. return "EV_EFI_BOOT_SERVICES_APPLICATION";
  68. case EV_EFI_BOOT_SERVICES_DRIVER:
  69. return "EV_EFI_BOOT_SERVICES_DRIVER";
  70. case EV_EFI_RUNTIME_SERVICES_DRIVER:
  71. return "EV_EFI_RUNTIME_SERVICES_DRIVER";
  72. case EV_EFI_GPT_EVENT:
  73. return "EV_EFI_GPT_EVENT";
  74. case EV_EFI_ACTION:
  75. return "EV_EFI_ACTION";
  76. case EV_EFI_PLATFORM_FIRMWARE_BLOB:
  77. return "EV_EFI_PLATFORM_FIRMWARE_BLOB";
  78. case EV_EFI_HANDOFF_TABLES:
  79. return "EV_EFI_HANDOFF_TABLES";
  80. case EV_EFI_VARIABLE_AUTHORITY:
  81. return "EV_EFI_VARIABLE_AUTHORITY";
  82. default:
  83. return "Unknown event type";
  84. }
  85. }
  86. void bytes_to_str(uint8_t const *buf, size_t size, char *dest, size_t dest_size) {
  87. size_t i, j;
  88. for(i = 0, j = 0; i < size && j < dest_size - 2; ++i, j+=2) {
  89. sprintf(&dest[j], "%02x", buf[i]);
  90. }
  91. dest[j] = '\0';
  92. }
  93. void yaml_event2hdr(TCG_EVENT_HEADER2 const *eventhdr, size_t size) {
  94. (void)size;
  95. tpm2_tool_output(" PCRIndex: %d\n"
  96. " EventType: %s\n"
  97. " DigestCount: %d\n",
  98. eventhdr->PCRIndex,
  99. eventtype_to_string(eventhdr->EventType),
  100. eventhdr->DigestCount);
  101. return;
  102. }
  103. void yaml_sha1_log_eventhdr(TCG_EVENT const *eventhdr, size_t size) {
  104. (void)size;
  105. tpm2_tool_output(" PCRIndex: %d\n"
  106. " EventType: %s\n",
  107. eventhdr->pcrIndex,
  108. eventtype_to_string(eventhdr->eventType));
  109. return;
  110. }
  111. /* converting byte buffer to hex string requires 2x, plus 1 for '\0' */
  112. #define BYTES_TO_HEX_STRING_SIZE(byte_count) ((byte_count) * 2 + 1)
  113. #define DIGEST_HEX_STRING_MAX BYTES_TO_HEX_STRING_SIZE(TPM2_MAX_DIGEST_BUFFER)
  114. bool yaml_digest2(TCG_DIGEST2 const *digest, size_t size) {
  115. char hexstr[DIGEST_HEX_STRING_MAX] = { 0, };
  116. bytes_to_str(digest->Digest, size, hexstr, sizeof(hexstr));
  117. tpm2_tool_output(" - AlgorithmId: %s\n"
  118. " Digest: \"%s\"\n",
  119. tpm2_alg_util_algtostr(digest->AlgorithmId, tpm2_alg_util_flags_hash),
  120. hexstr);
  121. return true;
  122. }
  123. char *yaml_uefi_var_unicodename(UEFI_VARIABLE_DATA *data) {
  124. int ret = 0;
  125. mbstate_t st;
  126. memset(&st, '\0', sizeof(st));
  127. char *mbstr = calloc(data->UnicodeNameLength + 1, MB_CUR_MAX);
  128. char *tmp = mbstr;
  129. if (mbstr == NULL) {
  130. LOG_ERR("failed to allocate data: %s\n", strerror(errno));
  131. return NULL;
  132. }
  133. for(size_t i = 0; i < data->UnicodeNameLength; ++i, tmp += ret) {
  134. ret = c16rtomb(tmp, data->UnicodeName[i], &st);
  135. if (ret < 0) {
  136. LOG_ERR("c16rtomb failed: %s", strerror(errno));
  137. free(mbstr);
  138. return NULL;
  139. }
  140. }
  141. return mbstr;
  142. }
  143. #define VAR_DATA_HEX_SIZE(data) BYTES_TO_HEX_STRING_SIZE(data->VariableDataLength)
  144. static bool yaml_uefi_var_data(UEFI_VARIABLE_DATA *data) {
  145. if (data->VariableDataLength == 0) {
  146. return true;
  147. }
  148. char *var_data = calloc (1, VAR_DATA_HEX_SIZE(data));
  149. uint8_t *variable_data = (uint8_t*)&data->UnicodeName[
  150. data->UnicodeNameLength];
  151. if (var_data == NULL) {
  152. LOG_ERR("failled to allocate data: %s\n", strerror(errno));
  153. return false;
  154. }
  155. bytes_to_str(variable_data, data->VariableDataLength, var_data,
  156. VAR_DATA_HEX_SIZE(data));
  157. tpm2_tool_output(" VariableData: \"%s\"\n", var_data);
  158. free(var_data);
  159. return true;
  160. }
  161. /*
  162. * TCG PC Client FPF section 2.3.4.1 and 9.4.1:
  163. * Usage of the event type EV_POST_CODE:
  164. * - If a combined event is measured, the event field SHOULD
  165. * be the string "POST CODE" in all caps. ...
  166. * - Embedded SMM code and the code that sets it up SHOULD use
  167. * the string "SMM CODE" in all caps...
  168. * - BIS code (excluding the BIS Certificate) should use event
  169. * field string of "BIS CODE" in all caps. ...
  170. * - ACPI flash data prior to any modifications ... should use
  171. * event field string of "ACPI DATA" in all caps.
  172. *
  173. * Section 9.2.5 also says "...Below is the definition of the
  174. * UEFI_PLATFORM_FIRMWARE_BLOB structure that the CRTM MUST put
  175. * into the Event Log entry TCG_PCR_EVENT2.event[1] field for
  176. * event types EV_POST_CODE, EV_S_CRTM_CONTENTS, and
  177. * EV_EFI_PLATFORM_FIRMWARE_BLOB."
  178. */
  179. static bool yaml_uefi_post_code(const TCG_EVENT2* const event) {
  180. const size_t len = event->EventSize;
  181. /* if length is 16, we treat it as EV_EFI_PLATFORM_FIRMWARE_BLOB */
  182. if (len == 16) {
  183. const UEFI_PLATFORM_FIRMWARE_BLOB * const blob = \
  184. (const UEFI_PLATFORM_FIRMWARE_BLOB*) event->Event;
  185. tpm2_tool_output(" Event:\n"
  186. " BlobBase: 0x%" PRIx64 "\n"
  187. " BlobLength: 0x%" PRIx64 "\n",
  188. blob->BlobBase,
  189. blob->BlobLength);
  190. } else { // otherwise, we treat it as an ASCII string
  191. const char* const data = (const char *) event->Event;
  192. tpm2_tool_output(" Event: |-\n"
  193. " %.*s\n", (int) len, data);
  194. }
  195. return true;
  196. }
  197. /*
  198. * Parses Device Path field using the efivar library if present, otherwise,
  199. * print the field in raw byte format
  200. */
  201. #ifdef HAVE_EFIVAR_EFIVAR_H
  202. char *yaml_devicepath(BYTE* dp, UINT64 dp_len) {
  203. int ret;
  204. ret = efidp_format_device_path(NULL, 0, (const_efidp)dp, dp_len);
  205. if (ret < 0) {
  206. LOG_ERR("failed to allocate memory: %s\n", strerror(errno));
  207. return NULL;
  208. }
  209. int text_path_len;
  210. char *text_path;
  211. text_path_len = ret + 1;
  212. text_path = (char*)malloc(text_path_len);
  213. if (!text_path) {
  214. LOG_ERR("failed to allocate memory: %s\n", strerror(errno));
  215. return NULL;
  216. }
  217. ret = efidp_format_device_path(text_path,
  218. text_path_len, (const_efidp)dp, dp_len);
  219. if (ret < 0) {
  220. free(text_path);
  221. LOG_ERR("cannot parse device path\n");
  222. return NULL;
  223. }
  224. return text_path;
  225. }
  226. #endif
  227. /*
  228. * TCG PC Client FPF section 9.2.6
  229. * The tpm2_eventlog module validates the event structure but nothing within
  230. * the event data buffer so we must do that here.
  231. */
  232. static bool yaml_uefi_var(UEFI_VARIABLE_DATA *data, size_t size, UINT32 type,
  233. uint32_t eventlog_version) {
  234. char uuidstr[37] = { 0 };
  235. size_t start = 0;
  236. if (size < sizeof(*data)) {
  237. LOG_ERR("EventSize is too small\n");
  238. return false;
  239. }
  240. uuid_unparse_lower(data->VariableName, uuidstr);
  241. tpm2_tool_output(" Event:\n"
  242. " VariableName: %s\n"
  243. " UnicodeNameLength: %"PRIu64"\n"
  244. " VariableDataLength: %" PRIu64 "\n",
  245. uuidstr, data->UnicodeNameLength,
  246. data->VariableDataLength);
  247. start += sizeof(*data);
  248. if (start + data->UnicodeNameLength*2 > size) {
  249. LOG_ERR("EventSize is too small\n");
  250. return false;
  251. }
  252. char *ret = yaml_uefi_var_unicodename(data);
  253. if (!ret) {
  254. return false;
  255. }
  256. tpm2_tool_output(" UnicodeName: %s\n", ret);
  257. start += data->UnicodeNameLength*2;
  258. /* Try to parse as much as we can without fail-stop. Bugs in firmware, shim,
  259. * grub could produce inconsistent metadata. As long as it is not preventing
  260. * us from parsing the data, we try to continue while giving a warning
  261. * message.
  262. */
  263. if (start + data->VariableDataLength > size) {
  264. LOG_ERR("EventSize is inconsistent with actual data\n");
  265. }
  266. if (eventlog_version == 2) {
  267. /* PK, KEK, db, and dbx are reserved variables names used to store platform
  268. * keys, key exchange keys, database keys, and blacklisted database keys,
  269. * respectively.
  270. */
  271. if (type == EV_EFI_VARIABLE_DRIVER_CONFIG) {
  272. if ((strlen(ret) == 2 && strncmp(ret, "PK", 2) == 0) ||
  273. (strlen(ret) == 3 && strncmp(ret, "KEK", 3) == 0) ||
  274. (strlen(ret) == 2 && strncmp(ret, "db", 2) == 0) ||
  275. (strlen(ret) == 3 && strncmp(ret, "dbx", 3) == 0)) {
  276. free(ret);
  277. tpm2_tool_output(" VariableData:\n");
  278. uint8_t *variable_data = (uint8_t *)&data->UnicodeName[
  279. data->UnicodeNameLength];
  280. /* iterate through each EFI_SIGNATURE_LIST */
  281. while (start < size) {
  282. EFI_SIGNATURE_LIST *slist = (EFI_SIGNATURE_LIST *)variable_data;
  283. if (start + sizeof(*slist) > size) {
  284. LOG_ERR("EventSize is inconsistent with actual data\n");
  285. break;
  286. }
  287. if (slist->SignatureSize < 16) {
  288. LOG_ERR("SignatureSize is too small\n");
  289. break;
  290. }
  291. uuid_unparse_lower(slist->SignatureType, uuidstr);
  292. tpm2_tool_output(" - SignatureType: %s\n"
  293. " SignatureListSize: %" PRIu32 "\n"
  294. " SignatureHeaderSize: %" PRIu32 "\n"
  295. " SignatureSize: %" PRIu32 "\n"
  296. " Keys:\n",
  297. uuidstr, slist->SignatureListSize,
  298. slist->SignatureHeaderSize,
  299. slist->SignatureSize);
  300. start += (sizeof(*slist) + slist->SignatureHeaderSize);
  301. if (start + slist->SignatureSize > size) {
  302. LOG_ERR("EventSize is inconsistent with actual data\n");
  303. break;
  304. }
  305. int signature_size = slist->SignatureListSize -
  306. sizeof(*slist) - slist->SignatureHeaderSize;
  307. if (signature_size < 0 || signature_size % slist->SignatureSize != 0) {
  308. LOG_ERR("Malformed EFI_SIGNATURE_LIST\n");
  309. break;
  310. }
  311. uint8_t *signature = (uint8_t *)slist +
  312. sizeof(*slist) + slist->SignatureHeaderSize;
  313. int signatures = signature_size / slist->SignatureSize;
  314. /* iterate through each EFI_SIGNATURE on the list */
  315. int i;
  316. for (i = 0; i < signatures; i++) {
  317. EFI_SIGNATURE_DATA *s = (EFI_SIGNATURE_DATA *)signature;
  318. char *sdata = calloc (1,
  319. BYTES_TO_HEX_STRING_SIZE(slist->SignatureSize-16));
  320. if (sdata == NULL) {
  321. LOG_ERR("Failled to allocate data: %s\n", strerror(errno));
  322. return false;
  323. }
  324. bytes_to_str(s->SignatureData, slist->SignatureSize-16,
  325. sdata, BYTES_TO_HEX_STRING_SIZE(slist->SignatureSize-16));
  326. uuid_unparse_lower(s->SignatureOwner, uuidstr);
  327. tpm2_tool_output(" - SignatureOwner: %s\n"
  328. " SignatureData: %s\n",
  329. uuidstr, sdata);
  330. free(sdata);
  331. signature += slist->SignatureSize;
  332. start += slist->SignatureSize;
  333. if (start > size) {
  334. LOG_ERR("Malformed EFI_SIGNATURE_DATA\n");
  335. break;
  336. }
  337. }
  338. variable_data += slist->SignatureListSize;
  339. }
  340. return true;
  341. } else if ((strlen(ret) == 10 && strncmp(ret, "SecureBoot", 10) == 0)) {
  342. free(ret);
  343. tpm2_tool_output(" VariableData:\n"
  344. " Enabled: ");
  345. if (data->VariableDataLength == 0) {
  346. tpm2_tool_output("'No'\n");
  347. } else if (data->VariableDataLength > 1) {
  348. LOG_ERR("SecureBoot value length %" PRIu64 " is unexpectedly > 1\n",
  349. data->VariableDataLength);
  350. return false;
  351. } else {
  352. uint8_t *variable_data = (uint8_t *)&data->UnicodeName[
  353. data->UnicodeNameLength];
  354. if (*variable_data == 0) {
  355. tpm2_tool_output("'No'\n");
  356. } else {
  357. tpm2_tool_output("'Yes'\n");
  358. }
  359. }
  360. return true;
  361. }
  362. /* Other variables will be printed as a hex string */
  363. } else if (type == EV_EFI_VARIABLE_AUTHORITY) {
  364. free(ret);
  365. tpm2_tool_output(" VariableData:\n");
  366. EFI_SIGNATURE_DATA *s= (EFI_SIGNATURE_DATA *)&data->UnicodeName[
  367. data->UnicodeNameLength];
  368. char *sdata = calloc (1,
  369. BYTES_TO_HEX_STRING_SIZE(data->VariableDataLength - 16));
  370. if (sdata == NULL) {
  371. LOG_ERR("Failled to allocate data: %s\n", strerror(errno));
  372. return false;
  373. }
  374. bytes_to_str(s->SignatureData, data->VariableDataLength - 16,
  375. sdata, BYTES_TO_HEX_STRING_SIZE(data->VariableDataLength - 16));
  376. uuid_unparse_lower(s->SignatureOwner, uuidstr);
  377. tpm2_tool_output(" - SignatureOwner: %s\n"
  378. " SignatureData: %s\n",
  379. uuidstr, sdata);
  380. free(sdata);
  381. return true;
  382. } else if (type == EV_EFI_VARIABLE_BOOT) {
  383. if ((strlen(ret) == 9 && strncmp(ret, "BootOrder", 9) == 0)) {
  384. free(ret);
  385. tpm2_tool_output(" VariableData:\n");
  386. if (data->VariableDataLength % 2 != 0) {
  387. LOG_ERR("BootOrder value length %" PRIu64 " is not divisible by 2\n",
  388. data->VariableDataLength);
  389. return false;
  390. }
  391. uint8_t *variable_data = (uint8_t *)&data->UnicodeName[
  392. data->UnicodeNameLength];
  393. for (uint64_t i = 0; i < data->VariableDataLength / 2; i++) {
  394. tpm2_tool_output(" - Boot%04x\n", *((uint16_t*)variable_data + i));
  395. }
  396. return true;
  397. }
  398. /* Test for regex "^Boot[0-9a-fA-F]\\{4\\}$" */
  399. if (strlen(ret) == 8 && strncmp(ret, "Boot", 4) == 0 &&
  400. isxdigit((int)ret[4]) && isxdigit((int)ret[5]) &&
  401. isxdigit((int)ret[6]) && isxdigit((int)ret[7])) {
  402. free(ret);
  403. tpm2_tool_output(" VariableData:\n"
  404. " Enabled: ");
  405. EFI_LOAD_OPTION *loadopt = (EFI_LOAD_OPTION*)&data->UnicodeName[
  406. data->UnicodeNameLength];
  407. if (loadopt->Attributes & 1) {
  408. tpm2_tool_output("'Yes'\n");
  409. } else {
  410. tpm2_tool_output("'No'\n");
  411. }
  412. tpm2_tool_output(" FilePathListLength: %" PRIu16 "\n",
  413. loadopt->FilePathListLength);
  414. tpm2_tool_output(" Description: \"");
  415. int i;
  416. for (i = 0; (wchar_t)loadopt->Description[i] != 0; i++) {
  417. wchar_t c = (wchar_t)loadopt->Description[i];
  418. tpm2_tool_output("%lc", c);
  419. }
  420. tpm2_tool_output("\"\n");
  421. uint8_t *devpath = (uint8_t*)&loadopt->Description[++i];
  422. size_t devpath_len = (data->VariableDataLength -
  423. sizeof(EFI_LOAD_OPTION) - sizeof(UINT16) * i) * 2 + 1;
  424. char *buf = calloc(1, devpath_len);
  425. if (!buf) {
  426. LOG_ERR("failed to allocate memory: %s\n", strerror(errno));
  427. return false;
  428. }
  429. #ifdef HAVE_EFIVAR_EFIVAR_H
  430. char *dp = yaml_devicepath(devpath, devpath_len);
  431. if (dp) {
  432. tpm2_tool_output(" DevicePath: '%s'\n", dp);
  433. free(dp);
  434. } else {
  435. /* fallback to printing the raw bytes if devicepath cannot be parsed */
  436. bytes_to_str(devpath, data->VariableDataLength -
  437. sizeof(EFI_LOAD_OPTION) - sizeof(UINT16) * i, buf, devpath_len);
  438. tpm2_tool_output(" DevicePath: '%s'\n", buf);
  439. }
  440. #else
  441. bytes_to_str(devpath, data->VariableDataLength -
  442. sizeof(EFI_LOAD_OPTION) - sizeof(UINT16) * i, buf, devpath_len);
  443. tpm2_tool_output(" DevicePath: '%s'\n", buf);
  444. #endif
  445. free(buf);
  446. return true;
  447. }
  448. }
  449. /* Other event types will be printed as a hex string */
  450. }
  451. free(ret);
  452. return yaml_uefi_var_data(data);
  453. }
  454. /* TCG PC Client FPF section 9.2.5 */
  455. bool yaml_uefi_platfwblob(UEFI_PLATFORM_FIRMWARE_BLOB *data) {
  456. tpm2_tool_output(" Event:\n"
  457. " BlobBase: 0x%" PRIx64 "\n"
  458. " BlobLength: 0x%" PRIx64 "\n",
  459. data->BlobBase,
  460. data->BlobLength);
  461. return true;
  462. }
  463. /* TCG PC Client PFP section 9.4.4 */
  464. bool yaml_uefi_action(UINT8 const *action, size_t size) {
  465. tpm2_tool_output(" Event: |-\n"
  466. " %.*s\n", (int) size, action);
  467. return true;
  468. }
  469. /*
  470. * TCG PC Client PFP section 9.4.1
  471. * This event type is extensively used by the Shim and Grub on a wide varities
  472. * of Linux distributions to measure grub and kernel command line parameters and
  473. * the loading of grub, kernel, and initrd images.
  474. */
  475. bool yaml_ipl(UINT8 const *description, size_t size) {
  476. tpm2_tool_output(" Event:\n"
  477. " String: |-\n");
  478. /* We need to handle when description contains multiple lines. */
  479. size_t i, j;
  480. for (i = 0; i < size; i++) {
  481. for (j = i; j < size; j++) {
  482. if (description[j] == '\n' || description[j] == '\0') {
  483. break;
  484. }
  485. }
  486. tpm2_tool_output(" %.*s\n", (int)(j - i), description+i);
  487. i = j;
  488. }
  489. return true;
  490. }
  491. /* TCG PC Client PFP section 9.2.3 */
  492. bool yaml_uefi_image_load(UEFI_IMAGE_LOAD_EVENT *data, size_t size) {
  493. size_t devpath_len = (size - sizeof(*data)) * 2 + 1;
  494. char *buf = calloc(1, devpath_len);
  495. if (!buf) {
  496. LOG_ERR("failed to allocate memory: %s\n", strerror(errno));
  497. return false;
  498. }
  499. tpm2_tool_output(" Event:\n"
  500. " ImageLocationInMemory: 0x%" PRIx64 "\n"
  501. " ImageLengthInMemory: %" PRIu64 "\n"
  502. " ImageLinkTimeAddress: 0x%" PRIx64 "\n"
  503. " LengthOfDevicePath: %" PRIu64 "\n",
  504. data->ImageLocationInMemory, data->ImageLengthInMemory,
  505. data->ImageLinkTimeAddress, data->LengthOfDevicePath);
  506. #ifdef HAVE_EFIVAR_EFIVAR_H
  507. char *dp = yaml_devicepath(data->DevicePath, data->LengthOfDevicePath);
  508. if (dp) {
  509. tpm2_tool_output(" DevicePath: '%s'\n", dp);
  510. free(dp);
  511. } else {
  512. /* fallback to printing the raw bytes if devicepath cannot be parsed */
  513. bytes_to_str(data->DevicePath, size - sizeof(*data), buf, devpath_len);
  514. tpm2_tool_output(" DevicePath: '%s'\n", buf);
  515. }
  516. #else
  517. bytes_to_str(data->DevicePath, size - sizeof(*data), buf, devpath_len);
  518. tpm2_tool_output(" DevicePath: '%s'\n", buf);
  519. #endif
  520. free(buf);
  521. return true;
  522. }
  523. #define EVENT_BUF_MAX BYTES_TO_HEX_STRING_SIZE(1024)
  524. /* TCG PC Client PFP section 9.2.6 */
  525. bool yaml_gpt(UEFI_GPT_DATA *data, size_t size, uint32_t eventlog_version) {
  526. if (size < sizeof(*data)) {
  527. LOG_ERR("EventSize(%zu) is too small\n", size);
  528. return false;
  529. }
  530. if (eventlog_version == 2) {
  531. UEFI_PARTITION_TABLE_HEADER *header = &data->UEFIPartitionHeader;
  532. char guid[37] = { 0 };
  533. uuid_unparse_lower(header->DiskGUID, guid);
  534. tpm2_tool_output(" Event:\n"
  535. " Header:\n"
  536. " Signature: \"%.*s\"\n"
  537. " Revision: 0x%" PRIx32 "\n"
  538. " HeaderSize: %" PRIu32 "\n"
  539. " HeaderCRC32: 0x%" PRIx32 "\n"
  540. " MyLBA: 0x%" PRIx64 "\n"
  541. " AlternateLBA: 0x%" PRIx64 "\n"
  542. " FirstUsableLBA: 0x%" PRIx64 "\n"
  543. " LastUsableLBA: 0x%" PRIx64 "\n"
  544. " DiskGUID: %s\n"
  545. " PartitionEntryLBA: 0x%" PRIx64 "\n"
  546. " NumberOfPartitionEntry: %" PRIu32 "\n"
  547. " SizeOfPartitionEntry: %" PRIu32 "\n"
  548. " PartitionEntryArrayCRC32: 0x%" PRIx32 "\n"
  549. " NumberOfPartitions: %" PRIu64 "\n"
  550. " Partitions:\n",
  551. 8, (char*)&header->Signature, /* 8-char ASCII string */
  552. header->Revision,
  553. header->HeaderSize,
  554. header->HeaderCRC32,
  555. header->MyLBA,
  556. header->AlternateLBA,
  557. header->FirstUsableLBA,
  558. header->LastUsableLBA,
  559. guid,
  560. header->PartitionEntryLBA,
  561. header->NumberOfPartitionEntries,
  562. header->SizeOfPartitionEntry,
  563. header->PartitionEntryArrayCRC32,
  564. data->NumberOfPartitions);
  565. size -= (sizeof(data->UEFIPartitionHeader) + sizeof(data->NumberOfPartitions));
  566. UINT64 i;
  567. UEFI_PARTITION_ENTRY *partition = data->Partitions;
  568. for (i = 0; i < data->NumberOfPartitions; i++) {
  569. if (size < sizeof(*partition)) {
  570. LOG_ERR("Cannot parse GPT partition entry: insufficient data (%zu)\n", size);
  571. return false;
  572. }
  573. uuid_unparse_lower(partition->PartitionTypeGUID, guid);
  574. tpm2_tool_output(" - PartitionTypeGUID: %s\n", guid);
  575. uuid_unparse_lower(partition->UniquePartitionGUID, guid);
  576. tpm2_tool_output(" UniquePartitionGUID: %s\n"
  577. " StartingLBA: 0x%" PRIx64 "\n"
  578. " EndingLBA: 0x%" PRIx64 "\n"
  579. " Attributes: 0x%" PRIx64 "\n"
  580. " PartitionName: \"%.*s\"\n",
  581. guid,
  582. partition->StartingLBA,
  583. partition->EndingLBA,
  584. partition->Attributes,
  585. 72, partition->PartitionName);
  586. size -= sizeof(*partition);
  587. }
  588. if (size != 0) {
  589. LOG_ERR("EventSize is inconsistent with actual data\n");
  590. return false;
  591. }
  592. } else {
  593. char hexstr[EVENT_BUF_MAX] = { 0, };
  594. bytes_to_str((UINT8*)data, size, hexstr, sizeof(hexstr));
  595. tpm2_tool_output(" Event: \"%s\"\n", hexstr);
  596. }
  597. return true;
  598. }
  599. bool yaml_event2data(TCG_EVENT2 const *event, UINT32 type, uint32_t eventlog_version) {
  600. char hexstr[EVENT_BUF_MAX] = { 0, };
  601. tpm2_tool_output(" EventSize: %" PRIu32 "\n", event->EventSize);
  602. if (event->EventSize == 0) {
  603. return true;
  604. }
  605. switch (type) {
  606. case EV_EFI_VARIABLE_DRIVER_CONFIG:
  607. case EV_EFI_VARIABLE_BOOT:
  608. case EV_EFI_VARIABLE_AUTHORITY:
  609. return yaml_uefi_var((UEFI_VARIABLE_DATA*)event->Event,
  610. event->EventSize, type, eventlog_version);
  611. case EV_POST_CODE:
  612. return yaml_uefi_post_code(event);
  613. case EV_S_CRTM_CONTENTS:
  614. case EV_EFI_PLATFORM_FIRMWARE_BLOB:
  615. return yaml_uefi_platfwblob((UEFI_PLATFORM_FIRMWARE_BLOB*)event->Event);
  616. case EV_EFI_ACTION:
  617. return yaml_uefi_action(event->Event, event->EventSize);
  618. case EV_IPL:
  619. return yaml_ipl(event->Event, event->EventSize);
  620. case EV_EFI_BOOT_SERVICES_APPLICATION:
  621. case EV_EFI_BOOT_SERVICES_DRIVER:
  622. case EV_EFI_RUNTIME_SERVICES_DRIVER:
  623. return yaml_uefi_image_load((UEFI_IMAGE_LOAD_EVENT*)event->Event,
  624. event->EventSize);
  625. case EV_EFI_GPT_EVENT:
  626. return yaml_gpt((UEFI_GPT_DATA*)event->Event,
  627. event->EventSize, eventlog_version);
  628. default:
  629. bytes_to_str(event->Event, event->EventSize, hexstr, sizeof(hexstr));
  630. tpm2_tool_output(" Event: \"%s\"\n", hexstr);
  631. return true;
  632. }
  633. }
  634. bool yaml_event2data_callback(TCG_EVENT2 const *event, UINT32 type,
  635. void *data, uint32_t eventlog_version) {
  636. (void)data;
  637. return yaml_event2data(event, type, eventlog_version);
  638. }
  639. bool yaml_digest2_callback(TCG_DIGEST2 const *digest, size_t size,
  640. void *data_in) {
  641. (void)data_in;
  642. return yaml_digest2(digest, size);
  643. }
  644. bool yaml_event2hdr_callback(TCG_EVENT_HEADER2 const *eventhdr, size_t size,
  645. void *data_in) {
  646. size_t *count = (size_t*)data_in;
  647. if (count == NULL) {
  648. LOG_ERR("callback requires user data");
  649. return false;
  650. }
  651. tpm2_tool_output("- EventNum: %zu\n", (*count)++);
  652. yaml_event2hdr(eventhdr, size);
  653. tpm2_tool_output(" Digests:\n");
  654. return true;
  655. }
  656. bool yaml_sha1_log_eventhdr_callback(TCG_EVENT const *eventhdr, size_t size,
  657. void *data_in) {
  658. (void)data_in;
  659. yaml_sha1_log_eventhdr(eventhdr, size);
  660. char hexstr[BYTES_TO_HEX_STRING_SIZE(sizeof(eventhdr->digest))] = { 0, };
  661. bytes_to_str(eventhdr->digest, sizeof(eventhdr->digest), hexstr, sizeof(hexstr));
  662. tpm2_tool_output(" DigestCount: 1\n"
  663. " Digests:\n"
  664. " - AlgorithmId: %s\n"
  665. " Digest: \"%s\"\n",
  666. tpm2_alg_util_algtostr(TPM2_ALG_SHA1, tpm2_alg_util_flags_hash),
  667. hexstr);
  668. return true;
  669. }
  670. void yaml_eventhdr(TCG_EVENT const *event, size_t *count) {
  671. /* digest is 20 bytes, 2 chars / byte and null terminator for string*/
  672. char digest_hex[2*sizeof(event->digest) + 1] = {};
  673. bytes_to_str(event->digest, sizeof(event->digest), digest_hex, sizeof(digest_hex));
  674. tpm2_tool_output("- EventNum: %zu\n"
  675. " PCRIndex: %" PRIu32 "\n"
  676. " EventType: %s\n"
  677. " Digest: \"%s\"\n"
  678. " EventSize: %" PRIu32 "\n",
  679. (*count)++, event->pcrIndex,
  680. eventtype_to_string(event->eventType), digest_hex,
  681. event->eventDataSize);
  682. }
  683. void yaml_specid(TCG_SPECID_EVENT* specid) {
  684. /* 'Signature' defined as byte buf, spec treats it like string w/o null. */
  685. char sig_str[sizeof(specid->Signature) + 1] = { '\0', };
  686. memcpy(sig_str, specid->Signature, sizeof(specid->Signature));
  687. tpm2_tool_output(" SpecID:\n"
  688. " - Signature: %s\n"
  689. " platformClass: %" PRIu32 "\n"
  690. " specVersionMinor: %" PRIu8 "\n"
  691. " specVersionMajor: %" PRIu8 "\n"
  692. " specErrata: %" PRIu8 "\n"
  693. " uintnSize: %" PRIu8 "\n"
  694. " numberOfAlgorithms: %" PRIu32 "\n"
  695. " Algorithms:\n",
  696. sig_str,
  697. specid->platformClass, specid->specVersionMinor,
  698. specid->specVersionMajor, specid->specErrata,
  699. specid->uintnSize,
  700. specid->numberOfAlgorithms);
  701. }
  702. void yaml_specid_algs(TCG_SPECID_ALG const *alg, size_t count) {
  703. for (size_t i = 0; i < count; ++i, ++alg) {
  704. tpm2_tool_output(" - Algorithm[%zu]:\n"
  705. " algorithmId: %s\n"
  706. " digestSize: %" PRIu16 "\n",
  707. i,
  708. tpm2_alg_util_algtostr(alg->algorithmId,
  709. tpm2_alg_util_flags_hash),
  710. alg->digestSize);
  711. }
  712. }
  713. bool yaml_specid_vendor(TCG_VENDOR_INFO *vendor) {
  714. char *vendinfo_str;
  715. tpm2_tool_output(" vendorInfoSize: %" PRIu8 "\n", vendor->vendorInfoSize);
  716. if (vendor->vendorInfoSize == 0) {
  717. return true;
  718. }
  719. vendinfo_str = calloc(1, vendor->vendorInfoSize * 2 + 1);
  720. if (vendinfo_str == NULL) {
  721. LOG_ERR("failed to allocate memory for vendorInfo: %s\n",
  722. strerror(errno));
  723. return false;
  724. }
  725. bytes_to_str(vendor->vendorInfo, vendor->vendorInfoSize, vendinfo_str,
  726. vendor->vendorInfoSize * 2 + 1);
  727. tpm2_tool_output(" vendorInfo: \"%s\"\n", vendinfo_str);
  728. free(vendinfo_str);
  729. return true;
  730. }
  731. bool yaml_specid_event(TCG_EVENT const *event, size_t *count) {
  732. TCG_SPECID_EVENT *specid = (TCG_SPECID_EVENT*)event->event;
  733. TCG_SPECID_ALG *alg = (TCG_SPECID_ALG*)specid->digestSizes;
  734. TCG_VENDOR_INFO *vendor = (TCG_VENDOR_INFO*)(alg + specid->numberOfAlgorithms);
  735. yaml_eventhdr(event, count);
  736. yaml_specid(specid);
  737. yaml_specid_algs(alg, specid->numberOfAlgorithms);
  738. return yaml_specid_vendor(vendor);
  739. }
  740. bool yaml_specid_callback(TCG_EVENT const *event, void *data) {
  741. size_t *count = (size_t*)data;
  742. return yaml_specid_event(event, count);
  743. }
  744. static void yaml_eventlog_pcrs(tpm2_eventlog_context *ctx) {
  745. char hexstr[DIGEST_HEX_STRING_MAX] = { 0, };
  746. tpm2_tool_output("pcrs:\n");
  747. if (ctx->sha1_used != 0) {
  748. tpm2_tool_output(" sha1:\n");
  749. for(unsigned i = 0 ; i < TPM2_MAX_PCRS ; i++) {
  750. if ((ctx->sha1_used & (1 << i)) == 0)
  751. continue;
  752. bytes_to_str(ctx->sha1_pcrs[i], sizeof(ctx->sha1_pcrs[i]),
  753. hexstr, sizeof(hexstr));
  754. tpm2_tool_output(" %-2d : 0x%s\n", i, hexstr);
  755. }
  756. }
  757. if (ctx->sha256_used != 0) {
  758. tpm2_tool_output(" sha256:\n");
  759. for(unsigned i = 0 ; i < TPM2_MAX_PCRS ; i++) {
  760. if ((ctx->sha256_used & (1 << i)) == 0)
  761. continue;
  762. bytes_to_str(ctx->sha256_pcrs[i], sizeof(ctx->sha256_pcrs[i]),
  763. hexstr, sizeof(hexstr));
  764. tpm2_tool_output(" %-2d : 0x%s\n", i, hexstr);
  765. }
  766. }
  767. if (ctx->sha384_used != 0) {
  768. tpm2_tool_output(" sha384:\n");
  769. for(unsigned i = 0 ; i < TPM2_MAX_PCRS ; i++) {
  770. if ((ctx->sha384_used & (1 << i)) == 0)
  771. continue;
  772. bytes_to_str(ctx->sha384_pcrs[i], sizeof(ctx->sha384_pcrs[i]),
  773. hexstr, sizeof(hexstr));
  774. tpm2_tool_output(" %-2d : 0x%s\n", i, hexstr);
  775. }
  776. }
  777. if (ctx->sha512_used != 0) {
  778. tpm2_tool_output(" sha512:\n");
  779. for(unsigned i = 0 ; i < TPM2_MAX_PCRS ; i++) {
  780. if ((ctx->sha512_used & (1 << i)) == 0)
  781. continue;
  782. bytes_to_str(ctx->sha512_pcrs[i], sizeof(ctx->sha512_pcrs[i]),
  783. hexstr, sizeof(hexstr));
  784. tpm2_tool_output(" %-2d : 0x%s\n", i, hexstr);
  785. }
  786. }
  787. if (ctx->sm3_256_used != 0) {
  788. tpm2_tool_output(" sm3_256:\n");
  789. for(unsigned i = 0 ; i < TPM2_MAX_PCRS ; i++) {
  790. if ((ctx->sm3_256_used & (1 << i)) == 0)
  791. continue;
  792. bytes_to_str(ctx->sm3_256_pcrs[i], sizeof(ctx->sm3_256_pcrs[i]),
  793. hexstr, sizeof(hexstr));
  794. tpm2_tool_output(" %-2d : 0x%s\n", i, hexstr);
  795. }
  796. }
  797. }
  798. bool yaml_eventlog(UINT8 const *eventlog, size_t size, uint32_t eventlog_version) {
  799. if (eventlog_version < MIN_EVLOG_YAML_VERSION ||
  800. eventlog_version > MAX_EVLOG_YAML_VERSION) {
  801. LOG_ERR("Unexpected YAML version number: %u\n", eventlog_version);
  802. return false;
  803. }
  804. size_t count = 0;
  805. tpm2_eventlog_context ctx = {
  806. .data = &count,
  807. .specid_cb = yaml_specid_callback,
  808. .event2hdr_cb = yaml_event2hdr_callback,
  809. .log_eventhdr_cb = yaml_sha1_log_eventhdr_callback,
  810. .digest2_cb = yaml_digest2_callback,
  811. .event2_cb = yaml_event2data_callback,
  812. .eventlog_version = eventlog_version,
  813. };
  814. tpm2_tool_output("---\n");
  815. tpm2_tool_output("version: %u\n", eventlog_version);
  816. tpm2_tool_output("events:\n");
  817. bool rc = parse_eventlog(&ctx, eventlog, size);
  818. if (!rc) {
  819. return rc;
  820. }
  821. yaml_eventlog_pcrs(&ctx);
  822. return true;
  823. }