tpm2_policycountertimer.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /* SPDX-License-Identifier: BSD-3-Clause */
  2. #include <stddef.h>
  3. #include <stdlib.h>
  4. #include "log.h"
  5. #include "files.h"
  6. #include "tpm2.h"
  7. #include "tpm2_tool.h"
  8. #include "tpm2_nv_util.h"
  9. #include "tpm2_options.h"
  10. #include "tpm2_policy.h"
  11. #define OFFSET_TPMS_TIME_INFO_TIME offsetof(TPMS_TIME_INFO, time)
  12. #define OFFSET_TPMS_TIME_INFO_CLOCK offsetof(TPMS_TIME_INFO, clockInfo.clock)
  13. #define OFFSET_TPMS_TIME_INFO_RESETS offsetof(TPMS_TIME_INFO, clockInfo.resetCount)
  14. #define OFFSET_TPMS_TIME_INFO_RESTARTS offsetof(TPMS_TIME_INFO, clockInfo.restartCount)
  15. #define OFFSET_TPMS_TIME_INFO_SAFE offsetof(TPMS_TIME_INFO, clockInfo.safe);
  16. typedef struct tpm_policycountertimer_ctx tpm_policycountertimer_ctx;
  17. struct tpm_policycountertimer_ctx {
  18. //Inputs
  19. const char *session_path;
  20. tpm2_session *session;
  21. TPM2B_OPERAND operand_b;
  22. uint16_t offset;
  23. bool operation_set;
  24. TPM2_EO operation;
  25. //Output
  26. const char *policy_digest_path;
  27. };
  28. static tpm_policycountertimer_ctx ctx = {
  29. .operation = TPM2_EO_EQ,
  30. .offset = 0,
  31. };
  32. static bool convert_keyvalue_to_operand_buffer(const char *value,
  33. uint16_t offset, uint8_t size) {
  34. ctx.offset = offset;
  35. /*
  36. * Convert input string data to a *big endian* uint64_t or uint32_t
  37. */
  38. union data {
  39. uint32_t u32;
  40. uint64_t u64;
  41. uint8_t b;
  42. } data;
  43. bool result = false;
  44. switch(size) {
  45. case sizeof(uint32_t):
  46. result = tpm2_util_string_to_uint32(value, &data.u32);
  47. break;
  48. case sizeof(uint64_t):
  49. result = tpm2_util_string_to_uint64(value, &data.u64);
  50. break;
  51. default:
  52. LOG_ERR("Unknown size, got: %u", size);
  53. return false;
  54. }
  55. if (!result) {
  56. LOG_ERR("Invalid value specified for the key");
  57. return false;
  58. }
  59. /*
  60. * sizes should be u32 or u64 and thus never overflow a TPM2B_OPPERAND
  61. * but we will check anyways in case something changes elsewhere.
  62. */
  63. if (size > sizeof(ctx.operand_b.buffer)) {
  64. LOG_ERR("Size is too large for TPM2B_OPERAND. Got %u, max size is: %zu",
  65. size, sizeof(ctx.operand_b.buffer));
  66. return false;
  67. }
  68. ctx.operand_b.size = size;
  69. size_t i = 0;
  70. for (i = 0; i < size; i++) {
  71. ctx.operand_b.buffer[i] = *(&data.b + size - i - 1);
  72. }
  73. return true;
  74. }
  75. static bool on_arg(int argc, char **argv) {
  76. if (argc > 1) {
  77. LOG_ERR("Specify one argument as value/ parameter=value.");
  78. return false;
  79. }
  80. if (!strcmp("safe", argv[0])) {
  81. ctx.offset = OFFSET_TPMS_TIME_INFO_SAFE;
  82. ctx.operand_b.size = 1;
  83. ctx.operand_b.buffer[0] = TPM2_YES;
  84. return true;
  85. }
  86. const char *value;
  87. const char *key;
  88. char *a = argv[0];
  89. char *split = strchr(a, '=');
  90. if (!split) {
  91. value = argv[0];
  92. key = "time";
  93. } else {
  94. split[0] = '\0';
  95. value = split + 1;
  96. key = a;
  97. }
  98. if (!value[0]) {
  99. LOG_ERR("Must specify a corresponding value");
  100. return false;
  101. }
  102. // look up key and process value
  103. if (!strcmp("time", key)) {
  104. return convert_keyvalue_to_operand_buffer(value,
  105. OFFSET_TPMS_TIME_INFO_TIME, sizeof(uint64_t));
  106. }
  107. if (!strcmp("clock", key)) {
  108. return convert_keyvalue_to_operand_buffer(value,
  109. OFFSET_TPMS_TIME_INFO_CLOCK, sizeof(uint64_t));
  110. }
  111. if (!strcmp("resets", key)) {
  112. return convert_keyvalue_to_operand_buffer(value,
  113. OFFSET_TPMS_TIME_INFO_RESETS, sizeof(uint32_t));
  114. }
  115. if (!strcmp("restarts", key)) {
  116. return convert_keyvalue_to_operand_buffer(value,
  117. OFFSET_TPMS_TIME_INFO_RESTARTS, sizeof(uint32_t));
  118. }
  119. LOG_ERR("Unknown argument. Specify time/ clock/ resets/ restarts/ safe");
  120. return false;
  121. }
  122. static bool on_option(char key, char *value) {
  123. bool result = true;
  124. switch (key) {
  125. case 'L':
  126. ctx.policy_digest_path = value;
  127. break;
  128. case 'S':
  129. ctx.session_path = value;
  130. break;
  131. case TPM2_EO_EQ:
  132. case TPM2_EO_NEQ:
  133. case TPM2_EO_SIGNED_GT:
  134. case TPM2_EO_UNSIGNED_GT:
  135. case TPM2_EO_SIGNED_LT:
  136. case TPM2_EO_UNSIGNED_LT:
  137. case TPM2_EO_SIGNED_GE:
  138. case TPM2_EO_UNSIGNED_GE:
  139. case TPM2_EO_SIGNED_LE:
  140. case TPM2_EO_UNSIGNED_LE:
  141. case TPM2_EO_BITSET:
  142. case TPM2_EO_BITCLEAR:
  143. if (ctx.operation_set) {
  144. LOG_ERR("Only one operator can be specified");
  145. return false;
  146. }
  147. ctx.operation_set = true;
  148. ctx.operation = key;
  149. break;
  150. default:
  151. return false;
  152. }
  153. return result;
  154. }
  155. static bool tpm2_tool_onstart(tpm2_options **opts) {
  156. const struct option topts[] = {
  157. { "policy", required_argument, NULL, 'L' },
  158. { "session", required_argument, NULL, 'S' },
  159. { "eq", no_argument, NULL, TPM2_EO_EQ },
  160. { "neq", no_argument, NULL, TPM2_EO_NEQ },
  161. { "sgt", no_argument, NULL, TPM2_EO_SIGNED_GT },
  162. { "ugt", no_argument, NULL, TPM2_EO_UNSIGNED_GT },
  163. { "slt", no_argument, NULL, TPM2_EO_SIGNED_LT },
  164. { "ult", no_argument, NULL, TPM2_EO_UNSIGNED_LT },
  165. { "sge", no_argument, NULL, TPM2_EO_SIGNED_GE },
  166. { "uge", no_argument, NULL, TPM2_EO_UNSIGNED_GE },
  167. { "sle", no_argument, NULL, TPM2_EO_SIGNED_LE },
  168. { "ule", no_argument, NULL, TPM2_EO_UNSIGNED_LE },
  169. { "bs", no_argument, NULL, TPM2_EO_BITSET },
  170. { "bc", no_argument, NULL, TPM2_EO_BITCLEAR },
  171. };
  172. *opts = tpm2_options_new("L:S:", ARRAY_LEN(topts), topts, on_option,
  173. on_arg, 0);
  174. return *opts != NULL;
  175. }
  176. bool is_input_option_args_valid(void) {
  177. if (!ctx.session_path) {
  178. LOG_ERR("Must specify -S session file.");
  179. return false;
  180. }
  181. if (!ctx.operand_b.size) {
  182. LOG_WARN("Data to compare is of size 0");
  183. return false;
  184. }
  185. return true;
  186. }
  187. static tool_rc tpm2_tool_onrun(ESYS_CONTEXT *ectx, tpm2_option_flags flags) {
  188. UNUSED(flags);
  189. bool result = is_input_option_args_valid();
  190. if (!result) {
  191. return tool_rc_general_error;
  192. }
  193. //Input
  194. tool_rc rc = tpm2_session_restore(ectx, ctx.session_path, false,
  195. &ctx.session);
  196. if (rc != tool_rc_success) {
  197. return rc;
  198. }
  199. ESYS_TR policy_session = tpm2_session_get_handle(ctx.session);
  200. //ESAPI call
  201. rc = tpm2_policy_countertimer(ectx, policy_session, &ctx.operand_b,
  202. ctx.offset, ctx.operation);
  203. if (rc != tool_rc_success) {
  204. return rc;
  205. }
  206. //Output
  207. return tpm2_policy_tool_finish(ectx, ctx.session, ctx.policy_digest_path);
  208. }
  209. static tool_rc tpm2_tool_onstop(ESYS_CONTEXT *ectx) {
  210. UNUSED(ectx);
  211. return tpm2_session_close(&ctx.session);
  212. }
  213. // Register this tool with tpm2_tool.c
  214. TPM2_TOOL_REGISTER("policycountertimer", tpm2_tool_onstart, tpm2_tool_onrun, tpm2_tool_onstop, NULL)