File 0003-tpm2-Implement-more-TPM2-commands.patch of Package grub2
From a49c4dcbcb04078434f461ed3356c04042be461a Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Wed, 8 Feb 2023 10:30:55 +0800
Subject: [PATCH 3/4] tpm2: Implement more TPM2 commands
This commit implements a few more TPM2 commands as the preparation for
the authorized policy support.
* TPM2_LoadExternal
This command is added to load the external public key to verify the
signed policy digest
* TPM2_HashSequenceStart, TPM2_SequenceUpdate, TPM2_SequenceComplete,
and TPM2_Hash
With those commands, we can use the TPM as a coprocessor to calculate
the hash of a given binary blob.
* TPM2_VerifySignature
This command verifies the given signature with the given public key
and returns the validation ticket to authorize the policy.
* TPM2_PolicyAuthorize
This command approves the given policy digest so that we can unseal
the key with the newly authorized policy.
Signed-off-by: Gary Lin <glin@suse.com>
---
grub-core/tpm2/tpm2.c | 424 +++++++++++++++++++++++++
include/grub/tpm2/internal/functions.h | 57 ++++
2 files changed, 481 insertions(+)
diff --git a/grub-core/tpm2/tpm2.c b/grub-core/tpm2/tpm2.c
index d67699a24..159353b08 100644
--- a/grub-core/tpm2/tpm2.c
+++ b/grub-core/tpm2/tpm2.c
@@ -427,6 +427,73 @@ TPM2_Load (const TPMI_DH_OBJECT parent_handle,
return TPM_RC_SUCCESS;
}
+TPM_RC
+TPM2_LoadExternal (const TPMS_AUTH_COMMAND *authCommand,
+ const TPM2B_SENSITIVE *inPrivate,
+ const TPM2B_PUBLIC *inPublic,
+ const TPMI_RH_HIERARCHY hierarchy,
+ TPM_HANDLE *objectHandle,
+ TPM2B_NAME *name,
+ TPMS_AUTH_RESPONSE *authResponse)
+{
+ TPM_RC rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPM_HANDLE objectHandleTmp;
+ TPM2B_NAME nameTmp;
+ TPMS_AUTH_RESPONSE authResponseTmp;
+ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPM_RC responseCode;
+ grub_uint32_t param_size;
+
+ if (!inPublic)
+ return TPM_RC_VALUE;
+
+ if (!objectHandle)
+ objectHandle = &objectHandleTmp;
+ if (!name)
+ name = &nameTmp;
+ if (!authResponse)
+ authResponse = &authResponseTmp;
+
+ grub_memset (objectHandle, 0, sizeof (*objectHandle));
+ grub_memset (name, 0, sizeof (*name));
+ grub_memset (authResponse, 0, sizeof (*authResponse));
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ if (authCommand)
+ grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ if (inPrivate)
+ grub_tpm2_mu_TPM2B_SENSITIVE_Marshal (&in, inPrivate);
+ else
+ grub_tpm2_buffer_pack_u16 (&in, 0);
+ grub_tpm2_mu_TPM2B_PUBLIC_Marshal (&in, inPublic);
+ grub_tpm2_buffer_pack_u32 (&in, hierarchy);
+ if (in.error)
+ return TPM_RC_FAILURE;
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
+ rc = grub_tpm2_submit_command (tag, TPM_CC_LoadExternal, &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal*/
+ grub_tpm2_buffer_unpack_u32 (&out, objectHandle);
+ if (tag == TPM_ST_SESSIONS)
+ grub_tpm2_buffer_unpack_u32 (&out, ¶m_size);
+ grub_tpm2_mu_TPM2B_Unmarshal (&out, (TPM2B*)name);
+ if (tag == TPM_ST_SESSIONS)
+ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse);
+ if (out.error)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
TPM_RC
TPM2_Unseal (const TPMI_DH_OBJECT itemHandle,
const TPMS_AUTH_COMMAND *authCommand,
@@ -759,3 +826,360 @@ TPM2_EvictControl (const TPMI_RH_PROVISION auth,
return TPM_RC_SUCCESS;
}
+
+TPM_RC
+TPM2_HashSequenceStart (const TPMS_AUTH_COMMAND *authCommand,
+ const TPM2B_AUTH *auth,
+ const TPMI_ALG_HASH hashAlg,
+ TPMI_DH_OBJECT *sequenceHandle,
+ TPMS_AUTH_RESPONSE *authResponse)
+{
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPMI_DH_OBJECT sequenceHandleTmp;
+ TPMS_AUTH_RESPONSE authResponseTmp;
+ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPM_RC responseCode;
+ TPM_RC rc;
+ grub_uint32_t parameterSize;
+
+ if (!auth)
+ return TPM_RC_VALUE;
+
+ if (!sequenceHandle)
+ sequenceHandle = &sequenceHandleTmp;
+ if (!authResponse)
+ authResponse = &authResponseTmp;
+
+ grub_memset (sequenceHandle, 0, sizeof (*sequenceHandle));
+ grub_memset (authResponse, 0, sizeof (*authResponse));
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ if (authCommand)
+ grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ grub_tpm2_mu_TPM2B_Marshal (&in, auth->size, auth->buffer);
+ grub_tpm2_buffer_pack_u16 (&in, hashAlg);
+ if (in.error)
+ return TPM_RC_FAILURE;
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
+ rc = grub_tpm2_submit_command (tag, TPM_CC_HashSequenceStart, &responseCode, &in,
+ &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal */
+ grub_tpm2_buffer_unpack_u32 (&out, sequenceHandle);
+ if (tag == TPM_ST_SESSIONS)
+ {
+ grub_tpm2_buffer_unpack_u32 (&out, ¶meterSize);
+ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal(&out, authResponse);
+ }
+ if (out.error)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+TPM_RC
+TPM2_SequenceUpdate (const TPMI_DH_OBJECT sequenceHandle,
+ const TPMS_AUTH_COMMAND *authCommand,
+ const TPM2B_MAX_BUFFER *buffer,
+ TPMS_AUTH_RESPONSE *authResponse)
+{
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPMS_AUTH_RESPONSE authResponseTmp;
+ TPM_RC responseCode;
+ TPM_RC rc;
+ grub_uint32_t parameterSize;
+
+ if (!authCommand)
+ return TPM_RC_VALUE;
+
+ if (!authResponse)
+ authResponse = &authResponseTmp;
+
+ grub_memset (authResponse, 0, sizeof (*authResponse));
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ grub_tpm2_buffer_pack_u32 (&in, sequenceHandle);
+ grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ if (buffer)
+ grub_tpm2_mu_TPM2B_Marshal (&in, buffer->size, buffer->buffer);
+ else
+ grub_tpm2_buffer_pack_u16 (&in, 0);
+ if (in.error)
+ return TPM_RC_FAILURE;
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
+ rc = grub_tpm2_submit_command (TPM_ST_SESSIONS, TPM_CC_SequenceUpdate,
+ &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal */
+ grub_tpm2_buffer_unpack_u32 (&out, ¶meterSize);
+ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal(&out, authResponse);
+ if (out.error)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+TPM_RC
+TPM2_SequenceComplete (const TPMI_DH_OBJECT sequenceHandle,
+ const TPMS_AUTH_COMMAND *authCommand,
+ const TPM2B_MAX_BUFFER *buffer,
+ const TPMI_RH_HIERARCHY hierarchy,
+ TPM2B_DIGEST *result,
+ TPMT_TK_HASHCHECK *validation,
+ TPMS_AUTH_RESPONSE *authResponse)
+{
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPM2B_DIGEST resultTmp;
+ TPMT_TK_HASHCHECK validationTmp;
+ TPMS_AUTH_RESPONSE authResponseTmp;
+ TPM_RC responseCode;
+ TPM_RC rc;
+ grub_uint32_t parameterSize;
+
+ if (!authCommand)
+ return TPM_RC_VALUE;
+
+ if (!result)
+ result = &resultTmp;
+ if (!validation)
+ validation = &validationTmp;
+ if (!authResponse)
+ authResponse = &authResponseTmp;
+
+ grub_memset (result, 0, sizeof (*result));
+ grub_memset (validation, 0, sizeof (*validation));
+ grub_memset (authResponse, 0, sizeof (*authResponse));
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ grub_tpm2_buffer_pack_u32 (&in, sequenceHandle);
+ grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ if (buffer)
+ grub_tpm2_mu_TPM2B_Marshal (&in, buffer->size, buffer->buffer);
+ else
+ grub_tpm2_buffer_pack_u16 (&in, 0);
+ grub_tpm2_buffer_pack_u32 (&in, hierarchy);
+
+ if (in.error)
+ return TPM_RC_FAILURE;
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
+ rc = grub_tpm2_submit_command (TPM_ST_SESSIONS, TPM_CC_SequenceComplete,
+ &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal */
+ grub_tpm2_buffer_unpack_u32 (&out, ¶meterSize);
+ grub_tpm2_mu_TPM2B_DIGEST_Unmarshal (&out, result);
+ grub_tpm2_mu_TPMT_TK_HASHCHECK_Unmarshal (&out, validation);
+ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal(&out, authResponse);
+ if (out.error)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+TPM_RC
+TPM2_Hash (const TPMS_AUTH_COMMAND *authCommand,
+ const TPM2B_MAX_BUFFER *data,
+ const TPMI_ALG_HASH hashAlg,
+ const TPMI_RH_HIERARCHY hierarchy,
+ TPM2B_DIGEST *outHash,
+ TPMT_TK_HASHCHECK *validation,
+ TPMS_AUTH_RESPONSE *authResponse)
+{
+ TPM_RC rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPMS_AUTH_RESPONSE authResponseTmp;
+ TPM2B_DIGEST outHashTmp;
+ TPMT_TK_HASHCHECK validationTmp;
+ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPM_RC responseCode;
+ grub_uint32_t param_size;
+
+ if (hashAlg == TPM_ALG_NULL)
+ return TPM_RC_VALUE;
+
+ if (!outHash)
+ outHash = &outHashTmp;
+ if (!validation)
+ validation = &validationTmp;
+ if (!authResponse)
+ authResponse = &authResponseTmp;
+
+ grub_memset (outHash, 0, sizeof (*outHash));
+ grub_memset (validation, 0, sizeof (*validation));
+ grub_memset (authResponse, 0, sizeof (*authResponse));
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ if (authCommand)
+ grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ if (data)
+ grub_tpm2_mu_TPM2B_Marshal (&in, data->size, data->buffer);
+ else
+ grub_tpm2_buffer_pack_u16 (&in, 0);
+ grub_tpm2_buffer_pack_u16 (&in, hashAlg);
+ grub_tpm2_buffer_pack_u32 (&in, hierarchy);
+ if (in.error)
+ return TPM_RC_FAILURE;
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
+ rc = grub_tpm2_submit_command (tag, TPM_CC_Hash, &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal*/
+ if (tag == TPM_ST_SESSIONS)
+ grub_tpm2_buffer_unpack_u32 (&out, ¶m_size);
+ grub_tpm2_mu_TPM2B_DIGEST_Unmarshal (&out, outHash);
+ grub_tpm2_mu_TPMT_TK_HASHCHECK_Unmarshal (&out, validation);
+ if (tag == TPM_ST_SESSIONS)
+ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse);
+ if (out.error)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+TPM_RC
+TPM2_VerifySignature (const TPMI_DH_OBJECT keyHandle,
+ const TPMS_AUTH_COMMAND *authCommand,
+ const TPM2B_DIGEST *digest,
+ const TPMT_SIGNATURE *signature,
+ TPMT_TK_VERIFIED *validation,
+ TPMS_AUTH_RESPONSE *authResponse)
+{
+ TPM_RC rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPMS_AUTH_RESPONSE authResponseTmp;
+ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPMT_TK_VERIFIED validationTmp;
+ TPM_RC responseCode;
+ grub_uint32_t param_size;
+
+ if (!digest || !signature)
+ return TPM_RC_VALUE;
+
+ if (!validation)
+ validation = &validationTmp;
+ if (!authResponse)
+ authResponse = &authResponseTmp;
+
+ grub_memset (validation, 0, sizeof (*validation));
+ grub_memset (authResponse, 0, sizeof (*authResponse));
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ if (authCommand)
+ grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ grub_tpm2_buffer_pack_u32 (&in, keyHandle);
+ grub_tpm2_mu_TPM2B_Marshal (&in, digest->size, digest->buffer);
+ grub_tpm2_mu_TPMT_SIGNATURE_Marshal (&in, signature);
+ if (in.error)
+ return TPM_RC_FAILURE;
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
+ rc = grub_tpm2_submit_command (tag, TPM_CC_VerifySignature, &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal*/
+ if (tag == TPM_ST_SESSIONS)
+ grub_tpm2_buffer_unpack_u32 (&out, ¶m_size);
+ grub_tpm2_mu_TPMT_TK_VERIFIED_Unmarshal (&out, validation);
+ if (tag == TPM_ST_SESSIONS)
+ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse);
+ if (out.error)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+TPM_RC
+TPM2_PolicyAuthorize (const TPMI_SH_POLICY policySession,
+ const TPMS_AUTH_COMMAND *authCommand,
+ const TPM2B_DIGEST *approvedPolicy,
+ const TPM2B_NONCE *policyRef,
+ const TPM2B_NAME *keySign,
+ const TPMT_TK_VERIFIED *checkTicket,
+ TPMS_AUTH_RESPONSE *authResponse)
+{
+ TPM_RC rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPMS_AUTH_RESPONSE authResponseTmp;
+ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPM_RC responseCode;
+ grub_uint32_t param_size;
+
+ if (!approvedPolicy || !keySign || !checkTicket)
+ return TPM_RC_VALUE;
+
+ if (!authResponse)
+ authResponse = &authResponseTmp;
+
+ grub_memset (authResponse, 0, sizeof (*authResponse));
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ grub_tpm2_buffer_pack_u32 (&in, policySession);
+ if (authCommand)
+ grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ grub_tpm2_mu_TPM2B_Marshal (&in, approvedPolicy->size, approvedPolicy->buffer);
+ if (policyRef)
+ grub_tpm2_mu_TPM2B_Marshal (&in, policyRef->size, policyRef->buffer);
+ else
+ grub_tpm2_buffer_pack_u16 (&in, 0);
+ grub_tpm2_mu_TPM2B_Marshal (&in, keySign->size, keySign->name);
+ grub_tpm2_mu_TPMT_TK_VERIFIED_Marshal (&in, checkTicket);
+ if (in.error)
+ return TPM_RC_FAILURE;
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
+ rc = grub_tpm2_submit_command (tag, TPM_CC_PolicyAuthorize, &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal*/
+ if (tag == TPM_ST_SESSIONS)
+ grub_tpm2_buffer_unpack_u32 (&out, ¶m_size);
+ if (tag == TPM_ST_SESSIONS)
+ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse);
+ if (out.error)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
diff --git a/include/grub/tpm2/internal/functions.h b/include/grub/tpm2/internal/functions.h
index 9380f26a2..67b78fab8 100644
--- a/include/grub/tpm2/internal/functions.h
+++ b/include/grub/tpm2/internal/functions.h
@@ -70,6 +70,15 @@ TPM2_Load (const TPMI_DH_OBJECT parent_handle,
TPM2B_NAME *name,
TPMS_AUTH_RESPONSE *authResponse);
+TPM_RC
+TPM2_LoadExternal (const TPMS_AUTH_COMMAND *authCommand,
+ const TPM2B_SENSITIVE *inPrivate,
+ const TPM2B_PUBLIC *inPublic,
+ const TPMI_RH_HIERARCHY hierarchy,
+ TPM_HANDLE *objectHandle,
+ TPM2B_NAME *name,
+ TPMS_AUTH_RESPONSE *authResponse);
+
TPM_RC
TPM2_Unseal (const TPMI_DH_OBJECT item_handle,
const TPMS_AUTH_COMMAND *authCommand,
@@ -114,4 +123,52 @@ TPM2_EvictControl (const TPMI_RH_PROVISION auth,
const TPMI_DH_PERSISTENT persistentHandle,
TPMS_AUTH_RESPONSE *authResponse);
+TPM_RC
+TPM2_HashSequenceStart (const TPMS_AUTH_COMMAND *authCommand,
+ const TPM2B_AUTH *auth,
+ const TPMI_ALG_HASH hashAlg,
+ TPMI_DH_OBJECT *sequenceHandle,
+ TPMS_AUTH_RESPONSE *authResponse);
+
+TPM_RC
+TPM2_SequenceUpdate (const TPMI_DH_OBJECT sequenceHandle,
+ const TPMS_AUTH_COMMAND *authCommand,
+ const TPM2B_MAX_BUFFER *buffer,
+ TPMS_AUTH_RESPONSE *authResponse);
+
+TPM_RC
+TPM2_SequenceComplete (const TPMI_DH_OBJECT sequenceHandle,
+ const TPMS_AUTH_COMMAND *authCommand,
+ const TPM2B_MAX_BUFFER *buffer,
+ const TPMI_RH_HIERARCHY hierarchy,
+ TPM2B_DIGEST *result,
+ TPMT_TK_HASHCHECK *validation,
+ TPMS_AUTH_RESPONSE *authResponse);
+
+TPM_RC
+TPM2_Hash (const TPMS_AUTH_COMMAND *authCommand,
+ const TPM2B_MAX_BUFFER *data,
+ const TPMI_ALG_HASH hashAlg,
+ const TPMI_RH_HIERARCHY hierarchy,
+ TPM2B_DIGEST *outHash,
+ TPMT_TK_HASHCHECK *validation,
+ TPMS_AUTH_RESPONSE *authResponse);
+
+TPM_RC
+TPM2_VerifySignature (const TPMI_DH_OBJECT keyHandle,
+ const TPMS_AUTH_COMMAND *authCommand,
+ const TPM2B_DIGEST *digest,
+ const TPMT_SIGNATURE *signature,
+ TPMT_TK_VERIFIED *validation,
+ TPMS_AUTH_RESPONSE *authResponse);
+
+TPM_RC
+TPM2_PolicyAuthorize (const TPMI_SH_POLICY policySession,
+ const TPMS_AUTH_COMMAND *authCommand,
+ const TPM2B_DIGEST *approvedPolicy,
+ const TPM2B_NONCE *policyRef,
+ const TPM2B_NAME *keySign,
+ const TPMT_TK_VERIFIED *checkTicket,
+ TPMS_AUTH_RESPONSE *authResponse);
+
#endif /* ! GRUB_TPM2_INTERNAL_FUNCTIONS_HEADER */
--
2.35.3