tpm2_tis_sandbox.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (c) 2018, Bootlin
  4. * Author: Miquel Raynal <miquel.raynal@bootlin.com>
  5. */
  6. #include <common.h>
  7. #include <dm.h>
  8. #include <tpm-v2.h>
  9. #include <asm/state.h>
  10. #include <asm/unaligned.h>
  11. #include <linux/bitops.h>
  12. #include <u-boot/crc.h>
  13. #include <u-boot/sha256.h>
  14. #include "sandbox_common.h"
  15. /* Hierarchies */
  16. enum tpm2_hierarchy {
  17. TPM2_HIERARCHY_LOCKOUT = 0,
  18. TPM2_HIERARCHY_ENDORSEMENT,
  19. TPM2_HIERARCHY_PLATFORM,
  20. TPM2_HIERARCHY_NB,
  21. };
  22. /* Subset of supported capabilities */
  23. enum tpm2_capability {
  24. TPM_CAP_TPM_PROPERTIES = 0x6,
  25. };
  26. /* Subset of supported properties */
  27. #define TPM2_PROPERTIES_OFFSET 0x0000020E
  28. enum tpm2_cap_tpm_property {
  29. TPM2_FAIL_COUNTER = 0,
  30. TPM2_PROP_MAX_TRIES,
  31. TPM2_RECOVERY_TIME,
  32. TPM2_LOCKOUT_RECOVERY,
  33. TPM2_PROPERTY_NB,
  34. };
  35. #define SANDBOX_TPM_PCR_NB 1
  36. /*
  37. * Information about our TPM emulation. This is preserved in the sandbox
  38. * state file if enabled.
  39. *
  40. * @valid: true if this is valid (only used in s_state)
  41. * @init_done: true if open() has been called
  42. * @startup_done: true if TPM2_CC_STARTUP has been processed
  43. * @tests_done: true if TPM2_CC_SELF_TEST has be processed
  44. * @pw: TPM password per hierarchy
  45. * @pw_sz: Size of each password in bytes
  46. * @properties: TPM properties
  47. * @pcr: TPM Platform Configuration Registers. Each of these holds a hash and
  48. * can be 'extended' a number of times, meaning another hash is added into
  49. * its value (initial value all zeroes)
  50. * @pcr_extensions: Number of times each PCR has been extended (starts at 0)
  51. * @nvdata: non-volatile data, used to store important things for the platform
  52. */
  53. struct sandbox_tpm2 {
  54. bool valid;
  55. /* TPM internal states */
  56. bool init_done;
  57. bool startup_done;
  58. bool tests_done;
  59. char pw[TPM2_HIERARCHY_NB][TPM2_DIGEST_LEN + 1];
  60. int pw_sz[TPM2_HIERARCHY_NB];
  61. u32 properties[TPM2_PROPERTY_NB];
  62. u8 pcr[SANDBOX_TPM_PCR_NB][TPM2_DIGEST_LEN];
  63. u32 pcr_extensions[SANDBOX_TPM_PCR_NB];
  64. struct nvdata_state nvdata[NV_SEQ_COUNT];
  65. };
  66. static struct sandbox_tpm2 s_state, *g_state;
  67. /**
  68. * sandbox_tpm2_read_state() - read the sandbox EC state from the state file
  69. *
  70. * If data is available, then blob and node will provide access to it. If
  71. * not this function sets up an empty TPM.
  72. *
  73. * @blob: Pointer to device tree blob, or NULL if no data to read
  74. * @node: Node offset to read from
  75. */
  76. static int sandbox_tpm2_read_state(const void *blob, int node)
  77. {
  78. struct sandbox_tpm2 *state = &s_state;
  79. char prop_name[20];
  80. const char *prop;
  81. int len;
  82. int i;
  83. if (!blob)
  84. return 0;
  85. state->tests_done = fdtdec_get_int(blob, node, "tests-done", 0);
  86. for (i = 0; i < TPM2_HIERARCHY_NB; i++) {
  87. snprintf(prop_name, sizeof(prop_name), "pw%d", i);
  88. prop = fdt_getprop(blob, node, prop_name, &len);
  89. if (len > TPM2_DIGEST_LEN)
  90. return log_msg_ret("pw", -E2BIG);
  91. if (prop) {
  92. memcpy(state->pw[i], prop, len);
  93. state->pw_sz[i] = len;
  94. }
  95. }
  96. for (i = 0; i < TPM2_PROPERTY_NB; i++) {
  97. snprintf(prop_name, sizeof(prop_name), "properties%d", i);
  98. state->properties[i] = fdtdec_get_uint(blob, node, prop_name,
  99. 0);
  100. }
  101. for (i = 0; i < SANDBOX_TPM_PCR_NB; i++) {
  102. int subnode;
  103. snprintf(prop_name, sizeof(prop_name), "pcr%d", i);
  104. subnode = fdt_subnode_offset(blob, node, prop_name);
  105. if (subnode < 0)
  106. continue;
  107. prop = fdt_getprop(blob, subnode, "value", &len);
  108. if (len != TPM2_DIGEST_LEN)
  109. return log_msg_ret("pcr", -E2BIG);
  110. memcpy(state->pcr[i], prop, TPM2_DIGEST_LEN);
  111. state->pcr_extensions[i] = fdtdec_get_uint(blob, subnode,
  112. "extensions", 0);
  113. }
  114. for (i = 0; i < NV_SEQ_COUNT; i++) {
  115. struct nvdata_state *nvd = &state->nvdata[i];
  116. sprintf(prop_name, "nvdata%d", i);
  117. prop = fdt_getprop(blob, node, prop_name, &len);
  118. if (len > NV_DATA_SIZE)
  119. return log_msg_ret("nvd", -E2BIG);
  120. if (prop) {
  121. memcpy(nvd->data, prop, len);
  122. nvd->length = len;
  123. nvd->present = true;
  124. }
  125. }
  126. s_state.valid = true;
  127. return 0;
  128. }
  129. /**
  130. * sandbox_tpm2_write_state() - Write out our state to the state file
  131. *
  132. * The caller will ensure that there is a node ready for the state. The node
  133. * may already contain the old state, in which case it is overridden.
  134. *
  135. * @blob: Device tree blob holding state
  136. * @node: Node to write our state into
  137. */
  138. static int sandbox_tpm2_write_state(void *blob, int node)
  139. {
  140. const struct sandbox_tpm2 *state = g_state;
  141. char prop_name[20];
  142. int i;
  143. if (!state)
  144. return 0;
  145. /*
  146. * We are guaranteed enough space to write basic properties. This is
  147. * SANDBOX_STATE_MIN_SPACE.
  148. *
  149. * We could use fdt_add_subnode() to put each set of data in its
  150. * own node - perhaps useful if we add access information to each.
  151. */
  152. fdt_setprop_u32(blob, node, "tests-done", state->tests_done);
  153. for (i = 0; i < TPM2_HIERARCHY_NB; i++) {
  154. if (state->pw_sz[i]) {
  155. snprintf(prop_name, sizeof(prop_name), "pw%d", i);
  156. fdt_setprop(blob, node, prop_name, state->pw[i],
  157. state->pw_sz[i]);
  158. }
  159. }
  160. for (i = 0; i < TPM2_PROPERTY_NB; i++) {
  161. snprintf(prop_name, sizeof(prop_name), "properties%d", i);
  162. fdt_setprop_u32(blob, node, prop_name, state->properties[i]);
  163. }
  164. for (i = 0; i < SANDBOX_TPM_PCR_NB; i++) {
  165. int subnode;
  166. snprintf(prop_name, sizeof(prop_name), "pcr%d", i);
  167. subnode = fdt_add_subnode(blob, node, prop_name);
  168. fdt_setprop(blob, subnode, "value", state->pcr[i],
  169. TPM2_DIGEST_LEN);
  170. fdt_setprop_u32(blob, subnode, "extensions",
  171. state->pcr_extensions[i]);
  172. }
  173. for (i = 0; i < NV_SEQ_COUNT; i++) {
  174. const struct nvdata_state *nvd = &state->nvdata[i];
  175. if (nvd->present) {
  176. snprintf(prop_name, sizeof(prop_name), "nvdata%d", i);
  177. fdt_setprop(blob, node, prop_name, nvd->data,
  178. nvd->length);
  179. }
  180. }
  181. return 0;
  182. }
  183. SANDBOX_STATE_IO(sandbox_tpm2, "sandbox,tpm2", sandbox_tpm2_read_state,
  184. sandbox_tpm2_write_state);
  185. /*
  186. * Check the tag validity depending on the command (authentication required or
  187. * not). If authentication is required, check it is valid. Update the auth
  188. * pointer to point to the next chunk of data to process if needed.
  189. */
  190. static int sandbox_tpm2_check_session(struct udevice *dev, u32 command, u16 tag,
  191. const u8 **auth,
  192. enum tpm2_hierarchy *hierarchy)
  193. {
  194. struct sandbox_tpm2 *tpm = dev_get_priv(dev);
  195. u32 handle, auth_sz, session_handle;
  196. u16 nonce_sz, pw_sz;
  197. const char *pw;
  198. switch (command) {
  199. case TPM2_CC_STARTUP:
  200. case TPM2_CC_SELF_TEST:
  201. case TPM2_CC_GET_CAPABILITY:
  202. case TPM2_CC_PCR_READ:
  203. if (tag != TPM2_ST_NO_SESSIONS) {
  204. printf("No session required for command 0x%x\n",
  205. command);
  206. return TPM2_RC_BAD_TAG;
  207. }
  208. return 0;
  209. case TPM2_CC_CLEAR:
  210. case TPM2_CC_HIERCHANGEAUTH:
  211. case TPM2_CC_DAM_RESET:
  212. case TPM2_CC_DAM_PARAMETERS:
  213. case TPM2_CC_PCR_EXTEND:
  214. case TPM2_CC_NV_READ:
  215. case TPM2_CC_NV_WRITE:
  216. case TPM2_CC_NV_WRITELOCK:
  217. case TPM2_CC_NV_DEFINE_SPACE:
  218. if (tag != TPM2_ST_SESSIONS) {
  219. printf("Session required for command 0x%x\n", command);
  220. return TPM2_RC_AUTH_CONTEXT;
  221. }
  222. handle = get_unaligned_be32(*auth);
  223. *auth += sizeof(handle);
  224. /*
  225. * PCR_Extend had a different protection mechanism and does not
  226. * use the same standards as other commands.
  227. */
  228. if (command == TPM2_CC_PCR_EXTEND)
  229. break;
  230. switch (handle) {
  231. case TPM2_RH_LOCKOUT:
  232. *hierarchy = TPM2_HIERARCHY_LOCKOUT;
  233. break;
  234. case TPM2_RH_ENDORSEMENT:
  235. if (command == TPM2_CC_CLEAR) {
  236. printf("Endorsement hierarchy unsupported\n");
  237. return TPM2_RC_AUTH_MISSING;
  238. }
  239. *hierarchy = TPM2_HIERARCHY_ENDORSEMENT;
  240. break;
  241. case TPM2_RH_PLATFORM:
  242. *hierarchy = TPM2_HIERARCHY_PLATFORM;
  243. if (command == TPM2_CC_NV_READ ||
  244. command == TPM2_CC_NV_WRITE ||
  245. command == TPM2_CC_NV_WRITELOCK)
  246. *auth += sizeof(u32);
  247. break;
  248. default:
  249. printf("Wrong handle 0x%x\n", handle);
  250. return TPM2_RC_VALUE;
  251. }
  252. break;
  253. default:
  254. printf("Command code not recognized: 0x%x\n", command);
  255. return TPM2_RC_COMMAND_CODE;
  256. }
  257. auth_sz = get_unaligned_be32(*auth);
  258. *auth += sizeof(auth_sz);
  259. session_handle = get_unaligned_be32(*auth);
  260. *auth += sizeof(session_handle);
  261. if (session_handle != TPM2_RS_PW) {
  262. printf("Wrong session handle 0x%x\n", session_handle);
  263. return TPM2_RC_VALUE;
  264. }
  265. nonce_sz = get_unaligned_be16(*auth);
  266. *auth += sizeof(nonce_sz);
  267. if (nonce_sz) {
  268. printf("Nonces not supported in Sandbox, aborting\n");
  269. return TPM2_RC_HANDLE;
  270. }
  271. /* Ignore attributes */
  272. *auth += sizeof(u8);
  273. pw_sz = get_unaligned_be16(*auth);
  274. *auth += sizeof(pw_sz);
  275. if (auth_sz != (9 + nonce_sz + pw_sz)) {
  276. printf("Authentication size (%d) do not match %d\n",
  277. auth_sz, 9 + nonce_sz + pw_sz);
  278. return TPM2_RC_SIZE;
  279. }
  280. /* No passwork is acceptable */
  281. if (!pw_sz && !tpm->pw_sz[*hierarchy])
  282. return TPM2_RC_SUCCESS;
  283. /* Password is too long */
  284. if (pw_sz > TPM2_DIGEST_LEN) {
  285. printf("Password should not be more than %dB\n",
  286. TPM2_DIGEST_LEN);
  287. return TPM2_RC_AUTHSIZE;
  288. }
  289. pw = (const char *)*auth;
  290. *auth += pw_sz;
  291. /* Password is wrong */
  292. if (pw_sz != tpm->pw_sz[*hierarchy] ||
  293. strncmp(pw, tpm->pw[*hierarchy], tpm->pw_sz[*hierarchy])) {
  294. printf("Authentication failed: wrong password.\n");
  295. return TPM2_RC_BAD_AUTH;
  296. }
  297. return TPM2_RC_SUCCESS;
  298. }
  299. static int sandbox_tpm2_check_readyness(struct udevice *dev, int command)
  300. {
  301. struct sandbox_tpm2 *tpm = dev_get_priv(dev);
  302. switch (command) {
  303. case TPM2_CC_STARTUP:
  304. if (!tpm->init_done || tpm->startup_done)
  305. return TPM2_RC_INITIALIZE;
  306. break;
  307. case TPM2_CC_GET_CAPABILITY:
  308. if (!tpm->init_done || !tpm->startup_done)
  309. return TPM2_RC_INITIALIZE;
  310. break;
  311. case TPM2_CC_SELF_TEST:
  312. if (!tpm->startup_done)
  313. return TPM2_RC_INITIALIZE;
  314. break;
  315. default:
  316. if (!tpm->tests_done)
  317. return TPM2_RC_NEEDS_TEST;
  318. break;
  319. }
  320. return 0;
  321. }
  322. static int sandbox_tpm2_fill_buf(u8 *recv, size_t *recv_len, u16 tag, u32 rc)
  323. {
  324. *recv_len = sizeof(tag) + sizeof(u32) + sizeof(rc);
  325. /* Write tag */
  326. put_unaligned_be16(tag, recv);
  327. recv += sizeof(tag);
  328. /* Write length */
  329. put_unaligned_be32(*recv_len, recv);
  330. recv += sizeof(u32);
  331. /* Write return code */
  332. put_unaligned_be32(rc, recv);
  333. recv += sizeof(rc);
  334. /* Add trailing \0 */
  335. *recv = '\0';
  336. return 0;
  337. }
  338. static int sandbox_tpm2_extend(struct udevice *dev, int pcr_index,
  339. const u8 *extension)
  340. {
  341. struct sandbox_tpm2 *tpm = dev_get_priv(dev);
  342. sha256_context ctx;
  343. /* Zero the PCR if this is the first use */
  344. if (!tpm->pcr_extensions[pcr_index])
  345. memset(tpm->pcr[pcr_index], '\0', TPM2_DIGEST_LEN);
  346. sha256_starts(&ctx);
  347. sha256_update(&ctx, tpm->pcr[pcr_index], TPM2_DIGEST_LEN);
  348. sha256_update(&ctx, extension, TPM2_DIGEST_LEN);
  349. sha256_finish(&ctx, tpm->pcr[pcr_index]);
  350. tpm->pcr_extensions[pcr_index]++;
  351. return 0;
  352. };
  353. static int sandbox_tpm2_xfer(struct udevice *dev, const u8 *sendbuf,
  354. size_t send_size, u8 *recvbuf,
  355. size_t *recv_len)
  356. {
  357. struct sandbox_tpm2 *tpm = dev_get_priv(dev);
  358. enum tpm2_hierarchy hierarchy = 0;
  359. const u8 *sent = sendbuf;
  360. u8 *recv = recvbuf;
  361. u32 length, command, rc = 0;
  362. u16 tag, mode, new_pw_sz;
  363. u8 yes_no;
  364. int i, j;
  365. /* TPM2_GetProperty */
  366. u32 capability, property, property_count;
  367. /* TPM2_PCR_Read/Extend variables */
  368. int pcr_index = 0;
  369. u64 pcr_map = 0;
  370. u32 selections, pcr_nb;
  371. u16 alg;
  372. u8 pcr_array_sz;
  373. tag = get_unaligned_be16(sent);
  374. sent += sizeof(tag);
  375. length = get_unaligned_be32(sent);
  376. sent += sizeof(length);
  377. if (length != send_size) {
  378. printf("TPM2: Unmatching length, received: %zd, expected: %d\n",
  379. send_size, length);
  380. rc = TPM2_RC_SIZE;
  381. sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
  382. return 0;
  383. }
  384. command = get_unaligned_be32(sent);
  385. sent += sizeof(command);
  386. rc = sandbox_tpm2_check_readyness(dev, command);
  387. if (rc) {
  388. sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
  389. return 0;
  390. }
  391. rc = sandbox_tpm2_check_session(dev, command, tag, &sent, &hierarchy);
  392. if (rc) {
  393. sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
  394. return 0;
  395. }
  396. switch (command) {
  397. case TPM2_CC_STARTUP:
  398. mode = get_unaligned_be16(sent);
  399. sent += sizeof(mode);
  400. switch (mode) {
  401. case TPM2_SU_CLEAR:
  402. case TPM2_SU_STATE:
  403. break;
  404. default:
  405. rc = TPM2_RC_VALUE;
  406. }
  407. tpm->startup_done = true;
  408. sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
  409. break;
  410. case TPM2_CC_SELF_TEST:
  411. yes_no = *sent;
  412. sent += sizeof(yes_no);
  413. switch (yes_no) {
  414. case TPMI_YES:
  415. case TPMI_NO:
  416. break;
  417. default:
  418. rc = TPM2_RC_VALUE;
  419. }
  420. tpm->tests_done = true;
  421. sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
  422. break;
  423. case TPM2_CC_CLEAR:
  424. /* Reset this hierarchy password */
  425. tpm->pw_sz[hierarchy] = 0;
  426. /* Reset all password if thisis the PLATFORM hierarchy */
  427. if (hierarchy == TPM2_HIERARCHY_PLATFORM)
  428. for (i = 0; i < TPM2_HIERARCHY_NB; i++)
  429. tpm->pw_sz[i] = 0;
  430. /* Reset the properties */
  431. for (i = 0; i < TPM2_PROPERTY_NB; i++)
  432. tpm->properties[i] = 0;
  433. /* Reset the PCRs and their number of extensions */
  434. for (i = 0; i < SANDBOX_TPM_PCR_NB; i++) {
  435. tpm->pcr_extensions[i] = 0;
  436. for (j = 0; j < TPM2_DIGEST_LEN; j++)
  437. tpm->pcr[i][j] = 0;
  438. }
  439. sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
  440. break;
  441. case TPM2_CC_HIERCHANGEAUTH:
  442. new_pw_sz = get_unaligned_be16(sent);
  443. sent += sizeof(new_pw_sz);
  444. if (new_pw_sz > TPM2_DIGEST_LEN) {
  445. rc = TPM2_RC_SIZE;
  446. } else if (new_pw_sz) {
  447. tpm->pw_sz[hierarchy] = new_pw_sz;
  448. memcpy(tpm->pw[hierarchy], sent, new_pw_sz);
  449. sent += new_pw_sz;
  450. }
  451. sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
  452. break;
  453. case TPM2_CC_GET_CAPABILITY:
  454. capability = get_unaligned_be32(sent);
  455. sent += sizeof(capability);
  456. if (capability != TPM_CAP_TPM_PROPERTIES) {
  457. printf("Sandbox TPM only support TPM_CAPABILITIES\n");
  458. return TPM2_RC_HANDLE;
  459. }
  460. property = get_unaligned_be32(sent);
  461. sent += sizeof(property);
  462. property -= TPM2_PROPERTIES_OFFSET;
  463. property_count = get_unaligned_be32(sent);
  464. sent += sizeof(property_count);
  465. if (!property_count ||
  466. property + property_count > TPM2_PROPERTY_NB) {
  467. rc = TPM2_RC_HANDLE;
  468. return sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
  469. }
  470. /* Write tag */
  471. put_unaligned_be16(tag, recv);
  472. recv += sizeof(tag);
  473. /* Ignore length for now */
  474. recv += sizeof(u32);
  475. /* Write return code */
  476. put_unaligned_be32(rc, recv);
  477. recv += sizeof(rc);
  478. /* Tell there is more data to read */
  479. *recv = TPMI_YES;
  480. recv += sizeof(yes_no);
  481. /* Repeat the capability */
  482. put_unaligned_be32(capability, recv);
  483. recv += sizeof(capability);
  484. /* Give the number of properties that follow */
  485. put_unaligned_be32(property_count, recv);
  486. recv += sizeof(property_count);
  487. /* Fill with the properties */
  488. for (i = 0; i < property_count; i++) {
  489. put_unaligned_be32(TPM2_PROPERTIES_OFFSET + property +
  490. i, recv);
  491. recv += sizeof(property);
  492. put_unaligned_be32(tpm->properties[property + i],
  493. recv);
  494. recv += sizeof(property);
  495. }
  496. /* Add trailing \0 */
  497. *recv = '\0';
  498. /* Write response length */
  499. *recv_len = recv - recvbuf;
  500. put_unaligned_be32(*recv_len, recvbuf + sizeof(tag));
  501. break;
  502. case TPM2_CC_DAM_PARAMETERS:
  503. tpm->properties[TPM2_PROP_MAX_TRIES] = get_unaligned_be32(sent);
  504. sent += sizeof(*tpm->properties);
  505. tpm->properties[TPM2_RECOVERY_TIME] = get_unaligned_be32(sent);
  506. sent += sizeof(*tpm->properties);
  507. tpm->properties[TPM2_LOCKOUT_RECOVERY] = get_unaligned_be32(sent);
  508. sent += sizeof(*tpm->properties);
  509. sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
  510. break;
  511. case TPM2_CC_PCR_READ:
  512. selections = get_unaligned_be32(sent);
  513. sent += sizeof(selections);
  514. if (selections != 1) {
  515. printf("Sandbox cannot handle more than one PCR\n");
  516. rc = TPM2_RC_VALUE;
  517. return sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
  518. }
  519. alg = get_unaligned_be16(sent);
  520. sent += sizeof(alg);
  521. if (alg != TPM2_ALG_SHA256) {
  522. printf("Sandbox TPM only handle SHA256 algorithm\n");
  523. rc = TPM2_RC_VALUE;
  524. return sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
  525. }
  526. pcr_array_sz = *sent;
  527. sent += sizeof(pcr_array_sz);
  528. if (!pcr_array_sz || pcr_array_sz > 8) {
  529. printf("Sandbox TPM cannot handle so much PCRs\n");
  530. rc = TPM2_RC_VALUE;
  531. return sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
  532. }
  533. for (i = 0; i < pcr_array_sz; i++)
  534. pcr_map += (u64)sent[i] << (i * 8);
  535. if (!pcr_map) {
  536. printf("Empty PCR map\n");
  537. rc = TPM2_RC_VALUE;
  538. return sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
  539. }
  540. for (i = 0; i < SANDBOX_TPM_PCR_NB; i++)
  541. if (pcr_map & BIT(i))
  542. pcr_index = i;
  543. if (pcr_index >= SANDBOX_TPM_PCR_NB) {
  544. printf("Invalid index %d, sandbox TPM handles up to %d PCR(s)\n",
  545. pcr_index, SANDBOX_TPM_PCR_NB);
  546. rc = TPM2_RC_VALUE;
  547. return sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
  548. }
  549. /* Write tag */
  550. put_unaligned_be16(tag, recv);
  551. recv += sizeof(tag);
  552. /* Ignore length for now */
  553. recv += sizeof(u32);
  554. /* Write return code */
  555. put_unaligned_be32(rc, recv);
  556. recv += sizeof(rc);
  557. /* Number of extensions */
  558. put_unaligned_be32(tpm->pcr_extensions[pcr_index], recv);
  559. recv += sizeof(u32);
  560. /* Copy the PCR */
  561. memcpy(recv, tpm->pcr[pcr_index], TPM2_DIGEST_LEN);
  562. recv += TPM2_DIGEST_LEN;
  563. /* Add trailing \0 */
  564. *recv = '\0';
  565. /* Write response length */
  566. *recv_len = recv - recvbuf;
  567. put_unaligned_be32(*recv_len, recvbuf + sizeof(tag));
  568. break;
  569. case TPM2_CC_PCR_EXTEND:
  570. /* Get the PCR index */
  571. pcr_index = get_unaligned_be32(sendbuf + sizeof(tag) +
  572. sizeof(length) +
  573. sizeof(command));
  574. if (pcr_index >= SANDBOX_TPM_PCR_NB) {
  575. printf("Invalid index %d, sandbox TPM handles up to %d PCR(s)\n",
  576. pcr_index, SANDBOX_TPM_PCR_NB);
  577. rc = TPM2_RC_VALUE;
  578. }
  579. /* Check the number of hashes */
  580. pcr_nb = get_unaligned_be32(sent);
  581. sent += sizeof(pcr_nb);
  582. if (pcr_nb != 1) {
  583. printf("Sandbox cannot handle more than one PCR\n");
  584. rc = TPM2_RC_VALUE;
  585. return sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
  586. }
  587. /* Check the hash algorithm */
  588. alg = get_unaligned_be16(sent);
  589. sent += sizeof(alg);
  590. if (alg != TPM2_ALG_SHA256) {
  591. printf("Sandbox TPM only handle SHA256 algorithm\n");
  592. rc = TPM2_RC_VALUE;
  593. return sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
  594. }
  595. /* Extend the PCR */
  596. rc = sandbox_tpm2_extend(dev, pcr_index, sent);
  597. sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
  598. break;
  599. case TPM2_CC_NV_READ: {
  600. int index, seq;
  601. index = get_unaligned_be32(sendbuf + TPM2_HDR_LEN + 4);
  602. length = get_unaligned_be16(sent);
  603. /* ignore offset */
  604. seq = sb_tpm_index_to_seq(index);
  605. if (seq < 0)
  606. return log_msg_ret("index", -EINVAL);
  607. printf("tpm: nvread index=%#02x, len=%#02x, seq=%#02x\n", index,
  608. length, seq);
  609. *recv_len = TPM2_HDR_LEN + 6 + length;
  610. memset(recvbuf, '\0', *recv_len);
  611. put_unaligned_be32(length, recvbuf + 2);
  612. sb_tpm_read_data(tpm->nvdata, seq, recvbuf,
  613. TPM2_HDR_LEN + 4 + 2, length);
  614. break;
  615. }
  616. case TPM2_CC_NV_WRITE: {
  617. int index, seq;
  618. index = get_unaligned_be32(sendbuf + TPM2_HDR_LEN + 4);
  619. length = get_unaligned_be16(sent);
  620. sent += sizeof(u16);
  621. /* ignore offset */
  622. seq = sb_tpm_index_to_seq(index);
  623. if (seq < 0)
  624. return log_msg_ret("index", -EINVAL);
  625. printf("tpm: nvwrite index=%#02x, len=%#02x, seq=%#02x\n", index,
  626. length, seq);
  627. memcpy(&tpm->nvdata[seq].data, sent, length);
  628. tpm->nvdata[seq].present = true;
  629. *recv_len = TPM2_HDR_LEN + 2;
  630. memset(recvbuf, '\0', *recv_len);
  631. break;
  632. }
  633. case TPM2_CC_NV_DEFINE_SPACE: {
  634. int policy_size, index, seq;
  635. policy_size = get_unaligned_be16(sent + 12);
  636. index = get_unaligned_be32(sent + 2);
  637. sent += 14 + policy_size;
  638. length = get_unaligned_be16(sent);
  639. seq = sb_tpm_index_to_seq(index);
  640. if (seq < 0)
  641. return -EINVAL;
  642. printf("tpm: define_space index=%x, len=%x, seq=%x, policy_size=%x\n",
  643. index, length, seq, policy_size);
  644. sb_tpm_define_data(tpm->nvdata, seq, length);
  645. *recv_len = 12;
  646. memset(recvbuf, '\0', *recv_len);
  647. break;
  648. }
  649. case TPM2_CC_NV_WRITELOCK:
  650. *recv_len = 12;
  651. memset(recvbuf, '\0', *recv_len);
  652. break;
  653. default:
  654. printf("TPM2 command %02x unknown in Sandbox\n", command);
  655. rc = TPM2_RC_COMMAND_CODE;
  656. sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
  657. }
  658. return 0;
  659. }
  660. static int sandbox_tpm2_get_desc(struct udevice *dev, char *buf, int size)
  661. {
  662. if (size < 15)
  663. return -ENOSPC;
  664. return snprintf(buf, size, "Sandbox TPM2.x");
  665. }
  666. static int sandbox_tpm2_open(struct udevice *dev)
  667. {
  668. struct sandbox_tpm2 *tpm = dev_get_priv(dev);
  669. if (tpm->init_done)
  670. return -EIO;
  671. tpm->init_done = true;
  672. return 0;
  673. }
  674. static int sandbox_tpm2_probe(struct udevice *dev)
  675. {
  676. struct sandbox_tpm2 *tpm = dev_get_priv(dev);
  677. struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
  678. /* Use the TPM v2 stack */
  679. priv->version = TPM_V2;
  680. priv->pcr_count = 32;
  681. priv->pcr_select_min = 2;
  682. if (s_state.valid)
  683. memcpy(tpm, &s_state, sizeof(*tpm));
  684. g_state = tpm;
  685. return 0;
  686. }
  687. static int sandbox_tpm2_close(struct udevice *dev)
  688. {
  689. return 0;
  690. }
  691. static const struct tpm_ops sandbox_tpm2_ops = {
  692. .open = sandbox_tpm2_open,
  693. .close = sandbox_tpm2_close,
  694. .get_desc = sandbox_tpm2_get_desc,
  695. .xfer = sandbox_tpm2_xfer,
  696. };
  697. static const struct udevice_id sandbox_tpm2_ids[] = {
  698. { .compatible = "sandbox,tpm2" },
  699. { }
  700. };
  701. U_BOOT_DRIVER(sandbox_tpm2) = {
  702. .name = "sandbox_tpm2",
  703. .id = UCLASS_TPM,
  704. .of_match = sandbox_tpm2_ids,
  705. .ops = &sandbox_tpm2_ops,
  706. .probe = sandbox_tpm2_probe,
  707. .priv_auto = sizeof(struct sandbox_tpm2),
  708. };