2
0

tpm_util.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /*
  2. * TPM utility functions
  3. *
  4. * Copyright (c) 2010 - 2015 IBM Corporation
  5. * Authors:
  6. * Stefan Berger <stefanb@us.ibm.com>
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 2 of the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, see <http://www.gnu.org/licenses/>
  20. */
  21. #include "qemu/osdep.h"
  22. #include "qemu/error-report.h"
  23. #include "qapi/error.h"
  24. #include "qapi/visitor.h"
  25. #include "tpm_util.h"
  26. #include "tpm_int.h"
  27. #include "exec/memory.h"
  28. #include "hw/qdev-properties.h"
  29. #include "sysemu/tpm_backend.h"
  30. #include "trace.h"
  31. /* tpm backend property */
  32. static void get_tpm(Object *obj, Visitor *v, const char *name, void *opaque,
  33. Error **errp)
  34. {
  35. DeviceState *dev = DEVICE(obj);
  36. TPMBackend **be = qdev_get_prop_ptr(dev, opaque);
  37. char *p;
  38. p = g_strdup(*be ? (*be)->id : "");
  39. visit_type_str(v, name, &p, errp);
  40. g_free(p);
  41. }
  42. static void set_tpm(Object *obj, Visitor *v, const char *name, void *opaque,
  43. Error **errp)
  44. {
  45. DeviceState *dev = DEVICE(obj);
  46. Error *local_err = NULL;
  47. Property *prop = opaque;
  48. TPMBackend *s, **be = qdev_get_prop_ptr(dev, prop);
  49. char *str;
  50. if (dev->realized) {
  51. qdev_prop_set_after_realize(dev, name, errp);
  52. return;
  53. }
  54. visit_type_str(v, name, &str, &local_err);
  55. if (local_err) {
  56. error_propagate(errp, local_err);
  57. return;
  58. }
  59. s = qemu_find_tpm_be(str);
  60. if (s == NULL) {
  61. error_setg(errp, "Property '%s.%s' can't find value '%s'",
  62. object_get_typename(obj), prop->name, str);
  63. } else if (tpm_backend_init(s, TPM_IF(obj), errp) == 0) {
  64. *be = s; /* weak reference, avoid cyclic ref */
  65. }
  66. g_free(str);
  67. }
  68. static void release_tpm(Object *obj, const char *name, void *opaque)
  69. {
  70. DeviceState *dev = DEVICE(obj);
  71. Property *prop = opaque;
  72. TPMBackend **be = qdev_get_prop_ptr(dev, prop);
  73. if (*be) {
  74. tpm_backend_reset(*be);
  75. }
  76. }
  77. const PropertyInfo qdev_prop_tpm = {
  78. .name = "str",
  79. .description = "ID of a tpm to use as a backend",
  80. .get = get_tpm,
  81. .set = set_tpm,
  82. .release = release_tpm,
  83. };
  84. /*
  85. * Write an error message in the given output buffer.
  86. */
  87. void tpm_util_write_fatal_error_response(uint8_t *out, uint32_t out_len)
  88. {
  89. if (out_len >= sizeof(struct tpm_resp_hdr)) {
  90. tpm_cmd_set_tag(out, TPM_TAG_RSP_COMMAND);
  91. tpm_cmd_set_size(out, sizeof(struct tpm_resp_hdr));
  92. tpm_cmd_set_error(out, TPM_FAIL);
  93. }
  94. }
  95. bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len)
  96. {
  97. if (in_len >= sizeof(struct tpm_req_hdr)) {
  98. return tpm_cmd_get_ordinal(in) == TPM_ORD_ContinueSelfTest;
  99. }
  100. return false;
  101. }
  102. /*
  103. * Send request to a TPM device. We expect a response within one second.
  104. */
  105. static int tpm_util_request(int fd,
  106. const void *request,
  107. size_t requestlen,
  108. void *response,
  109. size_t responselen)
  110. {
  111. fd_set readfds;
  112. int n;
  113. struct timeval tv = {
  114. .tv_sec = 1,
  115. .tv_usec = 0,
  116. };
  117. n = write(fd, request, requestlen);
  118. if (n < 0) {
  119. return -errno;
  120. }
  121. if (n != requestlen) {
  122. return -EFAULT;
  123. }
  124. FD_ZERO(&readfds);
  125. FD_SET(fd, &readfds);
  126. /* wait for a second */
  127. n = select(fd + 1, &readfds, NULL, NULL, &tv);
  128. if (n != 1) {
  129. return -errno;
  130. }
  131. n = read(fd, response, responselen);
  132. if (n < sizeof(struct tpm_resp_hdr)) {
  133. return -EFAULT;
  134. }
  135. /* check the header */
  136. if (tpm_cmd_get_size(response) != n) {
  137. return -EMSGSIZE;
  138. }
  139. return 0;
  140. }
  141. /*
  142. * A basic test of a TPM device. We expect a well formatted response header
  143. * (error response is fine).
  144. */
  145. static int tpm_util_test(int fd,
  146. const void *request,
  147. size_t requestlen,
  148. uint16_t *return_tag)
  149. {
  150. char buf[1024];
  151. ssize_t ret;
  152. ret = tpm_util_request(fd, request, requestlen,
  153. buf, sizeof(buf));
  154. if (ret < 0) {
  155. return ret;
  156. }
  157. *return_tag = tpm_cmd_get_tag(buf);
  158. return 0;
  159. }
  160. /*
  161. * Probe for the TPM device in the back
  162. * Returns 0 on success with the version of the probed TPM set, 1 on failure.
  163. */
  164. int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version)
  165. {
  166. /*
  167. * Sending a TPM1.2 command to a TPM2 should return a TPM1.2
  168. * header (tag = 0xc4) and error code (TPM_BADTAG = 0x1e)
  169. *
  170. * Sending a TPM2 command to a TPM 2 will give a TPM 2 tag in the
  171. * header.
  172. * Sending a TPM2 command to a TPM 1.2 will give a TPM 1.2 tag
  173. * in the header and an error code.
  174. */
  175. const struct tpm_req_hdr test_req = {
  176. .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
  177. .len = cpu_to_be32(sizeof(test_req)),
  178. .ordinal = cpu_to_be32(TPM_ORD_GetTicks),
  179. };
  180. const struct tpm_req_hdr test_req_tpm2 = {
  181. .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
  182. .len = cpu_to_be32(sizeof(test_req_tpm2)),
  183. .ordinal = cpu_to_be32(TPM2_CC_ReadClock),
  184. };
  185. uint16_t return_tag;
  186. int ret;
  187. /* Send TPM 2 command */
  188. ret = tpm_util_test(tpm_fd, &test_req_tpm2,
  189. sizeof(test_req_tpm2), &return_tag);
  190. /* TPM 2 would respond with a tag of TPM2_ST_NO_SESSIONS */
  191. if (!ret && return_tag == TPM2_ST_NO_SESSIONS) {
  192. *tpm_version = TPM_VERSION_2_0;
  193. return 0;
  194. }
  195. /* Send TPM 1.2 command */
  196. ret = tpm_util_test(tpm_fd, &test_req,
  197. sizeof(test_req), &return_tag);
  198. if (!ret && return_tag == TPM_TAG_RSP_COMMAND) {
  199. *tpm_version = TPM_VERSION_1_2;
  200. /* this is a TPM 1.2 */
  201. return 0;
  202. }
  203. *tpm_version = TPM_VERSION_UNSPEC;
  204. return 1;
  205. }
  206. int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version,
  207. size_t *buffersize)
  208. {
  209. int ret;
  210. switch (tpm_version) {
  211. case TPM_VERSION_1_2: {
  212. const struct tpm_req_get_buffer_size {
  213. struct tpm_req_hdr hdr;
  214. uint32_t capability;
  215. uint32_t len;
  216. uint32_t subcap;
  217. } QEMU_PACKED tpm_get_buffer_size = {
  218. .hdr = {
  219. .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
  220. .len = cpu_to_be32(sizeof(tpm_get_buffer_size)),
  221. .ordinal = cpu_to_be32(TPM_ORD_GetCapability),
  222. },
  223. .capability = cpu_to_be32(TPM_CAP_PROPERTY),
  224. .len = cpu_to_be32(sizeof(uint32_t)),
  225. .subcap = cpu_to_be32(TPM_CAP_PROP_INPUT_BUFFER),
  226. };
  227. struct tpm_resp_get_buffer_size {
  228. struct tpm_resp_hdr hdr;
  229. uint32_t len;
  230. uint32_t buffersize;
  231. } QEMU_PACKED tpm_resp;
  232. ret = tpm_util_request(tpm_fd, &tpm_get_buffer_size,
  233. sizeof(tpm_get_buffer_size),
  234. &tpm_resp, sizeof(tpm_resp));
  235. if (ret < 0) {
  236. return ret;
  237. }
  238. if (be32_to_cpu(tpm_resp.hdr.len) != sizeof(tpm_resp) ||
  239. be32_to_cpu(tpm_resp.len) != sizeof(uint32_t)) {
  240. trace_tpm_util_get_buffer_size_hdr_len(
  241. be32_to_cpu(tpm_resp.hdr.len),
  242. sizeof(tpm_resp));
  243. trace_tpm_util_get_buffer_size_len(be32_to_cpu(tpm_resp.len),
  244. sizeof(uint32_t));
  245. error_report("tpm_util: Got unexpected response to "
  246. "TPM_GetCapability; errcode: 0x%x",
  247. be32_to_cpu(tpm_resp.hdr.errcode));
  248. return -EFAULT;
  249. }
  250. *buffersize = be32_to_cpu(tpm_resp.buffersize);
  251. break;
  252. }
  253. case TPM_VERSION_2_0: {
  254. const struct tpm2_req_get_buffer_size {
  255. struct tpm_req_hdr hdr;
  256. uint32_t capability;
  257. uint32_t property;
  258. uint32_t count;
  259. } QEMU_PACKED tpm2_get_buffer_size = {
  260. .hdr = {
  261. .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
  262. .len = cpu_to_be32(sizeof(tpm2_get_buffer_size)),
  263. .ordinal = cpu_to_be32(TPM2_CC_GetCapability),
  264. },
  265. .capability = cpu_to_be32(TPM2_CAP_TPM_PROPERTIES),
  266. .property = cpu_to_be32(TPM2_PT_MAX_COMMAND_SIZE),
  267. .count = cpu_to_be32(2), /* also get TPM2_PT_MAX_RESPONSE_SIZE */
  268. };
  269. struct tpm2_resp_get_buffer_size {
  270. struct tpm_resp_hdr hdr;
  271. uint8_t more;
  272. uint32_t capability;
  273. uint32_t count;
  274. uint32_t property1;
  275. uint32_t value1;
  276. uint32_t property2;
  277. uint32_t value2;
  278. } QEMU_PACKED tpm2_resp;
  279. ret = tpm_util_request(tpm_fd, &tpm2_get_buffer_size,
  280. sizeof(tpm2_get_buffer_size),
  281. &tpm2_resp, sizeof(tpm2_resp));
  282. if (ret < 0) {
  283. return ret;
  284. }
  285. if (be32_to_cpu(tpm2_resp.hdr.len) != sizeof(tpm2_resp) ||
  286. be32_to_cpu(tpm2_resp.count) != 2) {
  287. trace_tpm_util_get_buffer_size_hdr_len2(
  288. be32_to_cpu(tpm2_resp.hdr.len),
  289. sizeof(tpm2_resp));
  290. trace_tpm_util_get_buffer_size_len2(
  291. be32_to_cpu(tpm2_resp.count), 2);
  292. error_report("tpm_util: Got unexpected response to "
  293. "TPM2_GetCapability; errcode: 0x%x",
  294. be32_to_cpu(tpm2_resp.hdr.errcode));
  295. return -EFAULT;
  296. }
  297. *buffersize = MAX(be32_to_cpu(tpm2_resp.value1),
  298. be32_to_cpu(tpm2_resp.value2));
  299. break;
  300. }
  301. case TPM_VERSION_UNSPEC:
  302. return -EFAULT;
  303. }
  304. trace_tpm_util_get_buffer_size(*buffersize);
  305. return 0;
  306. }
  307. void tpm_sized_buffer_reset(TPMSizedBuffer *tsb)
  308. {
  309. g_free(tsb->buffer);
  310. tsb->buffer = NULL;
  311. tsb->size = 0;
  312. }