tpm2_checkquote.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. /* SPDX-License-Identifier: BSD-3-Clause */
  2. #include <inttypes.h>
  3. #include <stdbool.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <openssl/pem.h>
  8. #include <openssl/err.h>
  9. #include "files.h"
  10. #include "log.h"
  11. #include "object.h"
  12. #include "tpm2_alg_util.h"
  13. #include "tpm2_convert.h"
  14. #include "tpm2_openssl.h"
  15. #include "tpm2_options.h"
  16. #include "tpm2_systemdeps.h"
  17. #include "tpm2_tool.h"
  18. #include "tpm2_eventlog.h"
  19. typedef struct tpm2_verifysig_ctx tpm2_verifysig_ctx;
  20. struct tpm2_verifysig_ctx {
  21. union {
  22. struct {
  23. UINT8 msg :1;
  24. UINT8 sig :1;
  25. UINT8 pcr :1;
  26. UINT8 hlg :1;
  27. UINT8 eventlog :1;
  28. };
  29. UINT8 all;
  30. } flags;
  31. TPMI_ALG_HASH halg;
  32. TPM2B_DIGEST msg_hash;
  33. TPM2B_DIGEST pcr_hash;
  34. TPMS_ATTEST attest;
  35. TPM2B_DATA extra_data;
  36. TPM2B_MAX_BUFFER signature;
  37. char *msg_file_path;
  38. char *sig_file_path;
  39. char *out_file_path;
  40. char *pcr_file_path;
  41. const char *pubkey_file_path;
  42. char *eventlog_path;
  43. tpm2_loaded_object key_context_object;
  44. const char *pcr_selection_string;
  45. };
  46. static tpm2_verifysig_ctx ctx = {
  47. .halg = TPM2_ALG_SHA256,
  48. .msg_hash = TPM2B_TYPE_INIT(TPM2B_DIGEST, buffer),
  49. .pcr_hash = TPM2B_TYPE_INIT(TPM2B_DIGEST, buffer),
  50. };
  51. static bool verify(void) {
  52. bool result = false;
  53. /* read the public key */
  54. EVP_PKEY *pkey = NULL;
  55. bool ret = tpm2_public_load_pkey(ctx.pubkey_file_path, &pkey);
  56. if (!ret) {
  57. return false;
  58. }
  59. EVP_PKEY_CTX *pkey_ctx = EVP_PKEY_CTX_new(pkey, NULL);
  60. if (!pkey_ctx) {
  61. LOG_ERR("EVP_PKEY_CTX_new failed: %s", ERR_error_string(ERR_get_error(), NULL));
  62. goto err;
  63. }
  64. /* get the digest alg */
  65. /* TODO SPlit loading on plain vs tss format to detect the hash alg */
  66. /* If its a plain sig we need -g */
  67. const EVP_MD *md = tpm2_openssl_halg_from_tpmhalg(ctx.halg);
  68. // TODO error handling
  69. int rc = EVP_PKEY_verify_init(pkey_ctx);
  70. if (!rc) {
  71. LOG_ERR("EVP_PKEY_verify_init failed: %s", ERR_error_string(ERR_get_error(), NULL));
  72. goto err;
  73. }
  74. rc = EVP_PKEY_CTX_set_signature_md(pkey_ctx, md);
  75. if (!rc) {
  76. LOG_ERR("EVP_PKEY_CTX_set_signature_md failed: %s", ERR_error_string(ERR_get_error(), NULL));
  77. goto err;
  78. }
  79. /* TODO dump actual signature */
  80. tpm2_tool_output("sig: ");
  81. tpm2_util_hexdump(ctx.signature.buffer, ctx.signature.size);
  82. tpm2_tool_output("\n");
  83. // Verify the signature matches message digest
  84. rc = EVP_PKEY_verify(pkey_ctx, ctx.signature.buffer, ctx.signature.size,
  85. ctx.msg_hash.buffer, ctx.msg_hash.size);
  86. if (rc != 1) {
  87. if (rc == 0) {
  88. LOG_ERR("Error validating signed message with public key provided");
  89. } else {
  90. LOG_ERR("Error %s", ERR_error_string(ERR_get_error(), NULL));
  91. }
  92. goto err;
  93. }
  94. // Ensure nonce is the same as given
  95. if (ctx.attest.extraData.size != ctx.extra_data.size ||
  96. memcmp(ctx.attest.extraData.buffer, ctx.extra_data.buffer,
  97. ctx.extra_data.size) != 0) {
  98. LOG_ERR("Error validating nonce from quote");
  99. goto err;
  100. }
  101. // Also ensure digest from quote matches PCR digest
  102. if (ctx.flags.pcr) {
  103. if (!tpm2_util_verify_digests(&ctx.attest.attested.quote.pcrDigest,
  104. &ctx.pcr_hash)) {
  105. LOG_ERR("Error validating PCR composite against signed message");
  106. goto err;
  107. }
  108. }
  109. result = true;
  110. err:
  111. EVP_PKEY_free(pkey);
  112. EVP_PKEY_CTX_free(pkey_ctx);
  113. return result;
  114. }
  115. static TPM2B_ATTEST *message_from_file(const char *msg_file_path) {
  116. unsigned long size;
  117. bool result = files_get_file_size_path(msg_file_path, &size);
  118. if (!result) {
  119. return NULL;
  120. }
  121. if (!size) {
  122. LOG_ERR("The msg file \"%s\" is empty", msg_file_path);
  123. return NULL;
  124. }
  125. TPM2B_ATTEST *msg = (TPM2B_ATTEST *) calloc(1, sizeof(TPM2B_ATTEST) + size);
  126. if (!msg) {
  127. LOG_ERR("OOM");
  128. return NULL;
  129. }
  130. UINT16 tmp = msg->size = size;
  131. if (!files_load_bytes_from_path(msg_file_path, msg->attestationData,
  132. &tmp)) {
  133. free(msg);
  134. return NULL;
  135. }
  136. return msg;
  137. }
  138. static bool parse_selection_data_from_selection_string(FILE *pcr_input,
  139. TPML_PCR_SELECTION *pcr_select, tpm2_pcrs *pcrs) {
  140. bool result = pcr_parse_selections(ctx.pcr_selection_string, pcr_select);
  141. if (!result) {
  142. LOG_ERR("Could not parse PCR selections");
  143. return false;
  144. }
  145. /*
  146. * A tpm2_pcrs->pcr_values[tpm2_pcrs->count] is a TPML_DIGEST structure
  147. * which can hold a maximum of 8 digests. Once the count of 8 is exhausted
  148. * we need a new TPML_DIGEST structure.
  149. *
  150. * The digests count in a list is tracked with
  151. * tpm2_pcrs->pcr_values[tpm2_pcrs->count].count
  152. *
  153. * A total of such lists is tracked by the tpm2_pcrs->count.
  154. */
  155. unsigned i = 0;
  156. unsigned j = 0;
  157. unsigned read_size = 0;
  158. size_t read_count = 0;
  159. unsigned digest_list_count = 0;
  160. memset(pcrs, 0, sizeof(tpm2_pcrs));
  161. /*
  162. * Iterate through all the PCR banks selected.
  163. */
  164. for (i = 0; i < pcr_select->count; i++) {
  165. /*
  166. * Ensure all the digests across banks can fit in tpm2_pcrs.
  167. */
  168. if (digest_list_count >= TPM2_MAX_PCRS - 1) {
  169. LOG_ERR("Maximum count for allowed digest lists reached.");
  170. return false;
  171. }
  172. /*
  173. * Digest size of PCR bank selected in this iteration.
  174. */
  175. read_size = tpm2_alg_util_get_hash_size(pcr_select->pcrSelections[i].hash);
  176. /*
  177. * Iterate through pcrSelect bytes to find selected PCR index bitmap.
  178. */
  179. for (j = 0; j < pcr_select->pcrSelections[i].sizeofSelect * 8; j++) {
  180. /*
  181. * Test if PCR index select is true.
  182. */
  183. if ((pcr_select->pcrSelections[i].pcrSelect[j / 8] & 1 << (j % 8))
  184. != 0) {
  185. /*
  186. * Read the digest at a selected PCR index.
  187. */
  188. pcrs->pcr_values[digest_list_count].digests[pcrs->pcr_values[
  189. digest_list_count].count].size = read_size;
  190. read_count = fread(pcrs->pcr_values[digest_list_count].digests[
  191. pcrs->pcr_values[digest_list_count].count].buffer,
  192. read_size, 1, pcr_input);
  193. if (read_count != 1) {
  194. LOG_ERR("Failed to read PCR digests from file");
  195. return false;
  196. }
  197. /*
  198. * Ensure we don't overrun the allowed digest count in a
  199. * TPML_DIGEST.
  200. */
  201. if (pcrs->pcr_values[digest_list_count].count == 7) {
  202. digest_list_count++;
  203. } else {
  204. /*
  205. * Ensure we populate the digest in a new list if we
  206. * exhausted the digest count in the current TPML_DIGEST
  207. * instance.
  208. */
  209. pcrs->pcr_values[digest_list_count].count++;
  210. }
  211. }
  212. }
  213. }
  214. /*
  215. * Update the count of total TPML_DIGEST consumed to accomodate all the
  216. * selected PCR indices across all the banks.
  217. */
  218. pcrs->count = digest_list_count + 1;
  219. return true;
  220. }
  221. static bool parse_selection_data_from_file(FILE *pcr_input,
  222. TPML_PCR_SELECTION *pcr_select, tpm2_pcrs *pcrs) {
  223. // Import TPML_PCR_SELECTION structure to pcr outfile
  224. if (fread(pcr_select, sizeof(TPML_PCR_SELECTION), 1, pcr_input) != 1) {
  225. LOG_ERR("Failed to read PCR selection from file");
  226. return false;
  227. }
  228. // Import PCR digests to pcr outfile
  229. if (fread(&pcrs->count, sizeof(UINT32), 1, pcr_input) != 1) {
  230. LOG_ERR("Failed to read PCR digests header from file");
  231. return false;
  232. }
  233. if (le64toh(pcrs->count) > ARRAY_LEN(pcrs->pcr_values)) {
  234. LOG_ERR("Malformed PCR file, pcr count cannot be greater than %zu, got: %" PRIu64 " ",
  235. ARRAY_LEN(pcrs->pcr_values), le64toh((UINT64)pcrs->count));
  236. return false;
  237. }
  238. size_t j;
  239. for (j = 0; j < le64toh(pcrs->count); j++) {
  240. if (fread(&pcrs->pcr_values[j], sizeof(TPML_DIGEST), 1, pcr_input)
  241. != 1) {
  242. LOG_ERR("Failed to read PCR digest from file");
  243. return false;
  244. }
  245. }
  246. return true;
  247. }
  248. static bool pcrs_from_file(const char *pcr_file_path,
  249. TPML_PCR_SELECTION *pcr_select, tpm2_pcrs *pcrs) {
  250. bool result = false;
  251. unsigned long size;
  252. if (!files_get_file_size_path(pcr_file_path, &size)) {
  253. return false;
  254. }
  255. if (!size) {
  256. LOG_ERR("The pcr file \"%s\" is empty", pcr_file_path);
  257. return false;
  258. }
  259. FILE *pcr_input = fopen(pcr_file_path, "rb");
  260. if (!pcr_input) {
  261. LOG_ERR("Could not open PCRs input file \"%s\" error: \"%s\"",
  262. pcr_file_path, strerror(errno));
  263. goto out;
  264. }
  265. if (!ctx.pcr_selection_string) {
  266. result = parse_selection_data_from_file(pcr_input, pcr_select, pcrs);
  267. if (!result) {
  268. goto out;
  269. }
  270. } else {
  271. result = parse_selection_data_from_selection_string(pcr_input,
  272. pcr_select, pcrs);
  273. if (!result) {
  274. goto out;
  275. }
  276. }
  277. result = true;
  278. out:
  279. if (pcr_input) {
  280. fclose(pcr_input);
  281. }
  282. return result;
  283. }
  284. static bool eventlog_from_file(tpm2_eventlog_context *evctx, const char *file_path) {
  285. unsigned long size;
  286. if (!files_get_file_size_path(file_path, &size)) {
  287. return false;
  288. }
  289. if (!size) {
  290. LOG_ERR("The eventlog file \"%s\" is empty", file_path);
  291. return false;
  292. }
  293. uint8_t *eventlog = calloc(1, size);
  294. if (!eventlog) {
  295. LOG_ERR("OOM");
  296. return false;
  297. }
  298. uint16_t size_tmp = size;
  299. if (!files_load_bytes_from_path(file_path, eventlog, &size_tmp)) {
  300. free(eventlog);
  301. return false;
  302. }
  303. bool rc = parse_eventlog(evctx, eventlog, size);
  304. free(eventlog);
  305. return rc;
  306. }
  307. static tool_rc init(void) {
  308. /* check flags for mismatches */
  309. if (!(ctx.pubkey_file_path && ctx.flags.sig && ctx.flags.msg)) {
  310. LOG_ERR(
  311. "--pubkey (-u), --msg (-m) and --sig (-s) are required");
  312. return tool_rc_option_error;
  313. }
  314. if (ctx.flags.eventlog && !ctx.flags.pcr) {
  315. LOG_ERR("PCR file is required to validate eventlog");
  316. return tool_rc_option_error;
  317. }
  318. TPM2B_ATTEST *msg = NULL;
  319. TPML_PCR_SELECTION pcr_select;
  320. tpm2_pcrs *pcrs;
  321. tpm2_pcrs temp_pcrs;
  322. tool_rc return_value = tool_rc_general_error;
  323. msg = message_from_file(ctx.msg_file_path);
  324. if (!msg) {
  325. /* message_from_file() logs specific error no need to here */
  326. return tool_rc_general_error;
  327. }
  328. /*
  329. * If the caller specifies the signature format, like rsassa, that means
  330. * the caller doesn't have the TPMT signature, but rather a plain signature,
  331. * and we need to trust what was set in -g as the hash algorithm. The
  332. * verification will fail.
  333. *
  334. * In the case of the TSS signature format, we have the hash alg, so if the user
  335. * specifies the hash alg, or we're guessing, we should use the right one.
  336. */
  337. TPMI_ALG_HASH expected_halg = TPM2_ALG_ERROR;
  338. bool res = tpm2_convert_sig_load_plain(ctx.sig_file_path,
  339. &ctx.signature, &expected_halg);
  340. if (!res) {
  341. goto err;
  342. }
  343. if (expected_halg != TPM2_ALG_NULL) {
  344. if (ctx.halg != expected_halg) {
  345. if (ctx.flags.hlg) {
  346. const char *got_str = tpm2_alg_util_algtostr(ctx.halg, tpm2_alg_util_flags_any);
  347. const char *expected_str = tpm2_alg_util_algtostr(expected_halg, tpm2_alg_util_flags_any);
  348. LOG_WARN("User specified hash algorithm of \"%s\", does not match"
  349. "expected hash algorithm of \"%s\", using: \"%s\"",
  350. got_str, expected_str, expected_str);
  351. }
  352. ctx.halg = expected_halg;
  353. }
  354. }
  355. /* If no digest is specified, compute it */
  356. if (!ctx.flags.msg) {
  357. /*
  358. * This is a redundant check since main() checks this case, but we'll add it here to silence any
  359. * complainers.
  360. */
  361. LOG_ERR("No digest set and no message file to compute from, cannot "
  362. "compute message hash!");
  363. goto err;
  364. }
  365. if (ctx.flags.pcr) {
  366. if (pcrs_from_file(ctx.pcr_file_path, &pcr_select, &temp_pcrs)) {
  367. /* pcrs_from_file() logs specific error no need to here */
  368. pcrs = &temp_pcrs;
  369. } else {
  370. goto err;
  371. }
  372. if (le32toh(pcr_select.count) > TPM2_NUM_PCR_BANKS)
  373. goto err;
  374. UINT32 i;
  375. for (i = 0; i < le32toh(pcr_select.count); i++)
  376. if (le16toh(pcr_select.pcrSelections[i].hash) == TPM2_ALG_ERROR)
  377. goto err;
  378. if (!tpm2_openssl_hash_pcr_banks_le(ctx.halg, &pcr_select, pcrs,
  379. &ctx.pcr_hash)) {
  380. LOG_ERR("Failed to hash PCR values related to quote!");
  381. goto err;
  382. }
  383. if (!pcr_print_pcr_struct_le(&pcr_select, pcrs)) {
  384. LOG_ERR("Failed to print PCR values related to quote!");
  385. goto err;
  386. }
  387. }
  388. if (ctx.flags.eventlog && ctx.flags.pcr) {
  389. if (pcrs_from_file(ctx.pcr_file_path, &pcr_select, &temp_pcrs)) {
  390. /* pcrs_from_file() logs specific error no need to here */
  391. pcrs = &temp_pcrs;
  392. } else {
  393. goto err;
  394. }
  395. if (pcr_select.count > TPM2_NUM_PCR_BANKS)
  396. goto err;
  397. tpm2_eventlog_context eventlog_ctx = { 0 };
  398. bool rc = eventlog_from_file(&eventlog_ctx, ctx.eventlog_path);
  399. if (!rc) {
  400. LOG_ERR("Failed to process eventlog");
  401. goto err;
  402. }
  403. bool eventlog_fail = false;
  404. unsigned vi = 0;
  405. unsigned di = 0;
  406. for (unsigned i = 0; i < pcr_select.count; i++) {
  407. const TPMS_PCR_SELECTION *const sel = &pcr_select.pcrSelections[i];
  408. // Loop through all PCRs in this bank
  409. const unsigned bank_size = sel->sizeofSelect * 8;
  410. for (unsigned pcr_id = 0; pcr_id < bank_size; pcr_id++) {
  411. // skip non-selected banks
  412. if (!tpm2_util_is_pcr_select_bit_set(sel, pcr_id)) {
  413. continue;
  414. }
  415. if (vi >= pcrs->count || di >= pcrs->pcr_values[vi].count) {
  416. LOG_ERR("Something wrong, trying to print but nothing more");
  417. eventlog_fail = true;
  418. break;
  419. }
  420. // Compare this digest to the computed value from the eventlog
  421. const TPM2B_DIGEST *pcr = &pcrs->pcr_values[vi].digests[di];
  422. const uint8_t *pcr_q = pcr->buffer;
  423. const uint8_t *pcr_e = NULL;
  424. if (sel->hash == TPM2_ALG_SHA1 && pcr->size == TPM2_SHA1_DIGEST_SIZE) {
  425. pcr_e = eventlog_ctx.sha1_pcrs[pcr_id];
  426. } else if (sel->hash == TPM2_ALG_SHA256 && pcr->size == TPM2_SHA256_DIGEST_SIZE) {
  427. pcr_e = eventlog_ctx.sha256_pcrs[pcr_id];
  428. } else if (sel->hash == TPM2_ALG_SHA384 && pcr->size == TPM2_SHA384_DIGEST_SIZE) {
  429. pcr_e = eventlog_ctx.sha384_pcrs[pcr_id];
  430. } else if (sel->hash == TPM2_ALG_SHA512 && pcr->size == TPM2_SHA512_DIGEST_SIZE) {
  431. pcr_e = eventlog_ctx.sha512_pcrs[pcr_id];
  432. } else if (sel->hash == TPM2_ALG_SM3_256 && pcr->size == TPM2_SM3_256_DIGEST_SIZE) {
  433. pcr_e = eventlog_ctx.sm3_256_pcrs[pcr_id];
  434. } else {
  435. LOG_WARN("PCR%u unsupported algorithm/size %u/%u", pcr_id, sel->hash, pcr->size);
  436. eventlog_fail = 1;
  437. }
  438. if (pcr_e && memcmp(pcr_e, pcr_q, pcr->size) != 0) {
  439. LOG_WARN("PCR%u mismatch", pcr_id);
  440. eventlog_fail = 1;
  441. }
  442. if (++di < pcrs->pcr_values[vi].count) {
  443. continue;
  444. }
  445. di = 0;
  446. if (++vi < pcrs->count) {
  447. continue;
  448. }
  449. }
  450. }
  451. if (eventlog_fail) {
  452. LOG_ERR("Eventlog and quote PCR mismatch");
  453. goto err;
  454. }
  455. }
  456. tool_rc tmp_rc = files_tpm2b_attest_to_tpms_attest(msg, &ctx.attest);
  457. if (tmp_rc != tool_rc_success) {
  458. return_value = tmp_rc;
  459. goto err;
  460. }
  461. // Figure out the digest for this message
  462. res = tpm2_openssl_hash_compute_data(ctx.halg, msg->attestationData,
  463. msg->size, &ctx.msg_hash);
  464. if (!res) {
  465. LOG_ERR("Compute message hash failed!");
  466. goto err;
  467. }
  468. return_value = tool_rc_success;
  469. err:
  470. free(msg);
  471. return return_value;
  472. }
  473. static bool on_option(char key, char *value) {
  474. switch (key) {
  475. case 'u':
  476. ctx.pubkey_file_path = value;
  477. break;
  478. case 'g': {
  479. ctx.halg = tpm2_alg_util_from_optarg(value, tpm2_alg_util_flags_hash);
  480. if (ctx.halg == TPM2_ALG_ERROR) {
  481. LOG_ERR("Unable to convert algorithm, got: \"%s\"", value);
  482. return false;
  483. }
  484. ctx.flags.hlg = 1;
  485. }
  486. break;
  487. case 'm': {
  488. ctx.msg_file_path = value;
  489. ctx.flags.msg = 1;
  490. }
  491. break;
  492. case 'F':
  493. LOG_WARN("DEPRECATED: Format ignored");
  494. break;
  495. case 'q':
  496. ctx.extra_data.size = sizeof(ctx.extra_data.buffer);
  497. return tpm2_util_bin_from_hex_or_file(value, &ctx.extra_data.size,
  498. ctx.extra_data.buffer);
  499. break;
  500. case 's':
  501. ctx.sig_file_path = value;
  502. ctx.flags.sig = 1;
  503. break;
  504. case 'f':
  505. ctx.pcr_file_path = value;
  506. ctx.flags.pcr = 1;
  507. break;
  508. case 'e':
  509. ctx.eventlog_path = value;
  510. ctx.flags.eventlog = 1;
  511. break;
  512. case 'l':
  513. ctx.pcr_selection_string = value;
  514. break;
  515. /* no default */
  516. }
  517. return true;
  518. }
  519. static bool tpm2_tool_onstart(tpm2_options **opts) {
  520. const struct option topts[] = {
  521. { "hash-algorithm", required_argument, NULL, 'g' },
  522. { "message", required_argument, NULL, 'm' },
  523. { "format", required_argument, NULL, 'F' },
  524. { "signature", required_argument, NULL, 's' },
  525. { "eventlog", required_argument, NULL, 'e' },
  526. { "pcr", required_argument, NULL, 'f' },
  527. { "pcr-list", required_argument, NULL, 'l' },
  528. { "public", required_argument, NULL, 'u' },
  529. { "qualification", required_argument, NULL, 'q' },
  530. };
  531. *opts = tpm2_options_new("g:m:F:s:u:f:q:e:l:", ARRAY_LEN(topts), topts,
  532. on_option, NULL, TPM2_OPTIONS_NO_SAPI);
  533. return *opts != NULL;
  534. }
  535. static tool_rc tpm2_tool_onrun(ESYS_CONTEXT *ectx, tpm2_option_flags flags) {
  536. UNUSED(ectx);
  537. UNUSED(flags);
  538. /* initialize and process */
  539. tool_rc rc = init();
  540. if (rc != tool_rc_success) {
  541. return rc;
  542. }
  543. bool res = verify();
  544. if (!res) {
  545. LOG_ERR("Verify signature failed!");
  546. return tool_rc_general_error;
  547. }
  548. return tool_rc_success;
  549. }
  550. // Register this tool with tpm2_tool.c
  551. TPM2_TOOL_REGISTER("checkquote", tpm2_tool_onstart, tpm2_tool_onrun, NULL, NULL)