summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Pronin <apronin@chromium.org>2016-10-31 19:39:44 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-11-09 18:39:47 -0800
commit055788beb88972630d9ded866554f23b1f8a3c1a (patch)
treee4f8c15c34ceddb756e87aa64feb918b28b88a36
parentadfafba793684ed92965dfbd86b3fb3463975d8c (diff)
downloadvboot-055788beb88972630d9ded866554f23b1f8a3c1a.tar.gz
tpm2_lite: implement TlclDefineSpace
Implement TlclDefineSpace, which sends a TPM2_NV_DefineSpace command to define the attributes of an NV Index and cause the TPM to reserve space to hold the data associated with the NV Index (TPM2 Spec, Part 2, Section 31.3.1). Also, update TlclWrite and TlclWriteLock calls to use the platform authorization only for NV Indexes in TPM and Platform ranges, and use empty password authorization otherwise. This allows (1) working with the Off-Disk Early-Access Key Storage used by mount-encrypted through Tlcl API; and (2) testing Tlcl NV define/write/write-lock operations with platform hierarchy disabled. BUG=chrome-os-partner:55210 BUG=chrome-os-partner:59361 BRANCH=none TEST=After clearing the TPM owner run "tpmc def 0x800001 0x3 0x0" to create a TPM index of size 3, which can be read and written to with empty password. Verify that "tpmc write 0x800001 12 34 56" succeeds and "tpmc read 0x800001 0x3" prints "12 34 56" as NVRAM space contents. Change-Id: I185cf8380ef1579d0e9e4d8cead5a30ceda3ead9 Reviewed-on: https://chromium-review.googlesource.com/405792 Commit-Ready: Andrey Pronin <apronin@chromium.org> Tested-by: Andrey Pronin <apronin@chromium.org> Reviewed-by: Vadim Bendebury <vbendeb@google.com>
-rw-r--r--firmware/include/tpm2_tss_constants.h50
-rw-r--r--firmware/lib/tpm2_lite/marshaling.c151
-rw-r--r--firmware/lib/tpm2_lite/tlcl.c22
3 files changed, 209 insertions, 14 deletions
diff --git a/firmware/include/tpm2_tss_constants.h b/firmware/include/tpm2_tss_constants.h
index 7b1ab7b6..f24c7694 100644
--- a/firmware/include/tpm2_tss_constants.h
+++ b/firmware/include/tpm2_tss_constants.h
@@ -19,6 +19,7 @@
/* TPM2 command codes. */
#define TPM2_Hierarchy_Control ((TPM_CC)0x00000121)
#define TPM2_Clear ((TPM_CC)0x00000126)
+#define TPM2_NV_DefineSpace ((TPM_CC)0x0000012A)
#define TPM2_NV_Write ((TPM_CC)0x00000137)
#define TPM2_NV_WriteLock ((TPM_CC)0x00000138)
#define TPM2_SelfTest ((TPM_CC)0x00000143)
@@ -40,6 +41,7 @@
#define HR_SHIFT 24
#define TPM_HT_NV_INDEX 0x01
#define HR_NV_INDEX (TPM_HT_NV_INDEX << HR_SHIFT)
+#define TPM_RH_OWNER 0x40000001
#define TPM_RH_PLATFORM 0x4000000C
#define TPM_RS_PW 0x40000009
@@ -59,6 +61,36 @@
#define TPM_SU_CLEAR ((TPM_SU)0x0000)
#define TPM_SU_STATE ((TPM_SU)0x0001)
+/* TPM algorithm IDs. */
+#define TPM_ALG_SHA1 ((TPM_ALG_ID)0x0004)
+#define TPM_ALG_SHA256 ((TPM_ALG_ID)0x000B)
+#define TPM_ALG_NULL ((TPM_ALG_ID)0x0010)
+
+/* NV index attributes. */
+#define TPMA_NV_PPWRITE ((TPMA_NV)(1UL << 0))
+#define TPMA_NV_OWNERWRITE ((TPMA_NV)(1UL << 1))
+#define TPMA_NV_AUTHWRITE ((TPMA_NV)(1UL << 2))
+#define TPMA_NV_POLICYWRITE ((TPMA_NV)(1UL << 3))
+#define TPMA_NV_MASK_WRITE (TPMA_NV_PPWRITE | TPMA_NV_OWNERWRITE |\
+ TPMA_NV_AUTHWRITE | TPMA_NV_POLICYWRITE)
+#define TPMA_NV_PPREAD ((TPMA_NV)(1UL << 16))
+#define TPMA_NV_OWNERREAD ((TPMA_NV)(1UL << 17))
+#define TPMA_NV_AUTHREAD ((TPMA_NV)(1UL << 18))
+#define TPMA_NV_POLICYREAD ((TPMA_NV)(1UL << 19))
+#define TPMA_NV_MASK_READ (TPMA_NV_PPREAD | TPMA_NV_OWNERREAD |\
+ TPMA_NV_AUTHREAD | TPMA_NV_POLICYREAD)
+#define TPMA_NV_PLATFORMCREATE ((TPMA_NV)(1UL << 30))
+
+/* Starting indexes of NV index ranges, as defined in "Registry of reserved
+ * TPM 2.0 handles and localities".
+ */
+#define TPMI_RH_NV_INDEX_TPM_START ((TPMI_RH_NV_INDEX)0x01000000)
+#define TPMI_RH_NV_INDEX_PLATFORM_START ((TPMI_RH_NV_INDEX)0x01400000)
+#define TPMI_RH_NV_INDEX_OWNER_START ((TPMI_RH_NV_INDEX)0x01800000)
+#define TPMI_RH_NV_INDEX_TCG_OEM_START ((TPMI_RH_NV_INDEX)0x01C00000)
+#define TPMI_RH_NV_INDEX_TCG_WG_START ((TPMI_RH_NV_INDEX)0x01C40000)
+#define TPMI_RH_NV_INDEX_RESERVED_START ((TPMI_RH_NV_INDEX)0x01C90000)
+
typedef uint8_t TPMI_YES_NO;
typedef uint32_t TPM_CC;
typedef uint32_t TPM_HANDLE;
@@ -67,11 +99,14 @@ typedef TPM_HANDLE TPMI_RH_ENABLES;
typedef uint32_t TPM_CAP;
typedef uint32_t TPM_PT;
typedef uint16_t TPM_SU;
+typedef uint16_t TPM_ALG_ID;
+typedef TPM_ALG_ID TPMI_ALG_HASH;
+typedef uint32_t TPMA_NV;
typedef struct {
uint16_t size;
uint8_t *buffer;
-} TPM2B;
+} TPM2B, TPM2B_DIGEST, TPM2B_AUTH;
typedef union {
struct {
@@ -100,6 +135,19 @@ typedef struct {
TPMU_CAPABILITIES data;
} TPMS_CAPABILITY_DATA;
+typedef struct {
+ TPMI_RH_NV_INDEX nvIndex;
+ TPMI_ALG_HASH nameAlg;
+ TPMA_NV attributes;
+ TPM2B authPolicy;
+ uint16_t dataSize;
+} TPMS_NV_PUBLIC;
+
+struct tpm2_nv_define_space_cmd {
+ TPM2B auth;
+ TPMS_NV_PUBLIC publicInfo;
+};
+
struct tpm2_nv_read_cmd {
TPMI_RH_NV_INDEX nvIndex;
uint16_t size;
diff --git a/firmware/lib/tpm2_lite/marshaling.c b/firmware/lib/tpm2_lite/marshaling.c
index a51c1f66..57a05530 100644
--- a/firmware/lib/tpm2_lite/marshaling.c
+++ b/firmware/lib/tpm2_lite/marshaling.c
@@ -266,19 +266,67 @@ static void marshal_u32(void **buffer, uint32_t value, int *buffer_space)
#define unmarshal_TPM_CC(a, b) unmarshal_u32(a, b)
#define marshal_TPM_HANDLE(a, b, c) marshal_u32(a, b, c)
#define marshal_TPM_SU(a, b, c) marshal_u16(a, b, c)
+#define marshal_ALG_ID(a, b, c) marshal_u16(a, b, c)
+
+/*
+ * For TPM2B* structures the size field (16 or 32 bits) goes before the data.
+ * When marshaling, we first reserve the space for the size field, then
+ * marshal the data, then fill the reserved size field with the actual size
+ * of the marshaled data.
+ */
+typedef struct {
+ int size;
+ void *location;
+} tpm2_marshal_size_field;
+
+static void marshal_reserve_size_field(void **buffer,
+ tpm2_marshal_size_field *field,
+ int field_size,
+ int *buffer_space)
+{
+ if (field_size != sizeof(uint32_t) && field_size != sizeof(uint16_t)) {
+ VBDEBUG(("%s:%d:Unsupported size field size: %d\n",
+ __FILE__, __LINE__, field_size));
+ *buffer_space = -1;
+ return;
+ }
+ if (*buffer_space < field_size) {
+ *buffer_space = -1;
+ return;
+ }
+ field->size = field_size;
+ field->location = *buffer;
+ *buffer_space -= field_size;
+ *buffer = (void *)(((uintptr_t) *buffer) + field_size);
+}
+
+static void marshal_fill_size_field(void **buffer,
+ tpm2_marshal_size_field *field,
+ int include_size_field,
+ int *buffer_space)
+{
+ uintptr_t size = (uintptr_t) *buffer - (uintptr_t) field->location;
+
+ if (*buffer_space < 0)
+ return; /* The structure did not fit. */
+
+ if (!include_size_field)
+ size -= field->size;
+ if (field->size == sizeof(uint32_t))
+ marshal_u32(&field->location, size, &field->size);
+ else /* if (field->size == sizeof(uint16_t)) */
+ marshal_u16(&field->location, size, &field->size);
+}
static void marshal_session_header(void **buffer,
struct tpm2_session_header *session_header,
int *buffer_space)
{
- int base_size;
- void *size_location = *buffer;
+ tpm2_marshal_size_field size_field;
/* Skip room for the session header size. */
- *buffer_space -= sizeof(uint32_t);
- *buffer = (void *)(((uintptr_t) *buffer) + sizeof(uint32_t));
-
- base_size = *buffer_space;
+ marshal_reserve_size_field(buffer, &size_field,
+ sizeof(uint32_t), buffer_space);
marshal_u32(buffer, session_header->session_handle, buffer_space);
marshal_u16(buffer, session_header->nonce_size, buffer_space);
@@ -289,11 +337,8 @@ static void marshal_session_header(void **buffer,
marshal_blob(buffer, session_header->auth,
session_header->auth_size, buffer_space);
- if (*buffer_space < 0)
- return; /* The structure did not fit. */
-
/* Paste in the session size. */
- marshal_u32(&size_location, base_size - *buffer_space, &base_size);
+ marshal_fill_size_field(buffer, &size_field, 0, buffer_space);
}
static void marshal_TPM2B(void **buffer,
@@ -312,13 +357,88 @@ static void marshal_TPM2B(void **buffer,
*buffer_space -= data->size;
}
+static void marshal_TPMS_NV_PUBLIC(void **buffer,
+ TPMS_NV_PUBLIC *data,
+ int *buffer_space)
+{
+ tpm2_marshal_size_field size_field;
+
+ /* Skip room for the size. */
+ marshal_reserve_size_field(buffer, &size_field,
+ sizeof(uint16_t), buffer_space);
+
+ marshal_TPM_HANDLE(buffer, data->nvIndex, buffer_space);
+ marshal_ALG_ID(buffer, data->nameAlg, buffer_space);
+ marshal_u32(buffer, data->attributes, buffer_space);
+ marshal_TPM2B(buffer, &data->authPolicy, buffer_space);
+ marshal_u16(buffer, data->dataSize, buffer_space);
+
+ /* Paste in the structure size. */
+ marshal_fill_size_field(buffer, &size_field, 0, buffer_space);
+}
+
+static void marshal_nv_define_space(void **buffer,
+ struct tpm2_nv_define_space_cmd
+ *command_body,
+ int *buffer_space)
+{
+ struct tpm2_session_header session_header;
+
+ /* Use platform authorization if PLATFORMCREATE is set, and owner
+ * authorization otherwise (per TPM2 Spec. Part 2. Section 31.3.1).
+ * Owner authorization with empty password will work only until
+ * ownership is taken. Platform authorization will work only until
+ * platform hierarchy is disabled (i.e. in firmware or in recovery
+ * mode).
+ */
+ if (command_body->publicInfo.attributes & TPMA_NV_PLATFORMCREATE)
+ marshal_TPM_HANDLE(buffer, TPM_RH_PLATFORM, buffer_space);
+ else
+ marshal_TPM_HANDLE(buffer, TPM_RH_OWNER, buffer_space);
+
+ memset(&session_header, 0, sizeof(session_header));
+ session_header.session_handle = TPM_RS_PW;
+ marshal_session_header(buffer, &session_header, buffer_space);
+ tpm_tag = TPM_ST_SESSIONS;
+
+ marshal_TPM2B(buffer, &command_body->auth, buffer_space);
+ marshal_TPMS_NV_PUBLIC(buffer, &command_body->publicInfo, buffer_space);
+}
+
+/* Determine which authorization should be used when writing or write-locking
+ * an NV index.
+ *
+ * Use a simplified approach:
+ * 1) Use platform auth for indexes defined by TPM and Platform, as
+ * specified in "Registry of reserved TPM 2.0 handles and localities".
+ * That will only work for indexes with PPWRITE, and until the platform
+ * hierarchy is disabled.
+ * 2) Use empty password auth for other indexes.
+ * That will only work for indexes with AUTHWRITE and empty auth value.
+ *
+ * A more honest approach would require the caller to specify the
+ * authorization, or would check the NV index attributes.
+ * But that's not needed now, as all indexes defined by firmware are
+ * in the TPM range and have PPWRITE. The indexes defined by the
+ * OS are in the Owner range and have either OWNERWRITE or AUTHWRITE,
+ * but we don't ever use Tlcl to write to OWNERWRITE indexes.
+ */
+static TPM_HANDLE get_nv_index_write_auth(TPMI_RH_NV_INDEX nvIndex)
+{
+ return nvIndex >= TPMI_RH_NV_INDEX_OWNER_START ?
+ nvIndex :
+ TPM_RH_PLATFORM;
+}
+
static void marshal_nv_write(void **buffer,
struct tpm2_nv_write_cmd *command_body,
int *buffer_space)
{
struct tpm2_session_header session_header;
- marshal_TPM_HANDLE(buffer, TPM_RH_PLATFORM, buffer_space);
+ marshal_TPM_HANDLE(buffer,
+ get_nv_index_write_auth(command_body->nvIndex),
+ buffer_space);
marshal_TPM_HANDLE(buffer, command_body->nvIndex, buffer_space);
memset(&session_header, 0, sizeof(session_header));
session_header.session_handle = TPM_RS_PW;
@@ -370,7 +490,9 @@ static void marshal_nv_write_lock(void **buffer,
struct tpm2_session_header session_header;
tpm_tag = TPM_ST_SESSIONS;
- marshal_TPM_HANDLE(buffer, TPM_RH_PLATFORM, buffer_space);
+ marshal_TPM_HANDLE(buffer,
+ get_nv_index_write_auth(command_body->nvIndex),
+ buffer_space);
marshal_TPM_HANDLE(buffer, command_body->nvIndex, buffer_space);
memset(&session_header, 0, sizeof(session_header));
session_header.session_handle = TPM_RS_PW;
@@ -458,6 +580,10 @@ int tpm_marshal_command(TPM_CC command, void *tpm_command_body,
switch (command) {
+ case TPM2_NV_DefineSpace:
+ marshal_nv_define_space(&cmd_body, tpm_command_body, &body_size);
+ break;
+
case TPM2_NV_Read:
marshal_nv_read(&cmd_body, tpm_command_body, &body_size);
break;
@@ -558,6 +684,7 @@ struct tpm2_response *tpm_unmarshal_response(TPM_CC command,
case TPM2_SelfTest:
case TPM2_Startup:
case TPM2_Shutdown:
+ case TPM2_NV_DefineSpace:
/* Session data included in response can be safely ignored. */
cr_size = 0;
break;
diff --git a/firmware/lib/tpm2_lite/tlcl.c b/firmware/lib/tpm2_lite/tlcl.c
index 96900b07..3b4ba480 100644
--- a/firmware/lib/tpm2_lite/tlcl.c
+++ b/firmware/lib/tpm2_lite/tlcl.c
@@ -168,7 +168,27 @@ uint32_t TlclContinueSelfTest(void)
uint32_t TlclDefineSpace(uint32_t index, uint32_t perm, uint32_t size)
{
- VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
+ struct tpm2_response *response;
+ struct tpm2_nv_define_space_cmd define_space;
+
+ /* For backwards-compatibility, if no READ or WRITE permissions are set,
+ * assume readable/writeable with empty auth value.
+ */
+ if (!(perm & TPMA_NV_MASK_WRITE))
+ perm |= TPMA_NV_AUTHWRITE;
+ if (!(perm & TPMA_NV_MASK_READ))
+ perm |= TPMA_NV_AUTHREAD;
+
+ memset(&define_space, 0, sizeof(define_space));
+ define_space.publicInfo.nvIndex = HR_NV_INDEX + index;
+ define_space.publicInfo.dataSize = size;
+ define_space.publicInfo.attributes = perm;
+ define_space.publicInfo.nameAlg = TPM_ALG_SHA256;
+
+ response = tpm_process_command(TPM2_NV_DefineSpace, &define_space);
+ if (!response || response->hdr.tpm_code)
+ return TPM_E_IOERROR;
+
return TPM_SUCCESS;
}