From patchwork Tue Oct 27 15:44:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: GlovePuppet X-Patchwork-Id: 1388939 X-Patchwork-Delegate: wd@denx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CLMG83j6rz9sV0 for ; Wed, 28 Oct 2020 06:29:20 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 6A77B8249E; Tue, 27 Oct 2020 20:28:56 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by phobos.denx.de (Postfix, from userid 109) id A122B82483; Tue, 27 Oct 2020 16:45:10 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: * X-Spam-Status: No, score=1.7 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, FORGED_GMAIL_RCVD,FREEMAIL_FROM,NML_ADSP_CUSTOM_MED,SPF_HELO_PASS, SPOOFED_FREEMAIL,URIBL_BLOCKED autolearn=no autolearn_force=no version=3.4.2 Received: from n7.nabble.com (n7.nabble.com [162.253.133.57]) by phobos.denx.de (Postfix) with ESMTP id C8649801D8 for ; Tue, 27 Oct 2020 16:45:06 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=fail smtp.mailfrom=touched.by.his.noodley.appendage@gmail.com Received: from n7.nabble.com (localhost [127.0.0.1]) by n7.nabble.com (Postfix) with ESMTP id F3DC41B3B680C for ; Tue, 27 Oct 2020 08:44:55 -0700 (MST) Date: Tue, 27 Oct 2020 08:44:55 -0700 (MST) From: GlovePuppet To: u-boot@lists.denx.de Message-ID: <1603813495996-0.post@n7.nabble.com> Subject: [PATCH 2/2] Add TPM2 Unseal command and supporting functions MIME-Version: 1.0 X-Mailman-Approved-At: Tue, 27 Oct 2020 20:28:53 +0100 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean Unseals a loaded object, identified by handle, and returns data at a memory location or in an environment variable Caveats -The PolicyPCR command only supports one PCR -The auth request code only supports one handle Signed-off-by: GlovePuppet --- cmd/tpm-v2.c | 60 +++++++ drivers/tpm/Kconfig | 7 + include/tpm-v2.h | 41 +++++ lib/tpm-v2.c | 413 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 521 insertions(+) + + rc = tpm2_unseal(dev, nonce, &auth_session, &object, unsealed_data, unsealed_data_sz); + if (rc) + return rc; + + rc = tpm2_flushcontext(dev, &auth_session); + if (rc) + return rc; + + return 0; +} + +#endif /* CONFIG_TPM2_ENHANCEDAUTH_SESSIONS */ diff --git a/cmd/tpm-v2.c b/cmd/tpm-v2.c index e6742656f5..a94fcfabf0 100644 --- a/cmd/tpm-v2.c +++ b/cmd/tpm-v2.c @@ -354,6 +354,56 @@ static int do_tpm_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag, key, key_sz)); } +#if IS_ENABLED(CONFIG_TPM2_ENHANCEDAUTH_SESSIONS) + +static int do_tpm_unseal(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + u32 rc; + u32 handle; + u32 index; + struct tpm_chip_priv *priv; + u8 *data; + u8 buffer[129]; + u16 data_sz; + + if (argc != 4) + return CMD_RET_USAGE; + + if (get_tpm(&dev)) + return CMD_RET_FAILURE; + + priv = dev_get_uclass_priv(dev); + if (!priv) + return CMD_RET_FAILURE; + + handle = simple_strtoul(argv[1], NULL, 16); + + index = simple_strtoul(argv[2], NULL, 0); + if (index >= priv->pcr_count) + return CMD_RET_USAGE; + + if (*argv[3] == '*') { + /* Skip the '*' */ + data = map_sysmem(simple_strtoul(argv[3] + 1, NULL, 16), 0); + } else { + data = buffer; + } + + rc = tpm2_do_unseal(dev, handle, index, priv->pcr_select_min, data, &data_sz); + + if (*argv[3] == '*') { + unmap_sysmem(data); + } else { + buffer[data_sz] = '\0'; + env_set(argv[3], (char *)buffer); + } + + return report_return_code(rc); +} +#endif /* CONFIG_TPM2_ENHANCEDAUTH_SESSIONS */ + static struct cmd_tbl tpm2_commands[] = { U_BOOT_CMD_MKENT(device, 0, 1, do_tpm_device, "", ""), U_BOOT_CMD_MKENT(info, 0, 1, do_tpm_info, "", ""), @@ -371,6 +421,9 @@ static struct cmd_tbl tpm2_commands[] = { do_tpm_pcr_setauthpolicy, "", ""), U_BOOT_CMD_MKENT(pcr_setauthvalue, 0, 1, do_tpm_pcr_setauthvalue, "", ""), +#if IS_ENABLED(CONFIG_TPM2_ENHANCEDAUTH_SESSIONS) + U_BOOT_CMD_MKENT(unseal, 0, 1, do_tpm_unseal, "", ""), +#endif /* CONFIG_TPM2_ENHANCEDAUTH_SESSIONS */ }; struct cmd_tbl *get_tpm2_commands(unsigned int *size) @@ -442,4 +495,11 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command", " : index of the PCR\n" " : secret to protect the access of PCR #\n" " : optional password of the PLATFORM hierarchy\n" +#if IS_ENABLED(CONFIG_TPM2_ENHANCEDAUTH_SESSIONS) +"unseal \n" +" Create a pcr policy and unseal data from the TPM, [save to env var / *address]\n" +" : the handle of a loaded object\n" +" : index of the pcr\n" +" env var or *address to receive the unsealed data" +#endif /* CONFIG_TPM2_ENHANCEDAUTH_SESSIONS */ ); diff --git a/drivers/tpm/Kconfig b/drivers/tpm/Kconfig index 9eebab5cfd..0bdc76f181 100644 --- a/drivers/tpm/Kconfig +++ b/drivers/tpm/Kconfig @@ -161,6 +161,13 @@ config TPM2_FTPM_TEE help This driver supports firmware TPM running in TEE. +config TPM2_ENHANCEDAUTH_SESSIONS + bool "Enable TPM enhanced authentication session support" + depends on TPM_V2 + help + Enable support for enhanced authorisation commands and the TPM Unseal + command. + endif # TPM_V2 endmenu diff --git a/include/tpm-v2.h b/include/tpm-v2.h index f6c045d354..ca9e11eb13 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -52,6 +52,7 @@ enum tpm2_startup_types { */ enum tpm2_handles { TPM2_RH_OWNER = 0x40000001, + TPM2_RH_NULL = 0x40000007, TPM2_RS_PW = 0x40000009, TPM2_RH_LOCKOUT = 0x4000000A, TPM2_RH_ENDORSEMENT = 0x4000000B, @@ -85,9 +86,14 @@ enum tpm2_command_codes { TPM2_CC_DAM_RESET = 0x0139, TPM2_CC_DAM_PARAMETERS = 0x013A, TPM2_CC_NV_READ = 0x014E, + TPM2_CC_UNSEAL = 0x015E, + TPM2_CC_FLUSH_CONTEXT = 0x0165, + TPM2_CC_READ_PUBLIC = 0x0173, + TPM2_CC_START_AUTH_SESSION = 0x0176, TPM2_CC_GET_CAPABILITY = 0x017A, TPM2_CC_GET_RANDOM = 0x017B, TPM2_CC_PCR_READ = 0x017E, + TPM2_CC_POLICY_PCR = 0x017F, TPM2_CC_PCR_EXTEND = 0x0182, TPM2_CC_PCR_SETAUTHVAL = 0x0183, }; @@ -194,6 +200,23 @@ enum { TPM_MAX_BUF_SIZE = 1260, }; +#if IS_ENABLED(CONFIG_TPM2_ENHANCEDAUTH_SESSIONS) + +enum { + TPM_SE_HMAC = 0, + TPM_SE_POLICY = 1, + TPM_SE_TRIAL = 3 +}; + +enum { + TPM2_REQUEST_HEADER_LENGTH = 10, + TPM2_RESPONSE_HEADER_LENGTH = 10, + TPM2_REQUEST_AUTH_LENGTH = 45, + TPM2_RESPONSE_AUTH_LENGTH = 69 +}; + +#endif /* CONFIG_TPM2_ENHANCEDAUTH_SESSIONS */ + /** * Issue a TPM2_Startup command. * @@ -352,4 +375,22 @@ u32 tpm2_pcr_setauthvalue(struct udevice *dev, const char *pw, */ u32 tpm2_get_random(struct udevice *dev, void *data, u32 count); +#ifdef CONFIG_TPM2_ENHANCEDAUTH_SESSIONS +/** + * Perform a TPM_Unseal command sequence. + * + * @dev TPM device + * @handle Handle of a loaded object to be unsealed + * @pcr_index Index of the PCR + * @idx_min_sz Minimum size in bytes of the pcrSelect array + * @unsealed_data Buffer to receive the unsealed data + * @unsealed_data_sz Length of the unsealed data + * + * @return code of the operation + */ +u32 tpm2_do_unseal(struct udevice *dev, u32 handle, + u32 pcr_index, unsigned int idx_min_sz, + u8 *unsealed_data, u16 *unsealed_data_sz); +#endif /* CONFIG_TPM2_ENHANCEDAUTH_SESSIONS */ + #endif /* __TPM_V2_H */ diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index a4c352e3ef..d4b749d7aa 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -9,8 +9,30 @@ #include #include #include +#include #include "tpm-utils.h" +#if IS_ENABLED(CONFIG_TPM2_ENHANCEDAUTH_SESSIONS) + +#ifndef CONFIG_SHA256 +#error "TPM2_ENHANCEDAUTH_SESSIONS require SHA256 to be configured, too" +#endif /* !CONFIG_SHA256 */ + +struct session_data { + int valid; + u32 handle; + u8 newernonce[TPM2_DIGEST_LEN]; + u8 oldernonce[TPM2_DIGEST_LEN]; +}; + +struct tpm2_object { + u32 handle; + u16 hashalg; + u8 name[TPM2_DIGEST_LEN]; +}; + +#endif /* CONFIG_TPM2_ENHANCEDAUTH_SESSIONS */ + u32 tpm2_startup(struct udevice *dev, enum tpm2_startup_types mode) { const u8 command_v2[12] = { @@ -466,3 +488,394 @@ u32 tpm2_get_random(struct udevice *dev, void *data, u32 count) return 0; } + +#if IS_ENABLED(CONFIG_TPM2_ENHANCEDAUTH_SESSIONS) + +static u32 tpm2_start_authsession(struct udevice *dev, u8 session_type, const u8 *nonce, + struct session_data *auth_session) +{ + u32 rc; + u16 tpm_nonce_sz; + size_t response_len = COMMAND_BUFFER_SIZE; + u8 response[COMMAND_BUFFER_SIZE]; + + u8 command_v2[COMMAND_BUFFER_SIZE] = { + tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */ + tpm_u32(0x1B + TPM2_DIGEST_LEN), /* Length - fixed length nonce*/ + tpm_u32(TPM2_CC_START_AUTH_SESSION), /* Command code */ + + /* TPMI_DH_OBJECT+ */ + tpm_u32(TPM2_RH_NULL), /* tmpKey */ + /* TPMI_DH_ENTITY+ */ + tpm_u32(TPM2_RH_NULL), /* bind */ + }; + + size_t offset = 18; + + if (!auth_session || auth_session->valid) + return TPM_LIB_ERROR; + + if (pack_byte_string(command_v2, sizeof(command_v2), "wswbww", + offset, TPM2_DIGEST_LEN, + offset + 2, nonce, TPM2_DIGEST_LEN, + offset + TPM2_DIGEST_LEN + 2, 0, + offset + TPM2_DIGEST_LEN + 4, session_type, + offset + TPM2_DIGEST_LEN + 5, TPM2_ALG_NULL, + offset + TPM2_DIGEST_LEN + 7, TPM2_ALG_SHA256)) + return TPM_LIB_ERROR; + + rc = tpm_sendrecv_command(dev, command_v2, response, &response_len); + if (rc) + return rc; + + offset = 10; + + if (unpack_byte_string(response, response_len, "dw", + offset, &auth_session->handle, + offset + 4, &tpm_nonce_sz)) + return TPM_LIB_ERROR; + + if (unpack_byte_string(response, response_len, "s", + offset + 6, auth_session->newernonce, TPM2_DIGEST_LEN)) + return TPM_LIB_ERROR; + + memcpy(auth_session->oldernonce, nonce, TPM2_DIGEST_LEN); + auth_session->valid = 1; + return rc; +} + +static u32 tpm2_policypcr(struct udevice *dev, const u8 *pcr_digest, u32 idx, + unsigned int idx_min_sz, u32 policy) +{ + u8 idx_array_sz = max(idx_min_sz, DIV_ROUND_UP(idx, 8)); + u8 command_v2[COMMAND_BUFFER_SIZE] = { + tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */ + tpm_u32(0x1A + TPM2_DIGEST_LEN),/* Length */ + tpm_u32(TPM2_CC_POLICY_PCR), /* Command code */ + + /* TPMI_SH_POLICY */ + tpm_u32(policy), + + /* TPM2B_DIGEST */ + tpm_u16(TPM2_DIGEST_LEN), + }; + + size_t response_len = COMMAND_BUFFER_SIZE; + u8 response[COMMAND_BUFFER_SIZE]; + unsigned int pcr_sel_idx = idx / 8; + u8 pcr_sel_bit = BIT(idx % 8); + + size_t offset = 16; + + if (pack_byte_string(command_v2, COMMAND_BUFFER_SIZE, "sdwbb", + offset, pcr_digest, TPM2_DIGEST_LEN, + offset + TPM2_DIGEST_LEN, 1, + offset + TPM2_DIGEST_LEN + 4, TPM2_ALG_SHA256, + offset + TPM2_DIGEST_LEN + 4 + 2, idx_array_sz, + offset + TPM2_DIGEST_LEN + 4 + 2 + 1 + pcr_sel_idx, pcr_sel_bit)) + return TPM_LIB_ERROR; + + return tpm_sendrecv_command(dev, command_v2, response, &response_len); +} + +static u32 tpm2_readpublic(struct udevice *dev, u32 handle, struct tpm2_object *object) +{ + size_t response_len = COMMAND_BUFFER_SIZE; + u32 ret; + u16 public_sz; + u16 name_sz; + u8 response[COMMAND_BUFFER_SIZE]; + + u8 command_v2[COMMAND_BUFFER_SIZE] = { + tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */ + tpm_u32(0x0E),/* Length */ + tpm_u32(TPM2_CC_READ_PUBLIC), /* Command code */ + /* TPMI_SH_POLICY */ + tpm_u32(handle) + }; + + ret = tpm_sendrecv_command(dev, command_v2, response, &response_len); + if (ret) + return ret; + + size_t offset = 10; + + /* skip over TPM2B_PUBLIC */ + if (unpack_byte_string(response, response_len, "w", + offset, &public_sz)) + return TPM_LIB_ERROR; + + if (unpack_byte_string(response, response_len, "ww", + offset + 2 + public_sz, &name_sz, + offset + 2 + public_sz + 2, &object->hashalg)) + return TPM_LIB_ERROR; + + if (unpack_byte_string(response, response_len, "s", + offset + 2 + public_sz + 2 + 2, object->name, TPM2_DIGEST_LEN)) + return TPM_LIB_ERROR; + + object->handle = handle; + return 0; +} + +static u32 create_request_auth(const void *request, + size_t request_len0, + struct tpm2_object *object, + struct session_data *auth_session, + void *request_auth, + const void *auth) +{ + size_t offset; + u8 names[TPM2_DIGEST_LEN + 2]; + + u8 hmac_data[TPM2_DIGEST_LEN * 3 + 1]; + sha256_context ctx; + + const size_t command_code_offset = 6; + const size_t auth_auth_offset = 45; + const size_t request_header_length = 10; + + if (!auth_session || !auth_session->valid) + return TPM_LIB_ERROR; + + offset = 0; + if (pack_byte_string(names, TPM2_DIGEST_LEN + 2, "ws", + offset, object->hashalg, + offset + 2, object->name, TPM2_DIGEST_LEN)) + return TPM_LIB_ERROR; + + sha256_starts(&ctx); + sha256_update(&ctx, request + command_code_offset, 4); + sha256_update(&ctx, names, TPM2_DIGEST_LEN + 2); + if (request_len0 > request_header_length + 4) + sha256_update(&ctx, request + request_header_length + 4, + request_len0 - request_header_length - 4); + sha256_finish(&ctx, hmac_data); + + /* Populate the authorization session */ + if (pack_byte_string(request_auth, TPM2_REQUEST_AUTH_LENGTH, "ddwsbw", + offset, 0x49, + /* authHandle */ + offset + 4, auth_session->handle, + /* nonceCallerSize */ + offset + 8, TPM2_DIGEST_LEN, + /* nonceCaller */ + offset + 8 + 2, auth_session->newernonce, TPM2_DIGEST_LEN, + /* sessionAttributes (continueSession=1) */ + offset + 8 + 2 + TPM2_DIGEST_LEN, 1, + /* hmacSize */ + offset + 8 + 2 + TPM2_DIGEST_LEN + 1, TPM2_DIGEST_LEN)) + return TPM_LIB_ERROR; + + offset = TPM2_DIGEST_LEN; + + if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb", + offset, auth_session->newernonce, TPM2_DIGEST_LEN, + offset + TPM2_DIGEST_LEN, auth_session->oldernonce, TPM2_DIGEST_LEN, + offset + (2 * TPM2_DIGEST_LEN), 1)) /* continue */ + return TPM_LIB_ERROR; + + sha256_hmac(auth, + TPM2_DIGEST_LEN, + hmac_data, + TPM2_DIGEST_LEN * 3 + 1, + request_auth + auth_auth_offset); + + return 0; +} + +static u32 verify_response_auth(u32 command_code, const void *response, + size_t response_len0, size_t handles_len, + struct session_data *auth_session, + void *response_auth, const void *auth) +{ + u8 cc_data[4]; + u8 hmac[TPM2_DIGEST_LEN]; + u8 hmac_data[TPM2_DIGEST_LEN * 3 + 1]; + u16 tpmnonce_sz; + u16 hmac_sz; + u8 auth_continue; + + sha256_context ctx; + const size_t return_code_offset = 6; + const size_t response_header_length = 10; + + if (!auth_session || !auth_session->valid) + return TPM_LIB_ERROR; + + size_t offset = 0; + + if (pack_byte_string(cc_data, sizeof(cc_data), "d", + offset, command_code)) + return TPM_LIB_ERROR; + + sha256_starts(&ctx); + sha256_update(&ctx, response + return_code_offset, 4); + sha256_update(&ctx, cc_data, 4); + if (response_len0 > response_header_length + handles_len + 4) + sha256_update(&ctx, + response + response_header_length + handles_len + 4, + response_len0 - response_header_length + - handles_len - 4); + sha256_finish(&ctx, hmac_data); + + /* Nonce rotation */ + memcpy(auth_session->oldernonce, auth_session->newernonce, TPM2_DIGEST_LEN); + + if (unpack_byte_string(response_auth, TPM2_RESPONSE_AUTH_LENGTH, "w", + offset, &tpmnonce_sz)) + return TPM_LIB_ERROR; + + if (unpack_byte_string(response_auth, TPM2_RESPONSE_AUTH_LENGTH, "sbw", + offset + 2, auth_session->newernonce, tpmnonce_sz, + offset + 2 + tpmnonce_sz, &auth_continue, + offset + 2 + tpmnonce_sz + 1, &hmac_sz)) + return TPM_LIB_ERROR; + + offset = TPM2_DIGEST_LEN; + + if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb", + offset, auth_session->newernonce, TPM2_DIGEST_LEN, + offset + TPM2_DIGEST_LEN, auth_session->oldernonce, TPM2_DIGEST_LEN, + offset + (2 * TPM2_DIGEST_LEN), auth_continue)) + return TPM_LIB_ERROR; + + sha256_hmac(auth, TPM2_DIGEST_LEN, hmac_data, TPM2_DIGEST_LEN * 3 + 1, hmac); + + /* Check for / fix timing leaks here */ + return memcmp(response_auth + 2 + tpmnonce_sz + 1 + 2, + hmac, TPM2_DIGEST_LEN) == 0 ? 0 : TPM_LIB_ERROR; +} + +static u32 tpm2_unseal(struct udevice *dev, u8 *nonce, + struct session_data *auth_session, + struct tpm2_object *object, + void *data, u16 *data_sz) +{ + u16 parameter_sz; + size_t request_len0, response_len0, response_len = COMMAND_BUFFER_SIZE; + size_t offset; + u32 ret; + u8 response[COMMAND_BUFFER_SIZE]; + u8 hmac_key[TPM2_DIGEST_LEN]; + + memset(hmac_key, 0, TPM2_DIGEST_LEN); + + u8 command_v2[COMMAND_BUFFER_SIZE] = { + tpm_u16(TPM2_ST_SESSIONS), /* TAG */ + tpm_u32(0x5B), /* Length */ + tpm_u32(TPM2_CC_UNSEAL), /* Command code */ + tpm_u32(object->handle), + }; + + /* rotate the nonces */ + memcpy(auth_session->oldernonce, auth_session->newernonce, TPM2_DIGEST_LEN); + memcpy(auth_session->newernonce, nonce, TPM2_DIGEST_LEN); + + request_len0 = 0x0E; + + if (create_request_auth(command_v2, + request_len0, + object, + auth_session, + &command_v2[request_len0], hmac_key)) + return TPM_LIB_ERROR; + + ret = tpm_sendrecv_command(dev, command_v2, response, &response_len); + if (ret) + return ret; + + offset = 10; + if (unpack_byte_string(response, response_len, "d", offset, ¶meter_sz)) + return TPM_LIB_ERROR; + + response_len0 = response_len - TPM2_RESPONSE_AUTH_LENGTH; + if (verify_response_auth(TPM2_CC_UNSEAL, + response, + response_len0, + 0, + auth_session, + &response[response_len0], hmac_key)) + return TPM_LIB_ERROR; + + if (unpack_byte_string(response, response_len, "w", offset + 4, data_sz)) + return TPM_LIB_ERROR; + + if (unpack_byte_string(response, response_len, "s", offset + 6, data, *data_sz)) + return TPM_LIB_ERROR; + + return ret; +} + +static u32 tpm2_flushcontext(struct udevice *dev, struct session_data *auth_session) +{ + u32 rc; + size_t response_len = COMMAND_BUFFER_SIZE; + u8 response[COMMAND_BUFFER_SIZE]; + + u8 command_v2[COMMAND_BUFFER_SIZE] = { + tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */ + tpm_u32(0x0E), /* Length */ + tpm_u32(TPM2_CC_FLUSH_CONTEXT), /* Command code */ + /* TPMI_SH_POLICY */ + tpm_u32(auth_session->handle) + }; + + if (!auth_session || !auth_session->valid) + return TPM_LIB_ERROR; + + rc = tpm_sendrecv_command(dev, command_v2, response, &response_len); + if (rc) + return rc; + + auth_session->valid = 0; + + return 0; +} + +u32 tpm2_do_unseal(struct udevice *dev, u32 handle, u32 pcr_index, unsigned int idx_min_sz, + u8 *unsealed_data, u16 *unsealed_data_sz) +{ + sha256_context ctx; + u32 rc; + u8 nonce[TPM2_DIGEST_LEN]; + u8 pcr_data[TPM2_DIGEST_LEN]; + u8 pcr_data_digest[TPM2_DIGEST_LEN]; + unsigned int updates; + struct tpm2_object object; + struct session_data auth_session = {0, }; + + memset(nonce, 0, TPM2_DIGEST_LEN); + + rc = tpm2_start_authsession(dev, TPM_SE_POLICY, nonce, &auth_session); + if (rc) + return rc; + + rc = tpm2_pcr_read(dev, pcr_index, idx_min_sz, pcr_data, &updates); + if (rc) + return rc; + + sha256_starts(&ctx); + sha256_update(&ctx, pcr_data, TPM2_DIGEST_LEN); + sha256_finish(&ctx, pcr_data_digest); + + rc = tpm2_policypcr(dev, pcr_data_digest, pcr_index, idx_min_sz, auth_session.handle); + if (rc) + return rc; + + rc = tpm2_readpublic(dev, handle, &object); + if (rc) + return rc;