tpm2_startauthsession.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /* SPDX-License-Identifier: BSD-3-Clause */
  2. #include <stdbool.h>
  3. #include "log.h"
  4. #include "object.h"
  5. #include "tpm2.h"
  6. #include "tpm2_auth_util.h"
  7. #include "tpm2_tool.h"
  8. #include "tpm2_alg_util.h"
  9. #include "tpm2_options.h"
  10. typedef struct tpm2_startauthsession_ctx tpm2_startauthsession_ctx;
  11. struct tpm2_startauthsession_ctx {
  12. struct {
  13. TPM2_SE type;
  14. TPMI_ALG_HASH halg;
  15. struct {
  16. /*
  17. * Salt generated by esys is encrypted using the tpmkey and
  18. * encryption does not require auth to be specified.
  19. */
  20. const char *key_context_arg_str;
  21. tpm2_loaded_object key_context_object;
  22. } tpmkey;
  23. struct {
  24. /*
  25. * While TPM2_CC_StartAuthSession does not required the auth of the
  26. * bind to be specified, it is captured here for esys to calculate
  27. * the sessionkey.
  28. */
  29. const char *bind_context_arg_str;
  30. const char *bind_context_auth_str;
  31. tpm2_loaded_object bind_context_object;
  32. } bind;
  33. } session;
  34. struct {
  35. const char *path;
  36. } output;
  37. tpm2_session_data *session_data;
  38. TPMA_SESSION attrs;
  39. bool is_real_policy_session;
  40. bool is_hmac_session;
  41. bool is_session_encryption_possibly_needed;
  42. bool is_session_audit_required;
  43. /* Salted/ Bounded session combinations */
  44. bool is_salted;
  45. bool is_bounded;
  46. bool is_salt_and_bind_obj_same;
  47. };
  48. static tpm2_startauthsession_ctx ctx = {
  49. .attrs = TPMA_SESSION_CONTINUESESSION,
  50. .session = {
  51. .type = TPM2_SE_TRIAL,
  52. .halg = TPM2_ALG_SHA256
  53. }
  54. };
  55. static bool on_option(char key, char *value) {
  56. switch (key) {
  57. case 0:
  58. ctx.is_real_policy_session = true;
  59. break;
  60. case 1:
  61. ctx.is_hmac_session = true;
  62. ctx.is_session_audit_required = true;
  63. ctx.attrs |= TPMA_SESSION_AUDIT;
  64. break;
  65. case 'g':
  66. ctx.session.halg = tpm2_alg_util_from_optarg(value,
  67. tpm2_alg_util_flags_hash);
  68. if (ctx.session.halg == TPM2_ALG_ERROR) {
  69. LOG_ERR("Invalid choice for policy digest hash algorithm");
  70. return false;
  71. }
  72. break;
  73. case 'S':
  74. ctx.output.path = value;
  75. break;
  76. case 'c':
  77. ctx.is_salt_and_bind_obj_same = true;
  78. ctx.session.tpmkey.key_context_arg_str = value;
  79. ctx.session.bind.bind_context_arg_str = value;
  80. ctx.is_session_encryption_possibly_needed = true;
  81. ctx.attrs |= (TPMA_SESSION_DECRYPT | TPMA_SESSION_ENCRYPT);
  82. break;
  83. case 2:
  84. ctx.is_bounded = true;
  85. ctx.session.bind.bind_context_arg_str = value;
  86. ctx.is_session_encryption_possibly_needed = true;
  87. break;
  88. case 3:
  89. ctx.session.bind.bind_context_auth_str = value;
  90. break;
  91. case 4:
  92. ctx.is_salted = true;
  93. ctx.session.tpmkey.key_context_arg_str = value;
  94. ctx.is_session_encryption_possibly_needed = true;
  95. break;
  96. case 5:
  97. ctx.is_hmac_session = true;
  98. ctx.is_session_encryption_possibly_needed = true;
  99. break;
  100. }
  101. return true;
  102. }
  103. static bool tpm2_tool_onstart(tpm2_options **opts) {
  104. static struct option topts[] = {
  105. { "policy-session", no_argument, NULL, 0 },
  106. { "audit-session", no_argument, NULL, 1 },
  107. { "bind-context", required_argument, NULL, 2 },
  108. { "bind-auth", required_argument, NULL, 3 },
  109. { "tpmkey-context", required_argument, NULL, 4 },
  110. { "hmac-session", no_argument, NULL, 5 },
  111. { "hash-algorithm", required_argument, NULL, 'g'},
  112. { "session", required_argument, NULL, 'S'},
  113. { "key-context", required_argument, NULL, 'c'},
  114. };
  115. *opts = tpm2_options_new("g:S:c:", ARRAY_LEN(topts), topts, on_option,
  116. NULL, 0);
  117. return *opts != NULL;
  118. }
  119. static tool_rc is_input_options_valid(void) {
  120. if (!ctx.output.path) {
  121. LOG_ERR("Expected option -S");
  122. return tool_rc_option_error;
  123. }
  124. /* Trial-session: neither real_policy nor audit/hmac session */
  125. if (!ctx.is_real_policy_session && !ctx.is_hmac_session &&
  126. ctx.is_session_encryption_possibly_needed) {
  127. LOG_ERR("Trial sessions cannot be additionally used as encrypt/decrypt "
  128. "session");
  129. return tool_rc_option_error;
  130. }
  131. /*
  132. * Only use --key-context if both bind and tpmkey objects are the same.
  133. */
  134. if (ctx.is_salted && ctx.is_salt_and_bind_obj_same) {
  135. LOG_ERR("Specify --key-context or tpmkey-context, not both.");
  136. return tool_rc_option_error;
  137. }
  138. if (ctx.is_bounded && ctx.is_salt_and_bind_obj_same) {
  139. LOG_ERR("Specify --key-context or --bind-context, not both.");
  140. return tool_rc_option_error;
  141. }
  142. if (ctx.session.bind.bind_context_auth_str &&
  143. !ctx.session.bind.bind_context_arg_str) {
  144. LOG_ERR("Specify the bind entity when specifying the bind auth "
  145. "even when bind is same as tpmkey object.");
  146. return tool_rc_option_error;
  147. }
  148. /*
  149. * Setting sessions for audit should be handled with tpm2_sessionconfig
  150. * The following support is for backwards compatibility
  151. */
  152. if (ctx.is_real_policy_session && ctx.is_session_audit_required) {
  153. LOG_ERR("Policy sessions cannot be additionally used for audit");
  154. return tool_rc_option_error;
  155. }
  156. /*
  157. * A session cannot be without a purpose.
  158. */
  159. if (!(ctx.attrs & TPMA_SESSION_AUDIT) &&
  160. !(ctx.attrs & TPMA_SESSION_ENCRYPT) &&
  161. !(ctx.attrs & TPMA_SESSION_DECRYPT) && ctx.is_hmac_session) {
  162. LOG_WARN("Session has to be used either for auth and/or audit and/or "
  163. "parameter-encryption/decryption. Use session-config tool to "
  164. "specify the use");
  165. }
  166. return tool_rc_success;
  167. }
  168. static tool_rc setup_session_data(void) {
  169. if (ctx.is_real_policy_session) {
  170. ctx.session.type = TPM2_SE_POLICY;
  171. }
  172. if (ctx.is_hmac_session) {
  173. ctx.session.type = TPM2_SE_HMAC;
  174. }
  175. ctx.session_data = tpm2_session_data_new(ctx.session.type);
  176. if (!ctx.session_data) {
  177. LOG_ERR("oom");
  178. return tool_rc_general_error;
  179. }
  180. tpm2_session_set_path(ctx.session_data, ctx.output.path);
  181. tpm2_session_set_authhash(ctx.session_data, ctx.session.halg);
  182. if (ctx.is_session_encryption_possibly_needed) {
  183. TPMT_SYM_DEF sym = {
  184. .algorithm = TPM2_ALG_AES,
  185. .keyBits = {
  186. .aes = 128
  187. },
  188. .mode = {
  189. .aes = TPM2_ALG_CFB
  190. }
  191. };
  192. tpm2_session_set_symmetric(ctx.session_data, &sym);
  193. }
  194. if (ctx.session.bind.bind_context_arg_str) {
  195. tpm2_session_set_bind(ctx.session_data,
  196. ctx.session.bind.bind_context_object.tr_handle);
  197. }
  198. if (ctx.session.tpmkey.key_context_arg_str) {
  199. tpm2_session_set_key(ctx.session_data,
  200. ctx.session.tpmkey.key_context_object.tr_handle);
  201. }
  202. tpm2_session_set_attrs(ctx.session_data, ctx.attrs);
  203. return tool_rc_success;
  204. }
  205. static tool_rc process_input_data(ESYS_CONTEXT *ectx) {
  206. /*
  207. * Backwards compatibility behavior/ side-effect:
  208. *
  209. * The presence of a tpmkey and bind object should not result in setting up
  210. * the session for parameter encryption. It is not a requirement. IOW one
  211. * can have a salted and bounded session and not perform parameter
  212. * encryption.
  213. */
  214. if (ctx.session.tpmkey.key_context_arg_str) {
  215. /*
  216. * attempt to set up the encryption parameters for this, we load an ESYS_TR
  217. * from disk for transient objects and we load from tpm public for
  218. * persistent objects. Deserialized ESYS TR objects are checked.
  219. */
  220. tool_rc rc = tpm2_util_object_load(ectx,
  221. ctx.session.tpmkey.key_context_arg_str,
  222. &ctx.session.tpmkey.key_context_object, TPM2_HANDLE_ALL_W_NV);
  223. if (rc != tool_rc_success) {
  224. return rc;
  225. }
  226. /* if loaded object is non-permanant, it should ideally be persistent */
  227. if (ctx.session.tpmkey.key_context_object.handle) {
  228. bool is_transient = (ctx.session.tpmkey.key_context_object.handle
  229. >> TPM2_HR_SHIFT) == TPM2_HT_TRANSIENT;
  230. if (!is_transient) {
  231. LOG_WARN("check public portion of the tpmkey manually");
  232. }
  233. }
  234. }
  235. /*
  236. * We need to load the bind object and set its auth value in the bind
  237. * objects ESYS_TR.
  238. *
  239. * A loaded object creates another session and that is not what we want.
  240. */
  241. if (ctx.session.bind.bind_context_arg_str) {
  242. tool_rc rc = tpm2_util_object_load(ectx,
  243. ctx.session.bind.bind_context_arg_str,
  244. &ctx.session.bind.bind_context_object, TPM2_HANDLE_ALL_W_NV);
  245. if (rc != tool_rc_success) {
  246. return rc;
  247. }
  248. }
  249. if (ctx.session.bind.bind_context_auth_str) {
  250. TPM2B_AUTH authvalue = { 0 };
  251. bool result = handle_str_password(
  252. ctx.session.bind.bind_context_auth_str, &authvalue);
  253. if (!result) {
  254. return tool_rc_general_error;
  255. }
  256. tool_rc rc = tpm2_tr_set_auth(ectx,
  257. ctx.session.bind.bind_context_object.tr_handle, &authvalue);
  258. if (rc != tool_rc_success) {
  259. LOG_ERR("Failed setting auth in the bind object ESYS_TR");
  260. return rc;
  261. }
  262. }
  263. return setup_session_data();
  264. }
  265. static tool_rc tpm2_tool_onrun(ESYS_CONTEXT *ectx, tpm2_option_flags flags) {
  266. UNUSED(flags);
  267. //Check input options
  268. tool_rc rc = is_input_options_valid();
  269. if (rc != tool_rc_success) {
  270. return rc;
  271. }
  272. //Process inputs
  273. rc = process_input_data(ectx);
  274. if (rc != tool_rc_success) {
  275. return rc;
  276. }
  277. //ESAPI call to start session
  278. tpm2_session *s = NULL;
  279. rc = tpm2_session_open(ectx, ctx.session_data, &s);
  280. if (rc != tool_rc_success) {
  281. return rc;
  282. }
  283. //Process outputs
  284. return tpm2_session_close(&s);
  285. }
  286. // Register this tool with tpm2_tool.c
  287. TPM2_TOOL_REGISTER("startauthsession", tpm2_tool_onstart, tpm2_tool_onrun, NULL,
  288. NULL)