tpm2_verifysignature.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /* SPDX-License-Identifier: BSD-3-Clause */
  2. #include <stdlib.h>
  3. #include "files.h"
  4. #include "log.h"
  5. #include "object.h"
  6. #include "tpm2.h"
  7. #include "tpm2_tool.h"
  8. #include "tpm2_alg_util.h"
  9. #include "tpm2_convert.h"
  10. #include "tpm2_hash.h"
  11. #include "tpm2_options.h"
  12. typedef struct tpm2_verifysig_ctx tpm2_verifysig_ctx;
  13. struct tpm2_verifysig_ctx {
  14. union {
  15. struct {
  16. UINT8 digest :1;
  17. UINT8 halg :1;
  18. UINT8 msg :1;
  19. UINT8 sig :1;
  20. UINT8 ticket :1;
  21. UINT8 key_context :1;
  22. UINT8 fmt;
  23. };
  24. UINT8 all;
  25. } flags;
  26. TPMI_ALG_SIG_SCHEME format;
  27. TPMI_ALG_HASH halg;
  28. TPM2B_DIGEST *msg_hash;
  29. TPMT_SIGNATURE signature;
  30. char *msg_file_path;
  31. char *sig_file_path;
  32. char *out_file_path;
  33. const char *context_arg;
  34. tpm2_loaded_object key_context_object;
  35. };
  36. static tpm2_verifysig_ctx ctx = {
  37. .format = TPM2_ALG_ERROR,
  38. .msg_hash = NULL,
  39. .halg = TPM2_ALG_SHA256
  40. };
  41. static tool_rc verify_signature(ESYS_CONTEXT *context) {
  42. TPMT_TK_VERIFIED *validation = NULL;
  43. tool_rc rc = tpm2_verifysignature(context,
  44. ctx.key_context_object.tr_handle,
  45. ctx.msg_hash, &ctx.signature, &validation);
  46. if (rc != tool_rc_success) {
  47. goto out;
  48. }
  49. /*
  50. * NULL Hierarchies don't produce validation data, so let the user know
  51. * by issuing a warning.
  52. */
  53. if (ctx.out_file_path) {
  54. if (validation->hierarchy == TPM2_RH_NULL) {
  55. LOG_WARN("The NULL hierarchy doesn't produce a validation ticket,"
  56. " not outputting ticket");
  57. } else {
  58. if (!files_save_ticket(validation, ctx.out_file_path)) {
  59. rc = tool_rc_general_error;
  60. }
  61. }
  62. }
  63. out:
  64. free(validation);
  65. return rc;
  66. }
  67. static TPM2B *message_from_file(const char *msg_file_path) {
  68. unsigned long size;
  69. bool result = files_get_file_size_path(msg_file_path, &size);
  70. if (!result) {
  71. return NULL;
  72. }
  73. if (!size) {
  74. LOG_ERR("The msg file \"%s\" is empty", msg_file_path);
  75. return NULL;
  76. }
  77. TPM2B *msg = (TPM2B *) calloc(1, sizeof(TPM2B) + size);
  78. if (!msg) {
  79. LOG_ERR("OOM");
  80. return NULL;
  81. }
  82. UINT16 tmp = msg->size = size;
  83. if (!files_load_bytes_from_path(msg_file_path, msg->buffer, &tmp)) {
  84. free(msg);
  85. return NULL;
  86. }
  87. return msg;
  88. }
  89. static tool_rc init(ESYS_CONTEXT *context) {
  90. tool_rc rc = tool_rc_general_error;
  91. /* check flags for mismatches */
  92. if (ctx.flags.digest && (ctx.flags.msg || ctx.flags.halg)) {
  93. LOG_ERR("Cannot specify --digest (-d) and ( --msg (-m) or --halg (-g) )");
  94. return tool_rc_option_error;
  95. }
  96. if (!(ctx.context_arg && ctx.flags.sig)) {
  97. LOG_ERR("--key-context (-c) and --sig (-s) are required");
  98. return tool_rc_option_error;
  99. }
  100. TPM2B *msg = NULL;
  101. tool_rc tmp_rc = tpm2_util_object_load(context, ctx.context_arg,
  102. &ctx.key_context_object, TPM2_HANDLE_ALL_W_NV);
  103. if (tmp_rc != tool_rc_success) {
  104. return tmp_rc;
  105. }
  106. if (ctx.flags.msg) {
  107. msg = message_from_file(ctx.msg_file_path);
  108. if (!msg) {
  109. /* message_from_file() logs specific error no need to here */
  110. return tool_rc_general_error;
  111. }
  112. }
  113. if (ctx.flags.sig) {
  114. tpm2_convert_sig_fmt fmt =
  115. ctx.flags.fmt ? signature_format_plain : signature_format_tss;
  116. bool res = tpm2_convert_sig_load(ctx.sig_file_path, fmt, ctx.format,
  117. ctx.halg, &ctx.signature);
  118. if (!res) {
  119. goto err;
  120. }
  121. }
  122. /* If no digest is specified, compute it */
  123. if (!ctx.flags.digest) {
  124. if (!msg) {
  125. /*
  126. * This is a redundant check since main() checks this case, but
  127. * we'll add it here to silence any complainers (such as static
  128. * analysers).
  129. */
  130. LOG_ERR("No digest set and no message file to compute from, cannot "
  131. "compute message hash!");
  132. goto err;
  133. }
  134. tmp_rc = tpm2_hash_compute_data(context, ctx.halg, TPM2_RH_NULL,
  135. msg->buffer, msg->size, &ctx.msg_hash, NULL);
  136. if (tmp_rc != tool_rc_success) {
  137. rc = tmp_rc;
  138. LOG_ERR("Compute message hash failed!");
  139. goto err;
  140. }
  141. }
  142. rc = tool_rc_success;
  143. err:
  144. free(msg);
  145. return rc;
  146. }
  147. static bool on_option(char key, char *value) {
  148. switch (key) {
  149. case 'c':
  150. ctx.context_arg = value;
  151. break;
  152. case 'g': {
  153. ctx.halg = tpm2_alg_util_from_optarg(value, tpm2_alg_util_flags_hash);
  154. if (ctx.halg == TPM2_ALG_ERROR) {
  155. LOG_ERR("Unable to convert algorithm, got: \"%s\"", value);
  156. return false;
  157. }
  158. ctx.flags.halg = 1;
  159. }
  160. break;
  161. case 'm': {
  162. ctx.msg_file_path = value;
  163. ctx.flags.msg = 1;
  164. }
  165. break;
  166. case 'd': {
  167. ctx.msg_hash = malloc(sizeof(TPM2B_DIGEST));
  168. ctx.msg_hash->size = sizeof(ctx.msg_hash->buffer);
  169. if (!files_load_bytes_from_path(value, ctx.msg_hash->buffer,
  170. &ctx.msg_hash->size)) {
  171. LOG_ERR("Could not load digest from file!");
  172. return false;
  173. }
  174. ctx.flags.digest = 1;
  175. }
  176. break;
  177. case 0:
  178. LOG_WARN("Option \"--format\" is deprecated, use \"--scheme\"");
  179. /* falls through */
  180. case 'f':
  181. ctx.format = tpm2_alg_util_from_optarg(value, tpm2_alg_util_flags_sig);
  182. if (ctx.format == TPM2_ALG_ERROR) {
  183. LOG_ERR("Unknown signing scheme, got: \"%s\"", value);
  184. return false;
  185. }
  186. ctx.flags.fmt = 1;
  187. break;
  188. case 's':
  189. ctx.sig_file_path = value;
  190. ctx.flags.sig = 1;
  191. break;
  192. case 't':
  193. ctx.out_file_path = value;
  194. ctx.flags.ticket = 1;
  195. break;
  196. /* no default */
  197. }
  198. return true;
  199. }
  200. static bool tpm2_tool_onstart(tpm2_options **opts) {
  201. const struct option topts[] = {
  202. { "digest", required_argument, NULL, 'd' },
  203. { "hash-algorithm", required_argument, NULL, 'g' },
  204. { "message", required_argument, NULL, 'm' },
  205. { "format", required_argument, NULL, 0 },
  206. { "scheme", required_argument, NULL, 'f' },
  207. { "signature", required_argument, NULL, 's' },
  208. { "ticket", required_argument, NULL, 't' },
  209. { "key-context", required_argument, NULL, 'c' },
  210. };
  211. *opts = tpm2_options_new("g:m:d:f:s:t:c:", ARRAY_LEN(topts), topts,
  212. on_option, NULL, 0);
  213. return *opts != NULL;
  214. }
  215. static tool_rc tpm2_tool_onrun(ESYS_CONTEXT *context, tpm2_option_flags flags) {
  216. UNUSED(flags);
  217. /* initialize and process */
  218. tool_rc rc = init(context);
  219. if (rc != tool_rc_success) {
  220. return rc;
  221. }
  222. rc = verify_signature(context);
  223. if (rc != tool_rc_success) {
  224. LOG_ERR("Verify signature failed!");
  225. return rc;
  226. }
  227. return tool_rc_success;
  228. }
  229. static void tpm2_tool_onexit(void) {
  230. if (ctx.msg_hash) {
  231. free(ctx.msg_hash);
  232. }
  233. }
  234. // Register this tool with tpm2_tool.c
  235. TPM2_TOOL_REGISTER("verifysignature", tpm2_tool_onstart, tpm2_tool_onrun, NULL, tpm2_tool_onexit)