tpm2_activatecredential.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /* SPDX-License-Identifier: BSD-3-Clause */
  2. #include <errno.h>
  3. #include <inttypes.h>
  4. #include <stdbool.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include "files.h"
  9. #include "log.h"
  10. #include "tpm2.h"
  11. #include "tpm2_tool.h"
  12. typedef struct tpm_activatecred_ctx tpm_activatecred_ctx;
  13. #define MAX_AUX_SESSIONS 1 // two sessions provided by auth interface
  14. #define MAX_SESSIONS 3
  15. struct tpm_activatecred_ctx {
  16. /*
  17. * Inputs
  18. */
  19. struct {
  20. const char *ctx_path;
  21. const char *auth_str;
  22. tpm2_loaded_object object;
  23. } credential_key; //Typically EK
  24. struct {
  25. const char *ctx_path;
  26. const char *auth_str;
  27. tpm2_loaded_object object;
  28. } credentialed_key; //Typically AK
  29. TPM2B_ID_OBJECT credential_blob;
  30. const char *credential_blob_path;
  31. bool is_credential_blob_specified;
  32. TPM2B_ENCRYPTED_SECRET secret;
  33. /*
  34. * Outputs
  35. */
  36. const char *output_file;
  37. TPM2B_DIGEST *cert_info_data;
  38. /*
  39. * Parameter hashes
  40. */
  41. const char *cp_hash_path;
  42. TPM2B_DIGEST cp_hash;
  43. const char *rp_hash_path;
  44. TPM2B_DIGEST rp_hash;
  45. TPMI_ALG_HASH parameter_hash_algorithm;
  46. bool is_command_dispatch;
  47. /*
  48. * Aux sessions
  49. */
  50. uint8_t aux_session_cnt;
  51. tpm2_session *aux_session[MAX_AUX_SESSIONS];
  52. const char *aux_session_path[MAX_AUX_SESSIONS];
  53. ESYS_TR aux_session_handle[MAX_AUX_SESSIONS];
  54. };
  55. static tpm_activatecred_ctx ctx = {
  56. .aux_session_handle[0] = ESYS_TR_NONE,
  57. .parameter_hash_algorithm = TPM2_ALG_ERROR,
  58. };
  59. static tool_rc activate_credential_and_output(ESYS_CONTEXT *ectx) {
  60. /*
  61. * 1. TPM2_CC_<command> OR Retrieve cpHash
  62. */
  63. return tpm2_activatecredential(ectx, &ctx.credentialed_key.object,
  64. &ctx.credential_key.object, &ctx.credential_blob, &ctx.secret,
  65. &ctx.cert_info_data, &ctx.cp_hash, &ctx.rp_hash,
  66. ctx.parameter_hash_algorithm, ctx.aux_session_handle[0]);
  67. }
  68. static tool_rc process_output(ESYS_CONTEXT *ectx) {
  69. UNUSED(ectx);
  70. /*
  71. * 1. Outputs that do not require TPM2_CC_<command> dispatch
  72. */
  73. bool is_file_op_success = true;
  74. if (ctx.cp_hash_path) {
  75. is_file_op_success = files_save_digest(&ctx.cp_hash, ctx.cp_hash_path);
  76. if (!is_file_op_success) {
  77. return tool_rc_general_error;
  78. }
  79. }
  80. if (!ctx.is_command_dispatch) {
  81. return tool_rc_success;
  82. }
  83. /*
  84. * 2. Outputs generated after TPM2_CC_<command> dispatch
  85. */
  86. tpm2_tool_output("certinfodata:");
  87. size_t i;
  88. for (i = 0; i < ctx.cert_info_data->size; i++) {
  89. tpm2_tool_output("%.2x", ctx.cert_info_data->buffer[i]);
  90. }
  91. tpm2_tool_output("\n");
  92. is_file_op_success = files_save_bytes_to_file(ctx.output_file,
  93. ctx.cert_info_data->buffer, ctx.cert_info_data->size);
  94. free(ctx.cert_info_data);
  95. if (!is_file_op_success) {
  96. return tool_rc_general_error;
  97. }
  98. if (ctx.rp_hash_path) {
  99. is_file_op_success = files_save_digest(&ctx.rp_hash, ctx.rp_hash_path);
  100. }
  101. return is_file_op_success ? tool_rc_success : tool_rc_general_error;
  102. }
  103. static bool read_cert_secret(void) {
  104. bool result = false;
  105. FILE *fp = fopen(ctx.credential_blob_path, "rb");
  106. if (!fp) {
  107. LOG_ERR("Could not open file \"%s\" error: \"%s\"",
  108. ctx.credential_blob_path, strerror(errno));
  109. return false;
  110. }
  111. uint32_t version;
  112. result = files_read_header(fp, &version);
  113. if (!result) {
  114. LOG_ERR("Could not read version header");
  115. goto out;
  116. }
  117. if (version != 1) {
  118. LOG_ERR("Unknown credential format, got %"PRIu32" expected 1", version);
  119. goto out;
  120. }
  121. result = files_read_16(fp, &ctx.credential_blob.size);
  122. if (!result) {
  123. LOG_ERR("Could not read credential size");
  124. goto out;
  125. }
  126. result = files_read_bytes(fp, ctx.credential_blob.credential, ctx.credential_blob.size);
  127. if (!result) {
  128. LOG_ERR("Could not read credential data");
  129. goto out;
  130. }
  131. result = files_read_16(fp, &ctx.secret.size);
  132. if (!result) {
  133. LOG_ERR("Could not read secret size");
  134. goto out;
  135. }
  136. result = files_read_bytes(fp, ctx.secret.secret, ctx.secret.size);
  137. if (!result) {
  138. LOG_ERR("Could not write secret data");
  139. goto out;
  140. }
  141. result = true;
  142. out:
  143. fclose(fp);
  144. return result;
  145. }
  146. static tool_rc process_inputs(ESYS_CONTEXT *ectx) {
  147. /*
  148. * 1. Object and auth initializations
  149. */
  150. /*
  151. * 1.a Add the new-auth values to be set for the object.
  152. */
  153. /*
  154. * 1.b Add object names and their auth sessions
  155. */
  156. /* Object #1 */
  157. tool_rc rc = tpm2_util_object_load_auth(ectx, ctx.credential_key.ctx_path,
  158. ctx.credential_key.auth_str, &ctx.credential_key.object, false,
  159. TPM2_HANDLE_ALL_W_NV);
  160. if (rc != tool_rc_success) {
  161. return rc;
  162. }
  163. /* Object #2 */
  164. rc = tpm2_util_object_load_auth(ectx, ctx.credentialed_key.ctx_path,
  165. ctx.credentialed_key.auth_str, &ctx.credentialed_key.object, false,
  166. TPM2_HANDLE_ALL_W_NV);
  167. if (rc != tool_rc_success) {
  168. return rc;
  169. }
  170. /*
  171. * 2. Restore auxiliary sessions
  172. */
  173. rc = tpm2_util_aux_sessions_setup(ectx, ctx.aux_session_cnt,
  174. ctx.aux_session_path, ctx.aux_session_handle, ctx.aux_session);
  175. if (rc != tool_rc_success) {
  176. return rc;
  177. }
  178. /*
  179. * 3. Command specific initializations
  180. */
  181. rc = read_cert_secret() ? tool_rc_success : tool_rc_general_error;
  182. if (rc != tool_rc_success) {
  183. return rc;
  184. }
  185. /*
  186. * 4. Configuration for calculating the pHash
  187. */
  188. /*
  189. * 4.a Determine pHash length and alg
  190. */
  191. tpm2_session *all_sessions[MAX_SESSIONS] = {
  192. ctx.credential_key.object.session,
  193. ctx.credentialed_key.object.session,
  194. ctx.aux_session[0]
  195. };
  196. const char **cphash_path = ctx.cp_hash_path ? &ctx.cp_hash_path : 0;
  197. const char **rphash_path = ctx.rp_hash_path ? &ctx.rp_hash_path : 0;
  198. ctx.parameter_hash_algorithm = tpm2_util_calculate_phash_algorithm(ectx,
  199. cphash_path, &ctx.cp_hash, rphash_path, &ctx.rp_hash, all_sessions);
  200. /*
  201. * 4.b Determine if TPM2_CC_<command> is to be dispatched
  202. * !rphash && !cphash [Y]
  203. * !rphash && cphash [N]
  204. * rphash && !cphash [Y]
  205. * rphash && cphash [Y]
  206. */
  207. ctx.is_command_dispatch = (ctx.cp_hash_path && !ctx.rp_hash_path) ?
  208. false : true;
  209. return rc;
  210. }
  211. static tool_rc check_options(void) {
  212. if ((!ctx.credentialed_key.ctx_path) && (!ctx.credential_key.ctx_path)
  213. && !ctx.is_credential_blob_specified && !ctx.output_file) {
  214. LOG_ERR("Expected options c and C and i and o.");
  215. return tool_rc_option_error;
  216. }
  217. return tool_rc_success;
  218. }
  219. static bool on_option(char key, char *value) {
  220. switch (key) {
  221. case 'c':
  222. ctx.credentialed_key.ctx_path = value;
  223. break;
  224. case 'p':
  225. ctx.credentialed_key.auth_str = value;
  226. break;
  227. case 'C':
  228. ctx.credential_key.ctx_path = value;
  229. break;
  230. case 'P':
  231. ctx.credential_key.auth_str = value;
  232. break;
  233. case 'i':
  234. /* logs errors */
  235. ctx.credential_blob_path = value;
  236. ctx.is_credential_blob_specified = 1;
  237. break;
  238. case 'o':
  239. ctx.output_file = value;
  240. break;
  241. case 0:
  242. ctx.cp_hash_path = value;
  243. break;
  244. case 1:
  245. ctx.rp_hash_path = value;
  246. break;
  247. case 'S':
  248. ctx.aux_session_path[ctx.aux_session_cnt] = value;
  249. if (ctx.aux_session_cnt < MAX_AUX_SESSIONS) {
  250. ctx.aux_session_cnt++;
  251. } else {
  252. LOG_ERR("Specify a max of 3 sessions");
  253. return false;
  254. }
  255. break;
  256. }
  257. return true;
  258. }
  259. static bool tpm2_tool_onstart(tpm2_options **opts) {
  260. static const struct option topts[] = {
  261. {"credentialedkey-context", required_argument, NULL, 'c'},
  262. {"credentialkey-context", required_argument, NULL, 'C'},
  263. {"credentialedkey-auth", required_argument, NULL, 'p'},
  264. {"credentialkey-auth", required_argument, NULL, 'P'},
  265. {"credential-blob", required_argument, NULL, 'i'},
  266. {"certinfo-data", required_argument, NULL, 'o'},
  267. {"cphash", required_argument, NULL, 0 },
  268. {"rphash", required_argument, NULL, 1 },
  269. {"session", required_argument, NULL, 'S' },
  270. };
  271. *opts = tpm2_options_new("c:C:p:P:i:o:S:", ARRAY_LEN(topts), topts, on_option,
  272. NULL, 0);
  273. return *opts != NULL;
  274. }
  275. static tool_rc tpm2_tool_onrun(ESYS_CONTEXT *ectx, tpm2_option_flags flags) {
  276. /* opts is unused, avoid compiler warning */
  277. UNUSED(flags);
  278. /*
  279. * 1. Process options
  280. */
  281. tool_rc rc = check_options();
  282. if (rc != tool_rc_success) {
  283. return rc;
  284. }
  285. /*
  286. * 2. Process inputs
  287. */
  288. rc = process_inputs(ectx);
  289. if (rc != tool_rc_success) {
  290. return rc;
  291. }
  292. /*
  293. * 3. TPM2_CC_<command> call
  294. */
  295. rc = activate_credential_and_output(ectx);
  296. if (rc != tool_rc_success) {
  297. return rc;
  298. }
  299. /*
  300. * 4. Process outputs
  301. */
  302. return process_output(ectx);
  303. }
  304. static tool_rc tpm2_tool_onstop(ESYS_CONTEXT *ectx) {
  305. UNUSED(ectx);
  306. /*
  307. * 1. Free objects
  308. */
  309. /*
  310. * 2. Close authorization sessions
  311. */
  312. tool_rc rc = tool_rc_success;
  313. tool_rc tmp_rc = tpm2_session_close(&ctx.credentialed_key.object.session);
  314. if (tmp_rc != tool_rc_success) {
  315. rc = tmp_rc;
  316. }
  317. tmp_rc = tpm2_session_close(&ctx.credential_key.object.session);
  318. if (tmp_rc != tool_rc_success) {
  319. rc = tmp_rc;
  320. }
  321. /*
  322. * 3. Close auxiliary sessions
  323. */
  324. size_t i = 0;
  325. for(i = 0; i < ctx.aux_session_cnt; i++) {
  326. if (ctx.aux_session_path[i]) {
  327. tmp_rc = tpm2_session_close(&ctx.aux_session[i]);
  328. if (tmp_rc != tool_rc_success) {
  329. rc = tmp_rc;
  330. }
  331. }
  332. }
  333. return rc;
  334. }
  335. // Register this tool with tpm2_tool.c
  336. TPM2_TOOL_REGISTER("activatecredential", tpm2_tool_onstart, tpm2_tool_onrun,
  337. tpm2_tool_onstop, NULL)