tpm2_tool.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /* SPDX-License-Identifier: BSD-3-Clause */
  2. #include <stdbool.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <openssl/err.h>
  6. #include <openssl/evp.h>
  7. #include <tss2/tss2_tctildr.h>
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10. #include "log.h"
  11. #include "tpm2_errata.h"
  12. #include "tpm2_options.h"
  13. #include "tpm2_tool.h"
  14. #include "tpm2_tool_output.h"
  15. static void esys_teardown(ESYS_CONTEXT **esys_context) {
  16. if (esys_context == NULL)
  17. return;
  18. if (*esys_context == NULL)
  19. return;
  20. Esys_Finalize(esys_context);
  21. }
  22. static void teardown_full(ESYS_CONTEXT **esys_context) {
  23. TSS2_TCTI_CONTEXT *tcti_context = NULL;
  24. TSS2_RC rc;
  25. if (!*esys_context) {
  26. return;
  27. }
  28. rc = Esys_GetTcti(*esys_context, &tcti_context);
  29. if (rc != TPM2_RC_SUCCESS)
  30. return;
  31. esys_teardown(esys_context);
  32. Tss2_TctiLdr_Finalize(&tcti_context);
  33. }
  34. static ESYS_CONTEXT *ctx_init(TSS2_TCTI_CONTEXT *tcti_ctx) {
  35. ESYS_CONTEXT *esys_ctx;
  36. TSS2_RC rval = Esys_Initialize(&esys_ctx, tcti_ctx, NULL);
  37. if (rval != TPM2_RC_SUCCESS) {
  38. LOG_PERR(Esys_Initialize, rval);
  39. return NULL;
  40. }
  41. return esys_ctx;
  42. }
  43. /*
  44. * Build a list of the TPM2 tools linked into this executable
  45. */
  46. #ifndef TPM2_TOOLS_MAX
  47. #define TPM2_TOOLS_MAX 1024
  48. #endif
  49. static const tpm2_tool *tools[TPM2_TOOLS_MAX];
  50. static unsigned tool_count;
  51. void tpm2_tool_register(const tpm2_tool *tool) {
  52. if (tool_count < TPM2_TOOLS_MAX) {
  53. tools[tool_count++] = tool;
  54. } else {
  55. LOG_ERR("Over tool count");
  56. abort();
  57. }
  58. }
  59. static const char *tpm2_tool_name(const char *arg) {
  60. const char *name = rindex(arg, '/');
  61. if (name) {
  62. name++; // skip the '/'
  63. } else {
  64. name = arg; // use the full executable name as is
  65. }
  66. if (strncmp(name, "tpm2_", 5) == 0) {
  67. name += 5;
  68. }
  69. return name;
  70. }
  71. static const tpm2_tool *tpm2_tool_lookup(int *argc, char ***argv)
  72. {
  73. // find the executable name in the path
  74. // and skip "tpm2_" prefix if it is present
  75. const char *name = tpm2_tool_name((*argv)[0]);
  76. // if this was invoked as 'tpm2', then try again with the second argument
  77. if (strcmp(name, "tpm2") == 0) {
  78. if (--(*argc) == 0) {
  79. return NULL;
  80. }
  81. (*argv)++;
  82. name = tpm2_tool_name((*argv)[0]);
  83. }
  84. // search the tools array for a matching name
  85. for(unsigned i = 0 ; i < tool_count ; i++)
  86. {
  87. const tpm2_tool * const tool = tools[i];
  88. if (!tool || !tool->name) {
  89. continue;
  90. }
  91. if (strcmp(name, tool->name) == 0) {
  92. return tool;
  93. }
  94. }
  95. // not found? should print a table of the tools
  96. return NULL;
  97. }
  98. /*
  99. * This program is a template for TPM2 tools that use the SAPI. It does
  100. * nothing more than parsing command line options that allow the caller to
  101. * specify which TCTI to use for the test.
  102. */
  103. static struct tool_context {
  104. ESYS_CONTEXT *ectx;
  105. tpm2_options *tool_opts;
  106. } ctx;
  107. static void main_onexit(void) {
  108. teardown_full(&ctx.ectx);
  109. tpm2_options_free(ctx.tool_opts);
  110. }
  111. int main(int argc, char **argv) {
  112. /* get rid of:
  113. * owner execute (1)
  114. * group execute (1)
  115. * other write + read + execute (7)
  116. */
  117. umask(0117);
  118. if (!strcmp(argv[0], "tpm2")) {
  119. if (argc == 1 || (argc == 2 && (!strcmp(argv[1],"--help") ||
  120. !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help=man")))) {
  121. char *options[2] = {"tpm2","--help=man"};
  122. tpm2_handle_options(2, options, 0, 0, 0);
  123. exit(tool_rc_success);
  124. }
  125. if ((argc == 2 && (!strcmp(argv[1],"--version") ||
  126. !strcmp(argv[1], "-v") ))) {
  127. tpm2_handle_options(argc, argv, 0, 0, 0);
  128. exit(tool_rc_success);
  129. }
  130. }
  131. /* don't buffer stdin/stdout/stderr so pipes work */
  132. setvbuf (stdin, NULL, _IONBF, 0);
  133. setvbuf (stdout, NULL, _IONBF, 0);
  134. setvbuf (stderr, NULL, _IONBF, 0);
  135. const tpm2_tool * const tool = tpm2_tool_lookup(&argc, &argv);
  136. if (!tool) {
  137. LOG_ERR("%s: unknown tool. Available tpm2 commands:", argv[0]);
  138. for(unsigned i = 0 ; i < tool_count ; i++) {
  139. fprintf(stderr, "%s\n", tools[i]->name);
  140. }
  141. exit(tool_rc_general_error);
  142. }
  143. atexit(main_onexit);
  144. tool_rc ret = tool_rc_general_error;
  145. if (tool->onstart) {
  146. bool res = tool->onstart(&ctx.tool_opts);
  147. if (!res) {
  148. LOG_ERR("retrieving tool options");
  149. exit(tool_rc_general_error);
  150. }
  151. }
  152. if (tool->onexit) {
  153. atexit(tool->onexit);
  154. }
  155. tpm2_option_flags flags = { .all = 0 };
  156. TSS2_TCTI_CONTEXT *tcti = NULL;
  157. tpm2_option_code rc = tpm2_handle_options(argc, argv, ctx.tool_opts, &flags,
  158. &tcti);
  159. if (rc != tpm2_option_code_continue) {
  160. ret = rc == tpm2_option_code_err ?
  161. tool_rc_general_error : tool_rc_success;
  162. exit(ret);
  163. }
  164. if (flags.verbose) {
  165. log_set_level(log_level_verbose);
  166. }
  167. /*
  168. * We don't want a cyclic dependency between tools/options. Resolving those
  169. * works well on linux/elf based systems, but darwin and windows tend to
  170. * fall flat on there face. This is why we set quiet mode outside of
  171. * option and argument life-cycle. Thus TOOL_OUTPUT is only guaranteed
  172. * to respect quiet from here on out (onrun and onexit).
  173. */
  174. if (flags.quiet) {
  175. tpm2_tool_output_disable();
  176. }
  177. if (tcti) {
  178. ctx.ectx = ctx_init(tcti);
  179. if (!ctx.ectx) {
  180. exit(tool_rc_tcti_error);
  181. }
  182. }
  183. if (flags.enable_errata) {
  184. tpm2_errata_init(ctx.ectx);
  185. }
  186. /*
  187. * Load the openssl error strings and algorithms
  188. * so library routines work as expected.
  189. */
  190. OpenSSL_add_all_algorithms();
  191. OpenSSL_add_all_ciphers();
  192. ERR_load_crypto_strings();
  193. /*
  194. * Call the specific tool, all tools implement this function instead of
  195. * 'main'.
  196. */
  197. ret = tool->onrun(ctx.ectx, flags);
  198. if (tool->onstop) {
  199. tool_rc tmp_rc = tool->onstop(ctx.ectx);
  200. /* if onrun() passed, the error code should come from onstop() */
  201. ret = ret == tool_rc_success ? tmp_rc : ret;
  202. }
  203. switch (ret) {
  204. case tool_rc_success:
  205. /* nothing to do here */
  206. break;
  207. case tool_rc_option_error:
  208. tpm2_print_usage(argv[0], ctx.tool_opts);
  209. break;
  210. default:
  211. LOG_ERR("Unable to run %s", argv[0]);
  212. }
  213. exit(ret);
  214. }