tpm2_auth_util.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. /* SPDX-License-Identifier: BSD-3-Clause */
  2. #include <errno.h>
  3. #include <limits.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <termios.h>
  8. #include <unistd.h>
  9. #include "files.h"
  10. #include "log.h"
  11. #include "pcr.h"
  12. #include "tpm2.h"
  13. #include "tpm2_auth_util.h"
  14. #include "tpm2_policy.h"
  15. #define HEX_PREFIX "hex:"
  16. #define HEX_PREFIX_LEN sizeof(HEX_PREFIX) - 1
  17. #define STR_PREFIX "str:"
  18. #define STR_PREFIX_LEN sizeof(STR_PREFIX) - 1
  19. #define SESSION_PREFIX "session:"
  20. #define SESSION_PREFIX_LEN sizeof(SESSION_PREFIX) - 1
  21. #define FILE_PREFIX "file:"
  22. #define FILE_PREFIX_LEN sizeof(FILE_PREFIX) - 1
  23. #define PCR_PREFIX "pcr:"
  24. #define PCR_PREFIX_LEN sizeof(PCR_PREFIX) - 1
  25. static bool handle_hex_password(const char *password, TPM2B_AUTH *auth) {
  26. /* if it is hex, then skip the prefix */
  27. password += HEX_PREFIX_LEN;
  28. auth->size = BUFFER_SIZE(typeof(*auth), buffer);
  29. int rc = tpm2_util_hex_to_byte_structure(password, &auth->size,
  30. auth->buffer);
  31. if (rc) {
  32. auth->size = 0;
  33. return false;
  34. }
  35. return true;
  36. }
  37. bool handle_str_password(const char *password, TPM2B_AUTH *auth) {
  38. /* str may or may not have the str: prefix */
  39. bool is_str_prefix = !strncmp(password, STR_PREFIX, STR_PREFIX_LEN);
  40. if (is_str_prefix) {
  41. password += STR_PREFIX_LEN;
  42. }
  43. /*
  44. * Per the man page:
  45. * "a return value of size or more means that the output was truncated."
  46. */
  47. size_t wrote = snprintf((char * )&auth->buffer,
  48. BUFFER_SIZE(typeof(*auth), buffer), "%s", password);
  49. if (wrote >= BUFFER_SIZE(typeof(*auth), buffer)) {
  50. auth->size = 0;
  51. return false;
  52. }
  53. auth->size = wrote;
  54. return true;
  55. }
  56. static bool handle_password(const char *password, TPM2B_AUTH *auth) {
  57. bool is_hex = !strncmp(password, HEX_PREFIX, HEX_PREFIX_LEN);
  58. if (is_hex) {
  59. return handle_hex_password(password, auth);
  60. }
  61. /* must be string, handle it */
  62. return handle_str_password(password, auth);
  63. }
  64. static tool_rc start_hmac_session(ESYS_CONTEXT *ectx, TPM2B_AUTH *auth,
  65. tpm2_session **session) {
  66. tpm2_session_data *d = tpm2_session_data_new(TPM2_SE_HMAC);
  67. if (!d) {
  68. LOG_ERR("oom");
  69. return tool_rc_general_error;
  70. }
  71. tool_rc rc = tpm2_session_open(ectx, d, session);
  72. if (rc != tool_rc_success) {
  73. return rc;
  74. }
  75. tpm2_session_set_auth_value(*session, auth);
  76. return tool_rc_success;
  77. }
  78. static tool_rc handle_password_session(ESYS_CONTEXT *ectx, const char *password,
  79. tpm2_session **session) {
  80. TPM2B_AUTH auth = { 0 };
  81. bool result = handle_password(password, &auth);
  82. if (!result) {
  83. return tool_rc_general_error;
  84. }
  85. return start_hmac_session(ectx, &auth, session);
  86. }
  87. static tool_rc handle_session(ESYS_CONTEXT *ectx, const char *path,
  88. tpm2_session **session) {
  89. TPM2B_AUTH auth = { 0 };
  90. /* if it is session, then skip the prefix */
  91. path += SESSION_PREFIX_LEN;
  92. /* Make a local copy for manipulation */
  93. char tmp[PATH_MAX];
  94. size_t len = snprintf(tmp, sizeof(tmp), "%s", path);
  95. if (len >= sizeof(tmp)) {
  96. LOG_ERR("Path truncated");
  97. return tool_rc_general_error;
  98. }
  99. /*
  100. * Sessions can have an associated password/auth value denoted after
  101. * a + sign, ie session.ctx+foo, deal with it by
  102. * finding a +, splitting the string on it, and if
  103. * not a NULL byte after the +, use that as a password.
  104. */
  105. char *password = strchr(tmp, '+');
  106. if (password) {
  107. *password = '\0';
  108. password++;
  109. if (*password) {
  110. bool result = handle_password(password, &auth);
  111. if (!result) {
  112. return tool_rc_general_error;
  113. }
  114. }
  115. }
  116. tool_rc rc = tpm2_session_restore(ectx, tmp, false, session);
  117. if (rc != tool_rc_success) {
  118. return rc;
  119. }
  120. tpm2_session_set_auth_value(*session, &auth);
  121. bool is_trial = tpm2_session_is_trial(*session);
  122. if (is_trial) {
  123. LOG_ERR("A trial session cannot be used to authenticate, "
  124. "Please use an hmac or policy session");
  125. tpm2_session_close(session);
  126. return tool_rc_general_error;
  127. }
  128. return tool_rc_success;
  129. }
  130. static bool parse_pcr(const char *policy, char **pcr_str, char **raw_path) {
  131. char *split;
  132. policy += PCR_PREFIX_LEN;
  133. *pcr_str = NULL;
  134. *raw_path = NULL;
  135. /* completely empty PCR specification or just raw-pcr-file given */
  136. if ((policy[0] == '\0') || (policy[0] == '=')) {
  137. return false;
  138. }
  139. *pcr_str = strdup(policy);
  140. if (!*pcr_str) {
  141. LOG_ERR("oom");
  142. return false;
  143. }
  144. split = strchr(*pcr_str, '=');
  145. if (split) {
  146. split[0] = '\0';
  147. *raw_path = split + 1;
  148. /* empty raw-pcr-file */
  149. if (*raw_path[0] == '\0') {
  150. return false;
  151. }
  152. }
  153. return true;
  154. }
  155. static tool_rc handle_pcr(ESYS_CONTEXT *ectx, const char *policy,
  156. tpm2_session **session) {
  157. tool_rc rc = tool_rc_general_error;
  158. char *pcr_str, *raw_path;
  159. TPML_PCR_SELECTION pcrs;
  160. bool ret;
  161. ret = parse_pcr(policy, &pcr_str, &raw_path);
  162. if (!ret) {
  163. goto out;
  164. }
  165. ret = pcr_parse_selections(pcr_str, &pcrs);
  166. if (!ret) {
  167. goto out;
  168. }
  169. tpm2_session_data *d = tpm2_session_data_new(TPM2_SE_POLICY);
  170. if (!d) {
  171. LOG_ERR("oom");
  172. goto out;
  173. }
  174. tpm2_session *s = NULL;
  175. tool_rc tmp_rc = tpm2_session_open(ectx, d, &s);
  176. if (tmp_rc != tool_rc_success) {
  177. LOG_ERR("Could not start tpm session");
  178. rc = tmp_rc;
  179. goto out;
  180. }
  181. tmp_rc = tpm2_policy_build_pcr(ectx, s, raw_path, &pcrs, NULL);
  182. if (tmp_rc != tool_rc_success) {
  183. tpm2_session_close(&s);
  184. rc = tmp_rc;
  185. goto out;
  186. }
  187. *session = s;
  188. rc = tool_rc_success;
  189. out:
  190. free(pcr_str);
  191. return rc;
  192. }
  193. static tool_rc console_display_echo_control(bool echo) {
  194. struct termios console;
  195. int rc = tcgetattr(STDIN_FILENO, &console);
  196. if (rc) {
  197. return tool_rc_general_error;
  198. }
  199. if (echo) {
  200. console.c_lflag |= ECHO;
  201. } else {
  202. console.c_lflag &= ~((tcflag_t) ECHO);
  203. }
  204. rc = tcsetattr(STDIN_FILENO, TCSANOW, &console);
  205. if (rc) {
  206. return tool_rc_general_error;
  207. }
  208. return tool_rc_success;
  209. }
  210. static tool_rc handle_file(ESYS_CONTEXT *ectx, const char *path,
  211. tpm2_session **session) {
  212. path += FILE_PREFIX_LEN;
  213. path = strcmp("-", path) ? path : NULL;
  214. TPM2B_AUTH auth = { 0 };
  215. UINT8 buffer[(sizeof(auth.buffer) * 2) + HEX_PREFIX_LEN + 1] = { 0 };
  216. /*
  217. * If path is set or stdin is not a TTY, then read
  218. * from a path. Note: that "file:" will still go this
  219. * path and fail as path "" is not valid.
  220. */
  221. bool is_a_tty = isatty(STDIN_FILENO);
  222. if (!is_a_tty || path) {
  223. UINT16 size = sizeof(buffer) - 1;
  224. bool ret = files_load_bytes_from_buffer_or_file_or_stdin(NULL, path,
  225. &size, buffer);
  226. if (!ret) {
  227. return tool_rc_general_error;
  228. }
  229. /* bash here strings and many commands add a trailing newline, if its stdin, kill the newline */
  230. if (!path && buffer[size - 1] == '\n') {
  231. buffer[size - 1] = '\0';
  232. }
  233. /*
  234. * It is a TTY and we're reading from stdin.
  235. * Prompt the user for the password with echoing
  236. * disabled.
  237. */
  238. } else {
  239. tool_rc rc = console_display_echo_control(false);
  240. if (rc != tool_rc_success) {
  241. return rc;
  242. }
  243. printf("Enter Password: ");
  244. fflush(stdout);
  245. char *b = (char *) buffer;
  246. size_t size = sizeof(buffer) - 1;
  247. ssize_t read = getline(&b, &size, stdin);
  248. if (read < 0) {
  249. LOG_ERR("Could not get stdin, error: \"%s\"", strerror(errno));
  250. }
  251. b[read - 1] = '\0';
  252. rc = console_display_echo_control(true);
  253. if (rc != tool_rc_success || read < 0) {
  254. return tool_rc_general_error;
  255. }
  256. }
  257. /* from here the buffer has been populated with the password */
  258. bool ret = handle_password((char *) buffer, &auth);
  259. if (!ret) {
  260. return tool_rc_general_error;
  261. }
  262. return start_hmac_session(ectx, &auth, session);
  263. }
  264. tool_rc tpm2_auth_util_from_optarg(ESYS_CONTEXT *ectx, const char *password,
  265. tpm2_session **session, bool is_restricted) {
  266. password = password ? password : "";
  267. /* starts with session: */
  268. bool is_session = !strncmp(password, SESSION_PREFIX, SESSION_PREFIX_LEN);
  269. if (is_session) {
  270. if (is_restricted) {
  271. LOG_ERR("cannot specify password");
  272. return tool_rc_general_error;
  273. }
  274. return handle_session(ectx, password, session);
  275. }
  276. /* starts with "file:" */
  277. bool is_file = !strncmp(password, FILE_PREFIX, FILE_PREFIX_LEN);
  278. if (is_file) {
  279. return handle_file(ectx, password, session);
  280. }
  281. /* starts with pcr: */
  282. bool is_pcr = !strncmp(password, PCR_PREFIX, PCR_PREFIX_LEN);
  283. if (is_pcr) {
  284. return handle_pcr(ectx, password, session);
  285. }
  286. /* must be a password */
  287. return handle_password_session(ectx, password, session);
  288. }
  289. tool_rc tpm2_auth_util_get_shandle(ESYS_CONTEXT *ectx, ESYS_TR object,
  290. tpm2_session *session, ESYS_TR *out) {
  291. *out = tpm2_session_get_handle(session);
  292. const TPM2B_AUTH *auth = tpm2_session_get_auth_value(session);
  293. return tpm2_tr_set_auth(ectx, object, auth);
  294. }