]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
sandbox: tpm: Support storing device state in tpm2
authorSimon Glass <sjg@chromium.org>
Sun, 18 Jul 2021 20:18:04 +0000 (14:18 -0600)
committerSimon Glass <sjg@chromium.org>
Sun, 1 Aug 2021 15:05:24 +0000 (09:05 -0600)
At present the tpm2 emulator does not support storing the device state.
Add this so we can handle the normal vboot flow through the sandbox
executables (VPL->SPL etc.) with the TPM contents staying in place.

Note: sandbox has not yet been converted to use livetree for the state
information, since livetree does not yet support writing to the tree.

Signed-off-by: Simon Glass <sjg@chromium.org>
drivers/tpm/tpm2_tis_sandbox.c

index 1d38a79a867db82b366abc52efbb07829c3224c4..ed9c9a0bc9f7a48c00b5930a99eaf3e015f3ec87 100644 (file)
@@ -79,6 +79,145 @@ struct sandbox_tpm2 {
 
 static struct sandbox_tpm2 s_state, *g_state;
 
+/**
+ * sandbox_tpm2_read_state() - read the sandbox EC state from the state file
+ *
+ * If data is available, then blob and node will provide access to it. If
+ * not this function sets up an empty TPM.
+ *
+ * @blob: Pointer to device tree blob, or NULL if no data to read
+ * @node: Node offset to read from
+ */
+static int sandbox_tpm2_read_state(const void *blob, int node)
+{
+       struct sandbox_tpm2 *state = &s_state;
+       char prop_name[20];
+       const char *prop;
+       int len;
+       int i;
+
+       if (!blob)
+               return 0;
+       state->tests_done = fdtdec_get_int(blob, node, "tests-done", 0);
+
+       for (i = 0; i < TPM2_HIERARCHY_NB; i++) {
+               snprintf(prop_name, sizeof(prop_name), "pw%d", i);
+
+               prop = fdt_getprop(blob, node, prop_name, &len);
+               if (len > TPM2_DIGEST_LEN)
+                       return log_msg_ret("pw", -E2BIG);
+               if (prop) {
+                       memcpy(state->pw[i], prop, len);
+                       state->pw_sz[i] = len;
+               }
+       }
+
+       for (i = 0; i < TPM2_PROPERTY_NB; i++) {
+               snprintf(prop_name, sizeof(prop_name), "properties%d", i);
+               state->properties[i] = fdtdec_get_uint(blob, node, prop_name,
+                                                      0);
+       }
+
+       for (i = 0; i < SANDBOX_TPM_PCR_NB; i++) {
+               int subnode;
+
+               snprintf(prop_name, sizeof(prop_name), "pcr%d", i);
+               subnode = fdt_subnode_offset(blob, node, prop_name);
+               if (subnode < 0)
+                       continue;
+               prop = fdt_getprop(blob, subnode, "value", &len);
+               if (len != TPM2_DIGEST_LEN)
+                       return log_msg_ret("pcr", -E2BIG);
+               memcpy(state->pcr[i], prop, TPM2_DIGEST_LEN);
+               state->pcr_extensions[i] = fdtdec_get_uint(blob, subnode,
+                                                          "extensions", 0);
+       }
+
+       for (i = 0; i < NV_SEQ_COUNT; i++) {
+               struct nvdata_state *nvd = &state->nvdata[i];
+
+               sprintf(prop_name, "nvdata%d", i);
+               prop = fdt_getprop(blob, node, prop_name, &len);
+               if (len > NV_DATA_SIZE)
+                       return log_msg_ret("nvd", -E2BIG);
+               if (prop) {
+                       memcpy(nvd->data, prop, len);
+                       nvd->length = len;
+                       nvd->present = true;
+               }
+       }
+       s_state.valid = true;
+
+       return 0;
+}
+
+/**
+ * sandbox_tpm2_write_state() - Write out our state to the state file
+ *
+ * The caller will ensure that there is a node ready for the state. The node
+ * may already contain the old state, in which case it is overridden.
+ *
+ * @blob: Device tree blob holding state
+ * @node: Node to write our state into
+ */
+static int sandbox_tpm2_write_state(void *blob, int node)
+{
+       const struct sandbox_tpm2 *state = g_state;
+       char prop_name[20];
+       int i;
+
+       if (!state)
+               return 0;
+
+       /*
+        * We are guaranteed enough space to write basic properties. This is
+        * SANDBOX_STATE_MIN_SPACE.
+        *
+        * We could use fdt_add_subnode() to put each set of data in its
+        * own node - perhaps useful if we add access information to each.
+        */
+       fdt_setprop_u32(blob, node, "tests-done", state->tests_done);
+
+       for (i = 0; i < TPM2_HIERARCHY_NB; i++) {
+               if (state->pw_sz[i]) {
+                       snprintf(prop_name, sizeof(prop_name), "pw%d", i);
+                       fdt_setprop(blob, node, prop_name, state->pw[i],
+                                   state->pw_sz[i]);
+               }
+       }
+
+       for (i = 0; i < TPM2_PROPERTY_NB; i++) {
+               snprintf(prop_name, sizeof(prop_name), "properties%d", i);
+               fdt_setprop_u32(blob, node, prop_name, state->properties[i]);
+       }
+
+       for (i = 0; i < SANDBOX_TPM_PCR_NB; i++) {
+               int subnode;
+
+               snprintf(prop_name, sizeof(prop_name), "pcr%d", i);
+               subnode = fdt_add_subnode(blob, node, prop_name);
+               fdt_setprop(blob, subnode, "value", state->pcr[i],
+                           TPM2_DIGEST_LEN);
+               fdt_setprop_u32(blob, subnode, "extensions",
+                               state->pcr_extensions[i]);
+       }
+
+       for (i = 0; i < NV_SEQ_COUNT; i++) {
+               const struct nvdata_state *nvd = &state->nvdata[i];
+
+               if (nvd->present) {
+                       snprintf(prop_name, sizeof(prop_name), "nvdata%d", i);
+                       fdt_setprop(blob, node, prop_name, nvd->data,
+                                   nvd->length);
+               }
+       }
+
+       return 0;
+}
+
+SANDBOX_STATE_IO(sandbox_tpm2, "sandbox,tpm2", sandbox_tpm2_read_state,
+                sandbox_tpm2_write_state);
+
 /*
  * Check the tag validity depending on the command (authentication required or
  * not). If authentication is required, check it is valid. Update the auth