Attention is currently required from: Michał Żygowski.
Hello Michał Żygowski,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/coreboot/+/82037?usp=email
to review the following change.
Change subject: security/tpm: Add TPM2 NV_ReadPublic command support ......................................................................
security/tpm: Add TPM2 NV_ReadPublic command support
Change-Id: I3c032b4f88d445372beebbe354f458a061a63bb9 Signed-off-by: Michał Żygowski michal.zygowski@3mdeb.com --- M src/security/tpm/tss.h M src/security/tpm/tss/tcg-2.0/tss.c M src/security/tpm/tss/tcg-2.0/tss_marshaling.c M src/security/tpm/tss/tcg-2.0/tss_structures.h 4 files changed, 173 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/37/82037/1
diff --git a/src/security/tpm/tss.h b/src/security/tpm/tss.h index c9aec08..8833402 100644 --- a/src/security/tpm/tss.h +++ b/src/security/tpm/tss.h @@ -27,6 +27,39 @@ * * Other operations are defined in tss1.h and tss2.h. */ +uint32_t tlcl_define_space(uint32_t space_index, size_t space_size, + const TPMA_NV nv_attributes, + const uint8_t *nv_policy, size_t nv_policy_size); + +/** + * Read the public data of NV index. [index] is the index for the space, + * [nvrp_resp] is hte NV index output data. The TPM error code is returned. + */ +uint32_t tlcl_nv_read_public(uint32_t space_index, + struct nv_read_public_response *nvrp_resp); +/* + * Issue TPM2_GetCapability command + */ +uint32_t tlcl_get_capability(TPM_CAP capability, uint32_t property, + uint32_t property_count, + TPMS_CAPABILITY_DATA *capability_data); + +/* Issue TPM2_NV_SetBits command */ +uint32_t tlcl_set_bits(uint32_t index, uint64_t bits); + +/* + * Makes tpm_process_command available for on top implementations of + * custom tpm standards like cr50 + */ +void *tpm_process_command(TPM_CC command, void *command_body); + +/* Return digest size of hash algorithm */ +uint16_t tlcl_get_hash_size_from_algo(TPMI_ALG_HASH hash_algo); + +#endif + +/*****************************************************************************/ +/* Generic Functions implemented in tlcl.c */
/** * Call this first. Returns 0 if success, nonzero if error. diff --git a/src/security/tpm/tss/tcg-2.0/tss.c b/src/security/tpm/tss/tcg-2.0/tss.c index 282845e..576ad53 100644 --- a/src/security/tpm/tss/tcg-2.0/tss.c +++ b/src/security/tpm/tss/tcg-2.0/tss.c @@ -391,7 +391,36 @@ } }
-uint16_t tlcl2_get_hash_size_from_algo(TPMI_ALG_HASH hash_algo) +uint32_t tlcl_nv_read_public(uint32_t space_index, + struct nv_read_public_response *nvrp_resp) +{ + struct tpm2_nv_read_public_cmd nvrp_cmd; + struct tpm2_response *response; + + /* Prepare the define space command structure. */ + memset(&nvrp_cmd, 0, sizeof(nvrp_cmd)); + + nvrp_cmd.nvIndex = HR_NV_INDEX + space_index; + + response = tpm_process_command(TPM2_NV_ReadPublic, &nvrp_cmd); + printk(BIOS_INFO, "%s: response is %x\n", __func__, + response ? response->hdr.tpm_code : -1); + + if (!response) + return TPM_E_NO_DEVICE; + + /* Map TPM2 return codes into common vboot representation. */ + switch (response->hdr.tpm_code) { + case TPM2_RC_SUCCESS: + memcpy(nvrp_resp, &response->nvrp, sizeof(*nvrp_resp)); + return TPM_SUCCESS; + default: + return TPM_E_INTERNAL_INCONSISTENCY; + } +} + +uint16_t tlcl_get_hash_size_from_algo(TPMI_ALG_HASH hash_algo) + { uint16_t value;
diff --git a/src/security/tpm/tss/tcg-2.0/tss_marshaling.c b/src/security/tpm/tss/tcg-2.0/tss_marshaling.c index 3039a8b..5bf293e 100644 --- a/src/security/tpm/tss/tcg-2.0/tss_marshaling.c +++ b/src/security/tpm/tss/tcg-2.0/tss_marshaling.c @@ -197,6 +197,13 @@ return rc; }
+static int marshal_nv_read_public(struct obuf *ob, + const struct tpm2_nv_read_public_cmd *nvrp_in) +{ + return obuf_write_be32(ob, nvrp_in->nvIndex); +} + + static int marshal_nv_setbits(struct obuf *ob, const struct tpm2_nv_setbits_cmd *command_body) { @@ -401,6 +408,10 @@ rc |= marshal_nv_define_space(ob, tpm_command_body); break;
+ case TPM2_NV_ReadPublic: + rc |= marshal_nv_read_public(ob, tpm_command_body); + break; + case TPM2_NV_SetBits: rc |= marshal_nv_setbits(ob, tpm_command_body); break; @@ -563,6 +574,80 @@ return 0; }
+static int unmarshal_TPM2B_NV_PUBLIC(struct ibuf *ib, TPM2B_NV_PUBLIC *nv_public) +{ + int rc = 0; + + rc |= ibuf_read_be16(ib, &nv_public->t.size); + rc |= ibuf_read_be32(ib, &nv_public->t.nvPublic.nvIndex); + rc |= ibuf_read_be16(ib, &nv_public->t.nvPublic.nameAlg); + rc |= ibuf_read_be32(ib, (uint32_t *)&nv_public->t.nvPublic.attributes); + rc |= ibuf_read_be16(ib, &nv_public->t.nvPublic.authPolicy.t.size); + + nv_public->t.nvPublic.authPolicy.t.buffer = + ibuf_oob_drain(ib, nv_public->t.nvPublic.authPolicy.t.size); + + rc |= ibuf_read_be16(ib, &nv_public->t.nvPublic.dataSize); + + return rc; +} + +static int unmarshal_TPM2B_NAME(struct ibuf *ib, TPM2B_NAME *name) +{ + int rc = 0; + size_t digest_size; + + rc |= ibuf_read_be16(ib, &name->size); + + if (name->size == 0) + return rc; + + /* If size is 4 it is a handle, otherwise it should be a digest */ + if (name->size == 4) { + rc |= ibuf_read_be32(ib, &name->name.handle); + return rc; + } + + rc |= ibuf_read_be16(ib, &name->name.digest.hashAlg); + + switch(name->name.digest.hashAlg) { + case TPM_ALG_SHA1: + digest_size = SHA1_DIGEST_SIZE; + break; + case TPM_ALG_SHA256: + digest_size = SHA256_DIGEST_SIZE; + break; + case TPM_ALG_SHA384: + digest_size = SHA384_DIGEST_SIZE; + break; + case TPM_ALG_SHA512: + digest_size = SHA512_DIGEST_SIZE; + break; + case TPM_ALG_SM3_256: + digest_size = SM3_256_DIGEST_SIZE; + break; + default: + printk(BIOS_WARNING, "%s: Unknown hash algorithm (%02x)\n", + __func__, name->name.digest.hashAlg); + return 1; + } + + memcpy(&name->name.digest.digest, ibuf_oob_drain(ib, digest_size), digest_size); + + return rc; +} + + +static int unmarshal_nv_read_public(struct ibuf *ib, struct nv_read_public_response *nvrp) +{ + int rc = 0; + + rc |= unmarshal_TPM2B_NV_PUBLIC(ib, &nvrp->nvPublic); + rc |= unmarshal_TPM2B_NAME(ib, &nvrp->nvName); + + return rc; +} + static int unmarshal_vendor_command(struct ibuf *ib, struct vendor_command_response *vcr) { @@ -635,6 +720,10 @@ rc |= unmarshal_nv_read(ib, &tpm2_static_resp.nvr); break;
+ case TPM2_NV_ReadPublic: + rc |= unmarshal_nv_read_public(ib, &tpm2_static_resp.nvrp); + break; + case TPM2_Hierarchy_Control: case TPM2_Clear: case TPM2_ClearControl: diff --git a/src/security/tpm/tss/tcg-2.0/tss_structures.h b/src/security/tpm/tss/tcg-2.0/tss_structures.h index f2682b1..5893ffd 100644 --- a/src/security/tpm/tss/tcg-2.0/tss_structures.h +++ b/src/security/tpm/tss/tcg-2.0/tss_structures.h @@ -88,6 +88,7 @@ #define TPM2_Startup ((TPM_CC)0x00000144) #define TPM2_Shutdown ((TPM_CC)0x00000145) #define TPM2_NV_Read ((TPM_CC)0x0000014E) +#define TPM2_NV_ReadPublic ((TPM_CC)0x00000169) #define TPM2_GetCapability ((TPM_CC)0x0000017A) #define TPM2_PCR_Extend ((TPM_CC)0x00000182) /* TPM2 specifies vendor commands need to have this bit set. Vendor command @@ -345,6 +346,21 @@ TPM2B_MAX_NV_BUFFER buffer; };
+typedef union { + TPMT_HA digest; + TPM_HANDLE handle; +} TPMU_NAME; + +typedef struct { + uint16_t size; + TPMU_NAME name; +} TPM2B_NAME; + +struct nv_read_public_response { + TPM2B_NV_PUBLIC nvPublic; + TPM2B_NAME nvName; +}; + struct vendor_command_response { uint16_t vc_subcommand; union { @@ -391,6 +407,7 @@ union { struct get_cap_response gc; struct nv_read_response nvr; + struct nv_read_public_response nvrp; struct tpm2_session_header def_space; struct vendor_command_response vcr; }; @@ -401,6 +418,10 @@ TPMS_NV_PUBLIC publicInfo; };
+struct tpm2_nv_read_public_cmd { + TPMI_RH_NV_INDEX nvIndex; +}; + struct tpm2_nv_write_cmd { TPMI_RH_NV_INDEX nvIndex; TPM2B_MAX_NV_BUFFER data;