tpm2_certifycreation.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. /* SPDX-License-Identifier: BSD-3-Clause */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <stdbool.h>
  5. #include "files.h"
  6. #include "log.h"
  7. #include "tpm2.h"
  8. #include "tpm2_tool.h"
  9. #include "tpm2_alg_util.h"
  10. #include "tpm2_convert.h"
  11. #include "tpm2_options.h"
  12. #define MAX_AUX_SESSIONS 2 // one session provided by auth interface
  13. #define MAX_SESSIONS 3
  14. typedef struct tpm_certifycreation_ctx tpm_certifycreation_ctx;
  15. struct tpm_certifycreation_ctx {
  16. /*
  17. * Inputs
  18. */
  19. struct {
  20. const char *ctx_path;
  21. const char *auth_str;
  22. tpm2_loaded_object object;
  23. } signing_key;
  24. struct {
  25. const char *ctx_path;
  26. tpm2_loaded_object object;
  27. } certified_key;
  28. char *creation_hash_path;
  29. TPM2B_DIGEST creation_hash;
  30. char *creation_ticket_path;
  31. TPMT_TK_CREATION creation_ticket;
  32. TPM2B_DATA policy_qualifier;
  33. const char *policy_qualifier_data;
  34. TPMI_ALG_HASH halg;
  35. TPMI_ALG_SIG_SCHEME sig_scheme;
  36. tpm2_convert_sig_fmt sig_format;
  37. TPMT_SIG_SCHEME in_scheme;
  38. /*
  39. * Outputs
  40. */
  41. char *signature_path;
  42. TPMT_SIGNATURE *signature;
  43. char *certify_info_path;
  44. TPM2B_ATTEST *certify_info;
  45. /*
  46. * Parameter hashes
  47. */
  48. const char *cp_hash_path;
  49. TPM2B_DIGEST cp_hash;
  50. const char *rp_hash_path;
  51. TPM2B_DIGEST rp_hash;
  52. TPMI_ALG_HASH parameter_hash_algorithm;
  53. bool is_command_dispatch;
  54. /*
  55. * Aux sessions
  56. */
  57. uint8_t aux_session_cnt;
  58. tpm2_session *aux_session[MAX_AUX_SESSIONS];
  59. const char *aux_session_path[MAX_AUX_SESSIONS];
  60. ESYS_TR aux_session_handle[MAX_AUX_SESSIONS];
  61. };
  62. static tpm_certifycreation_ctx ctx = {
  63. .halg = TPM2_ALG_NULL,
  64. .sig_scheme = TPM2_ALG_NULL,
  65. .policy_qualifier = TPM2B_EMPTY_INIT,
  66. .aux_session_handle[0] = ESYS_TR_NONE,
  67. .aux_session_handle[1] = ESYS_TR_NONE,
  68. };
  69. static tool_rc certifycreation(ESYS_CONTEXT *ectx) {
  70. /*
  71. * 1. TPM2_CC_<command> OR Retrieve cpHash
  72. */
  73. return tpm2_certifycreation(ectx, &ctx.signing_key.object,
  74. &ctx.certified_key.object, &ctx.creation_hash, &ctx.in_scheme,
  75. &ctx.creation_ticket, &ctx.certify_info, &ctx.signature,
  76. &ctx.policy_qualifier, &ctx.cp_hash, &ctx.rp_hash,
  77. ctx.parameter_hash_algorithm, ctx.aux_session_handle[0],
  78. ctx.aux_session_handle[1]);
  79. }
  80. static tool_rc process_output(void) {
  81. /*
  82. * 1. Outputs that do not require TPM2_CC_<command> dispatch
  83. */
  84. bool is_file_op_success = true;
  85. if (ctx.cp_hash_path) {
  86. is_file_op_success = files_save_digest(&ctx.cp_hash, ctx.cp_hash_path);
  87. if (!is_file_op_success) {
  88. return tool_rc_general_error;
  89. }
  90. }
  91. if (!ctx.is_command_dispatch) {
  92. return tool_rc_success;
  93. }
  94. /*
  95. * 2. Outputs generated after TPM2_CC_<command> dispatch
  96. */
  97. is_file_op_success = tpm2_convert_sig_save(ctx.signature, ctx.sig_format,
  98. ctx.signature_path);
  99. if (!is_file_op_success) {
  100. LOG_ERR("Failed saving signature data.");
  101. return tool_rc_general_error;
  102. }
  103. is_file_op_success = files_save_bytes_to_file(ctx.certify_info_path,
  104. ctx.certify_info->attestationData, ctx.certify_info->size);
  105. if (!is_file_op_success) {
  106. LOG_ERR("Failed saving attestation data.");
  107. return tool_rc_general_error;
  108. }
  109. if (ctx.rp_hash_path) {
  110. is_file_op_success = files_save_digest(&ctx.rp_hash, ctx.rp_hash_path);
  111. }
  112. return is_file_op_success ? tool_rc_success : tool_rc_general_error;
  113. }
  114. static tool_rc process_inputs(ESYS_CONTEXT *ectx) {
  115. /*
  116. * 1. Object and auth initializations
  117. */
  118. /*
  119. * 1.a Add the new-auth values to be set for the object.
  120. */
  121. /*
  122. * 1.b Add object names and their auth sessions
  123. */
  124. tool_rc rc = tpm2_util_object_load_auth(ectx, ctx.signing_key.ctx_path,
  125. ctx.signing_key.auth_str, &ctx.signing_key.object, false,
  126. TPM2_HANDLES_FLAGS_TRANSIENT|TPM2_HANDLES_FLAGS_PERSISTENT);
  127. if (rc != tool_rc_success) {
  128. LOG_ERR("Invalid signing key/ authorization.");
  129. return rc;
  130. }
  131. rc = tpm2_util_object_load(ectx, ctx.certified_key.ctx_path,
  132. &ctx.certified_key.object,
  133. TPM2_HANDLES_FLAGS_TRANSIENT|TPM2_HANDLES_FLAGS_PERSISTENT);
  134. if (rc != tool_rc_success) {
  135. LOG_ERR("Invalid key specified for certification.");
  136. return rc;
  137. }
  138. /*
  139. * 2. Restore auxiliary sessions
  140. */
  141. rc = tpm2_util_aux_sessions_setup(ectx, ctx.aux_session_cnt,
  142. ctx.aux_session_path, ctx.aux_session_handle, ctx.aux_session);
  143. if (rc != tool_rc_success) {
  144. return rc;
  145. }
  146. /*
  147. * 3. Command specific initializations
  148. */
  149. /* Load creation hash */
  150. rc = files_load_digest(ctx.creation_hash_path, &ctx.creation_hash) ?
  151. tool_rc_success : tool_rc_general_error;
  152. if (rc != tool_rc_success) {
  153. LOG_ERR("Failed loading creation hash.");
  154. return rc;
  155. }
  156. /* Set signature scheme for key type & Validate chosen scheme */
  157. rc = tpm2_alg_util_get_signature_scheme(ectx,
  158. ctx.signing_key.object.tr_handle, &ctx.halg, ctx.sig_scheme,
  159. &ctx.in_scheme);
  160. if (rc != tool_rc_success) {
  161. LOG_ERR("bad signature scheme for key type!");
  162. return rc;
  163. }
  164. /* Load creation ticket */
  165. rc = files_load_creation_ticket(ctx.creation_ticket_path,
  166. &ctx.creation_ticket) ? tool_rc_success : tool_rc_general_error;
  167. if (rc != tool_rc_success) {
  168. LOG_ERR("Could not load creation ticket from file");
  169. return rc;
  170. }
  171. /* Qualifier data is optional. If not specified default to 0 */
  172. if (ctx.policy_qualifier_data) {
  173. ctx.policy_qualifier.size = sizeof(ctx.policy_qualifier.buffer);
  174. rc = tpm2_util_bin_from_hex_or_file(ctx.policy_qualifier_data,
  175. &ctx.policy_qualifier.size, ctx.policy_qualifier.buffer) ?
  176. tool_rc_success : tool_rc_general_error;
  177. if (rc != tool_rc_success) {
  178. LOG_ERR("Could not load qualifier data");
  179. return rc;
  180. }
  181. }
  182. /*
  183. * 4. Configuration for calculating the pHash
  184. */
  185. /*
  186. * 4.a Determine pHash length and alg
  187. */
  188. tpm2_session *all_sessions[MAX_SESSIONS] = {
  189. ctx.certified_key.object.session,
  190. ctx.aux_session[0],
  191. ctx.aux_session[1]
  192. };
  193. const char **cphash_path = ctx.cp_hash_path ? &ctx.cp_hash_path : 0;
  194. const char **rphash_path = ctx.rp_hash_path ? &ctx.rp_hash_path : 0;
  195. ctx.parameter_hash_algorithm = tpm2_util_calculate_phash_algorithm(ectx,
  196. cphash_path, &ctx.cp_hash, rphash_path, &ctx.rp_hash, all_sessions);
  197. /*
  198. * 4.b Determine if TPM2_CC_<command> is to be dispatched
  199. * !rphash && !cphash [Y]
  200. * !rphash && cphash [N]
  201. * rphash && !cphash [Y]
  202. * rphash && cphash [Y]
  203. */
  204. ctx.is_command_dispatch = (ctx.cp_hash_path && !ctx.rp_hash_path) ?
  205. false : true;
  206. return rc;
  207. }
  208. static bool check_options(void) {
  209. if (ctx.cp_hash_path && !ctx.rp_hash_path &&
  210. (ctx.certify_info_path || ctx.signature_path)) {
  211. LOG_ERR("Cannot generate outputs when calculating cpHash.");
  212. return false;
  213. }
  214. if (!ctx.signing_key.ctx_path) {
  215. LOG_ERR("Must specify the signing key '-C'.");
  216. return false;
  217. }
  218. if (!ctx.certified_key.ctx_path) {
  219. LOG_ERR("Must specify the path of the key to certify '-c'.");
  220. return false;
  221. }
  222. if (!ctx.creation_ticket_path) {
  223. LOG_ERR("Must specify the creation ticket path '-t'.");
  224. return false;
  225. }
  226. if (!ctx.signature_path && !ctx.cp_hash_path) {
  227. LOG_ERR("Must specify the file path to save signature '-o'");
  228. return false;
  229. }
  230. if (!ctx.certify_info_path && !ctx.cp_hash_path) {
  231. LOG_ERR("Must specify file path to save attestation '--attestation'");
  232. return false;
  233. }
  234. return true;
  235. }
  236. static bool set_signature_format(char *value) {
  237. ctx.sig_format = tpm2_convert_sig_fmt_from_optarg(value);
  238. if (ctx.sig_format == signature_format_err) {
  239. return false;
  240. }
  241. return true;
  242. }
  243. static bool set_signing_scheme(char *value) {
  244. ctx.sig_scheme = tpm2_alg_util_from_optarg(value, tpm2_alg_util_flags_sig);
  245. if (ctx.sig_scheme == TPM2_ALG_ERROR) {
  246. LOG_ERR("Unknown signing scheme, got: \"%s\"", value);
  247. return false;
  248. }
  249. return true;
  250. }
  251. static bool set_digest_algorithm(char *value) {
  252. ctx.halg = tpm2_alg_util_from_optarg(value, tpm2_alg_util_flags_hash);
  253. if (ctx.halg == TPM2_ALG_ERROR) {
  254. LOG_ERR("Could not convert to number or lookup algorithm, got: "
  255. "\"%s\"", value);
  256. return false;
  257. }
  258. return true;
  259. }
  260. static bool on_option(char key, char *value) {
  261. bool result = true;
  262. switch (key) {
  263. case 'C':
  264. ctx.signing_key.ctx_path = value;
  265. break;
  266. case 'P':
  267. ctx.signing_key.auth_str = value;
  268. break;
  269. case 'c':
  270. ctx.certified_key.ctx_path = value;
  271. break;
  272. case 'd':
  273. ctx.creation_hash_path = value;
  274. break;
  275. case 't':
  276. ctx.creation_ticket_path = value;
  277. break;
  278. case 'g':
  279. result = set_digest_algorithm(value);
  280. goto on_option_out;
  281. case 's':
  282. result = set_signing_scheme(value);
  283. goto on_option_out;
  284. case 'f':
  285. result = set_signature_format(value);
  286. goto on_option_out;
  287. case 'o':
  288. ctx.signature_path = value;
  289. break;
  290. case 0:
  291. ctx.certify_info_path = value;
  292. break;
  293. case 1:
  294. ctx.cp_hash_path = value;
  295. break;
  296. case 2:
  297. ctx.rp_hash_path = value;
  298. break;
  299. case 'q':
  300. ctx.policy_qualifier_data = value;
  301. break;
  302. case 'S':
  303. ctx.aux_session_path[ctx.aux_session_cnt] = value;
  304. if (ctx.aux_session_cnt < MAX_AUX_SESSIONS) {
  305. ctx.aux_session_cnt++;
  306. } else {
  307. LOG_ERR("Specify a max of 3 sessions");
  308. return false;
  309. }
  310. break;
  311. /* no default */
  312. }
  313. on_option_out:
  314. return result;
  315. }
  316. static bool tpm2_tool_onstart(tpm2_options **opts) {
  317. static const struct option topts[] = {
  318. { "signingkey-context", required_argument, NULL, 'C' },
  319. { "signingkey-auth", required_argument, NULL, 'P' },
  320. { "certifiedkey-context", required_argument, NULL, 'c' },
  321. { "creation-hash", required_argument, NULL, 'd' },
  322. { "ticket", required_argument, NULL, 't' },
  323. { "hash-algorithm", required_argument, NULL, 'g' },
  324. { "scheme", required_argument, NULL, 's' },
  325. { "format", required_argument, NULL, 'f' },
  326. { "signature", required_argument, NULL, 'o' },
  327. { "attestation", required_argument, NULL, 0 },
  328. { "qualification", required_argument, NULL, 'q' },
  329. { "cphash", required_argument, NULL, 1 },
  330. { "rphash", required_argument, NULL, 2 },
  331. { "session", required_argument, NULL, 'S' },
  332. };
  333. *opts = tpm2_options_new("C:P:c:d:t:g:s:f:o:q:S:", ARRAY_LEN(topts), topts,
  334. on_option, NULL, 0);
  335. return *opts != NULL;
  336. }
  337. static tool_rc tpm2_tool_onrun(ESYS_CONTEXT *ectx, tpm2_option_flags flags) {
  338. UNUSED(flags);
  339. /*
  340. * 1. Process options
  341. */
  342. bool result = check_options();
  343. if (!result) {
  344. return tool_rc_option_error;
  345. }
  346. /*
  347. * 2. Process inputs
  348. */
  349. tool_rc rc = process_inputs(ectx);
  350. if (rc != tool_rc_success) {
  351. return rc;
  352. }
  353. /*
  354. * 3. TPM2_CC_<command> call
  355. */
  356. rc = certifycreation(ectx);
  357. if (rc != tool_rc_success) {
  358. return rc;
  359. }
  360. /*
  361. * 4. Process outputs
  362. */
  363. rc = process_output();
  364. return rc;
  365. }
  366. static tool_rc tpm2_tool_onstop(ESYS_CONTEXT *ectx) {
  367. UNUSED(ectx);
  368. /*
  369. * 1. Free objects
  370. */
  371. Esys_Free(ctx.signature);
  372. Esys_Free(ctx.certify_info);
  373. /*
  374. * 2. Close authorization sessions
  375. */
  376. tool_rc rc = tool_rc_success;
  377. tool_rc tmp_rc = tpm2_session_close(&ctx.signing_key.object.session);
  378. if (tmp_rc != tool_rc_success) {
  379. rc = tmp_rc;
  380. }
  381. /*
  382. * 3. Close auxiliary sessions
  383. */
  384. size_t i = 0;
  385. for(i = 0; i < ctx.aux_session_cnt; i++) {
  386. if (ctx.aux_session_path[i]) {
  387. tmp_rc = tpm2_session_close(&ctx.aux_session[i]);
  388. if (tmp_rc != tool_rc_success) {
  389. rc = tmp_rc;
  390. }
  391. }
  392. }
  393. return rc;
  394. }
  395. // Register this tool with tpm2_tool.c
  396. TPM2_TOOL_REGISTER("certifycreation", tpm2_tool_onstart, tpm2_tool_onrun,
  397. tpm2_tool_onstop, NULL)